Scratch and Python 2017 Summer - Python Lecture 2
===
### Flow Control
+ [Flow chart](https://automatetheboringstuff.com/chapter2/#calibre_link-1903)
+ Boolean Values
+ `True`
+ `False`
+ `true` and `false` are no good
+ Comparison operators
+ `==`
+ `float` is not accurate.
+ `!=`
+ `<`
+ `<=`
+ `>`
+ `>=`
+ Compare values of different types
+ `string` versus `int`
+ `int` versus `float`
+ Boolean operators
+ `and`
+ `or`
+ `not`
+ Precedence: `not` > `and` > `or`
+ Truthy and falsey values
+ Truthy values
+ Non-zero integers
+ Non-zero `float`
+ Non-empty `string`
+ Falsey values
+ `0`
+ `0.0`
+ `''`
+ The are more truthy and falsey values. Not NOW.
+ Conditions: a Boolean expression
+ Block of code [Colored structure](https://github.com/mzshieh/snp2017/raw/master/lecture%202%20--%20structure.docx)
+ Selection
+ `if`
+ `if`-`else`
+ `if`-`elif`
+ `if`-`elif`-`else`
+ example
```python3=
x = int(input("請輸入成績(0~100) : "))
if x > 100 or x < 0:
print('不要騙喔! OAO')
elif x >= 90:
print('Nice!!')
elif x >= 60:
print('Pass')
else:
print('好課值得一修再修3修重修畢業後繼續修')
```
+ Iteration
+ `while` loop
+ `for` loop
+ `break`
+ `continue`
+ Sample code 1
```python3=
## Sample 1
while True:
x = input('助教帥不帥? (y/n)')
if x != 'y':
print('你確定?再給你一次機會')
else:
break
print('謝謝誇獎')
```
+ Sample code 2
```python3=
## Sample 2
print('數質數 1 ~ 20')
prime = [2, 3, 5, 7, 11, 13, 17, 19]
for num in range(1, 21):
if num not in prime:
continue
print(num)
```
+ Function definition
+ `def`
+ `return`
+ Sample code
```python3=
#========Function========#
def findmax(arr):
ans = arr[0]
for tmp in arr:
if ans < tmp:
ans = tmp
return ans
#========Function========#
array = [0, 2, 9, 3, 5, 6, 7]
print(findmax(array))
```
+ Exception handling
+ `try`-`except`
+ example
```python3=
x = input("做除法, 請輸入2個數字,用空白隔開\n").split()
try:
print(int(x[0]) / int(x[1]))
except:
print('除數不得為0')
```
### Debugger
https://openload.co/embed/r9y83gSF9K8
https://openload.co/embed/iO5qPL2928w
https://openload.co/embed/b3xYbhb_POU
http://tniesz.pl/tqxb0 =
http://tniesz.pl/3gemd =
http://tnij.tcz.pl/?u=188c0f
+ Breakpoints
+ Buttons
+ Debug file
+ Run current line
+ Step into function or method of current line
+ Run until current function or method returns
+ Continue execution until next breakpoint
+ Use the following code to try the debugger
```python3=
def calc_add(a, b):
sum = a + b
return sum
def calc_sum(a, b):
sum = 0
for i in range(a, b + 1):
sum = sum + i
return sum
x = 1
y = 100
z = 10
a = 1
b = 2
c = 3
print(calc_add(x, y))
print(calc_sum(x, y))
```
參考資料:[Spyder Debugger Tutorial](https://hackmd.io/65mcTrq4Tji-HXfWIliRXw?view)
### Task 3
+ Draw [Rokumonsen](https://www.google.com.tw/search?q=Rokumonsen)
+ Draw Ichimonsen (一文銭)
+ Draw Sanjurokumonsen (三十六文銭)
### `pyautogui`: open your eyes!
+ Sample code 1
```python3=
import pyautogui, time
def report():
pos = pyautogui.position()
color = pyautogui.screenshot().getpixel(pos)
print('Mouse position:',pos,'Color:',color)
while True:
report()
time.sleep(0.1)
```
+ `screenshot()`
+ Pixel
+ `screenshot().getpixel()`
+ `(R,G,B)`
+ `screenshot().im` is `iterable`
+ Pixels are balls, and `screenshot()` is a bag containing balls.
+ `screenshot().save('pic.png')` 存檔到 `pic.png`。
+ How to take a screen shot
+ Windows: print screen key
+ Hold alt, then press print screen
+ This gives you a picture of window on focus
+ Use Microsoft Paint to save the screenshot into png file
+ Sample code
```python3=
import pyautogui, time
pyautogui.FAILSAFE = True
loc = pyautogui.locateOnScreen('box.png') # 偵測螢幕上是否有與 box.png 相同的圖片,若有 loc 將會被指派相同於圖片的地方的位置,若沒有 loc 會被指派為 None
while loc == None: # 如果 loc 是 None (剛剛螢幕上沒找到相同的圖片) / 如果有找到,會直接跳過這個迴圈
time.sleep(0.1) # 停 0.1 秒
loc = pyautogui.locateOnScreen('box.png') # 再找一次
for loc_i in pyautogui.locateAllOnScreen('box.png'):
print(loc_i)
center = pyautogui.center(loc_i)
pyautogui.click(center)
```
+ `locateOnScreen(pic)`
+ 在螢幕上尋找與 `pic` 相同的圖片,若找到一個,則回傳位置(4-element `tuple` `(left,top,width,height)`)並停止尋找。
+ 若都沒有找到,則回傳 `None`。
+ `locateAllOnScreen(pic)`
+ 在螢幕上尋找 **全部** 與 `pic` 相同的圖片,吐出一個`generator`。
### Task: Check all boxes!
Practice [here](https://goo.gl/forms/dr5mkE7Z9dKiJ3gI3)
### Issues on `screenshot`
+ `screenshot` is slow
+ `locateOnScreen` is very slow
+ Hard to recognize objects
### Fast Screenshot
Save the following code as `fastscreenshot.py` at your desktop.
```python3=
import time
from PIL import Image
from mss import mss
# Fast screenshot
# mss 3.0 ver
# Usage just like pyautogui
# Parameter:
# region: optional, four-integer tuple (left, top, width, height)
def screenshot(region=None, **kwargs):
im = None
monitors = None
if region == None:
region = kwargs.get('region')
with mss() as sct:
# Region to capture
monitor = sct.monitors[1]
if region != None:
monitor['left'] = int(region[0])
monitor['top'] = int(region[1])
monitor['width'] = int(region[2])
monitor['height'] = int(region[3])
# Get pixels on image
sct_img = sct.grab(monitor)
im = Image.frombytes('RGBA', sct_img.size, bytes(sct_img.raw), 'raw', 'BGRA')
im = im.convert('RGB')
return im
# Evaluate screenshot time in seconds
def evaluate_screenshot_time(region=None):
t = time.time()
im = screenshot(region)
return time.time() - t
```
Then, save the following as `test.py` at your desktop.
```python3=
import time
import pyautogui
from pyautogui import screenshot
# from fastscreenshot import screenshot
def report_time():
t = time.time()
left, top, width, height = 5, 66, 77, 8
screenshot(region=(left,top,width,height))
print(time.time()-t)
for i in range(100):
report_time()
```
If `fastscreenshot.py` does not work, use the following.
```python3=
import time
from PIL import Image
from mss import mss
# Fast screenshot
# Usage just like pyautogui
# Parameter:
# region: optional, four-integer tuple (left, top, width, height)
def screenshot(region=None,**kwargs):
im = None
monitors = None
if region == None:
region = kwargs.get('region')
with mss() as sct:
# Retrieve monitors informations:
monitors = sct.enum_display_monitors()
# Region to capture
monitor = dict(monitors[1])
if region != None:
monitor['left'] = int(region[0])
monitor['top'] = int(region[1])
monitor['width'] = (int(region[2]) // 80 + int(region[2] % 80 != 0)) * 80
monitor['height'] = int(region[3])
# Get pixels on image
sct.get_pixels(monitor)
im = Image.frombytes('RGB', (sct.width, sct.height), sct.image)
if region != None:
if monitor.get('width') != region[2]:
im = im.crop((0, 0, region[2], region[3]))
return im
# Evaluate screenshot time in seconds
def evaluate_screenshot_time(region=None):
t = time.time()
im = screenshot(region)
return time.time() - t
```
### Type
+ All values have their own types.
+ Use `type(v)` to check the type of value `v`.
+ All defined name (identifier) have their values.
+ Use `type(name)` to check the type of `name`.
### Function
+ `def your_function()`
+ `return`
+ The function is terminated either by `return` or by the end of the block.
+ `None`: if there is no `return` or just `return` nothing
+ `def your_function_with_parameter(parameter)`
+ Argument
```python3=
def square(x):
return x**2
def square_root(x):
return x**0.5
```
+ `def your_function_with_parameters(parameter1, parameter2)`
+ More arguments
```python3=
def distance(x1,y1,x2,y2):
delta_x = x1-x2
delta_y = y1-y2
dx2 = square(delta_x)
dy2 = square(delta_y)
return square_root(dx2+dy2)
```
+ `def your_function_with_parameters(*args)`
+ Variable length list of arguments can be passed by `args` which is a `tuple`.
+ More flexible
```python3=
def square_var_len(*x):
print(type(x))
print(len(x))
ret = tuple()
for v in x:
ret = ret + (v**2,)
return ret
```
+ Access data via index `i`: `args[i]`
+ `def your_function_with_parameters(**kwargs)`
+ Keyword arguments
+ `print(some_str, end='')`
+ `print(some_str_1, some_str_2, sep=',')`
+ Access data via key string
+ `kwargs['end']`
+ `kwargs['sep']`
+ ```python3=
def square_kw(x,**kwargs):
if kwargs.get('test'):
return 'test'
return x**2
```
+ Please do not overwrite the arguments in your function now. We will discuss what will happen if you do so later.
+ Scope
+ Sample code
```python3=
a_global_var = 'A global variable'
def f(arg,*args,**kwargs):
print(arg)
print('args:',args)
print('kwargs:',kwargs)
local = 'A local variable'
print('local:',local)
print('a_global_var:',a_global_var)
f('hi','hi','ni',hihi='hihihi')
```
+ Variables are defined by assignment statements
+ Global
+ Defined in global scope
+ `global`
+ `global some_var`: `some_var` in this function is the global `some_var`
+ You must do this if you're going to write global variables
+ Local
+ Defined in local scope
+ Principles
+ Local variables cannot be used globally.
+ A local scope cannot access local variables in other scopes.
+ A local variable and a global variable may have the same name, but only local variable can be accessed.
+ You may still read the global variable correctly if no local variable is using the same name.
### Generator
+ Defined by a `def` block containing `yield`
+ Override `return`
+ Sample code
```python3=
def squares(n):
for i in range(n+1):
yield i**2
print('squares is',type(squares))
print('squares() is',type(squares(5)))
for i in squares(5):
print(i)
```
+ Sample code 2
```python3=
def primes(n):
if n < 2:
return
n_is_prime = True
for i in primes(n-1):
yield i
if n % i == 0:
n_is_prime = False
if n_is_prime:
yield n
for i in primes(100):
print(i)
```
+ Sample code 3
```python3=
def f():
yield 1
yield 2
yield 3
return 5
for i in f():
print(i)
```
### Task 4
+ More readable: use `def` block
+ Less dependent on maximizing window
+ Use screen shot and `locateOnScreen`
## 作業
### HW2
- 作業內容: [Task 3](#task-3)
- 請同學將做好的作品放到 [IDE one](https://ideone.com/) 上 **(記得語言選 python3)**
- 請一次只教一個連結,若有多個,請分開繳交
- 因為助教的螢幕比例不一定會跟你的一樣,所以位置 *建議* 抓**相對位置**
- 相對位置範例:
```python=
import pyautogui
screenX, screenY = pyautogui.size()
pyautogui.moveTo(screenX/2, screenY/2) # 將游標移到螢幕中心
pyautogui.dragTo(screenX * 2/3, screenY * 1/5)
...
```
- <font style="color:red;">Deadline: 7/24 12:00 pm</font>
- 作業繳交
- [Windows + 小畫家](https://goo.gl/forms/Qqh7qKIGo8lxHjb62)
- [Others](https://goo.gl/forms/sA0aZxDJZq4yOqff1)
#### [作業確認程式碼](https://ideone.com/QEr7tn)
### HW3
- 作業內容: [表單全部勾選](#task-check-all-boxes)
- <font style="color: red;">Deadline: 7/26 中午 12:30</font>
需求:
- 請在程式執行前,助教會先把表單滑到最上面 (so, 寫的時候也要是這樣)
- ~~請填入姓名~~ (因為中文輸入法太麻煩了,所以不需要填寫名字)
- 程式結束後,需按下『提交』,同時也需是偵測圖片的方式做的
- 助教將提供以下照片,您程式裡的命名必須與這兩個命名相同
- 箱子圖片:box.png

- 送出圖片:submit.png

- 請確認過 [範例表單](https://goo.gl/forms/qctR7aDpw6C5pi492) 可提交
- 如有任何問題,可寄信至 sz110010@gmail.com
- 作品上傳 [IDE one](https://ideone.com/) 上,再繳交連結 **(記得語言選 python3)**
- 請一次只教一個連結,若有多個,請分開繳交
- 同學亦可嘗試使用 fastscreenshot,助教環境有提供
- hw3 [繳交區](https://goo.gl/forms/7ipJn2JowWZjayjl1)
### [sample code](https://github.com/calee0219/snp2017_check_code/blob/master/hw3_sample.py)
### [checking code](https://github.com/calee0219/snp2017_check_code/blob/master/hw3_bot.py)
### HW4
- [T-Rex](http://www.trex-game.skipser.com/) 截圖
- <font style="color: red;">Deadline: 7/28 中午 12:30</font>
需求
- 最少要 300 分
- 需要用程式截圖 ( .save() )
- 截圖上傳到 [Imgur](http://imgur.com/),表單繳交 Imgur 連結 (不需要登入)
- hw4 [繳交區](https://goo.gl/forms/3TguatmaurS29Aen2)
#### problem
- 同學如果要用 `screenshot().im`,是只有 fastscreenshot.py 的 `screenshot()` 才有這個功能喔
- 儲存圖片的方法: `screenshot({自己想加的參數}).save('pic.png')`,這個 screenshot() 用 fastscreenshot 或是 pyautogui 的都可以喔
- 偵測某範圍內的顏色可以參考:
```python=
...
for px in screenshot({參數}).im:
if px == ({顏色}):
偵測到要做的事
...
```
以上 code 感謝同學提供