├── .DS_Store ├── .gitignore ├── 001_1_minute_math.md ├── 002_English_Chinese_Translation.md ├── 003_Add_text_watermark_on_pictures.md ├── 004_Check_your_English_speech.md ├── 005_Check_your_English_speech_baidu.md ├── 006_Arithmetic_Formatter.md ├── 007_OpenCV_Capture_Camera_Video.md ├── 008_OpenCV_MediaPipe_hand_detection.md ├── 009_OpenCV_MediaPipe_hands_fingers_count.md ├── 010_gobang.md ├── 011_snake_game.md ├── 012_Minesweeper.md ├── 013_Posegame.md ├── 014_Tetris.md ├── 015_2048.md ├── README.md ├── code ├── 1 │ └── 1.py ├── 2 │ └── 2.py ├── 3 │ ├── .DS_Store │ ├── 3.py │ ├── PMingLiU.ttf │ ├── Roboto-Italic.ttf │ ├── images │ │ └── 1.png │ ├── requirements.txt │ └── watermark │ │ └── 1.png ├── 4 │ ├── 4.py │ └── requirements.txt ├── 5 │ ├── 5.py │ └── requirements.txt ├── 6 │ ├── arithmetic_arranger.py │ └── test_module.py ├── 7 │ ├── opencv_capture_camera_video.py │ └── requirements.txt ├── 8 │ ├── hand.py │ ├── handUtils.py │ └── requirements.txt ├── 9 │ ├── hand.py │ ├── handUtils.py │ └── requirements.txt ├── 10 │ └── gobang.py ├── 11 │ └── snake.py ├── 12 │ └── minesweeper.py ├── 13 │ ├── game.py │ ├── images │ │ ├── b_1.png │ │ ├── b_10.png │ │ ├── b_11.png │ │ ├── b_12.png │ │ ├── b_13.png │ │ ├── b_14.png │ │ ├── b_15.png │ │ ├── b_16.png │ │ ├── b_17.png │ │ ├── b_18.png │ │ ├── b_19.png │ │ ├── b_2.png │ │ ├── b_20.png │ │ ├── b_21.png │ │ ├── b_22.png │ │ ├── b_23.png │ │ ├── b_24.png │ │ ├── b_25.png │ │ ├── b_3.png │ │ ├── b_4.png │ │ ├── b_5.png │ │ ├── b_6.png │ │ ├── b_7.png │ │ ├── b_8.png │ │ ├── b_9.png │ │ ├── covid.png │ │ ├── laser.png │ │ └── score.png │ ├── music │ │ └── bg.mp3 │ ├── pose_util.py │ ├── requirements.txt │ ├── sounds │ │ ├── boom.wav │ │ ├── coin.wav │ │ ├── cut.wav │ │ ├── explode.wav │ │ ├── jump.wav │ │ ├── lose.wav │ │ ├── pew.wav │ │ └── rip.wav │ ├── utils.py │ └── video.py └── .DS_Store ├── images ├── 011_snake.png ├── 012_minesweeper.png ├── 013_posegame.png ├── 2048.png ├── challenge1_1.png ├── challenge2_cn.png ├── challenge2_en.png ├── challenge4.png ├── challenge_10_1.png ├── challenge_10_2.png ├── challenge_3_1.png ├── challenge_3_2.png ├── challenge_3_3.png ├── challenge_3_4.png ├── challenge_3_5.png ├── challenge_4_cn.png ├── challenge_4_en.png ├── challenge_5_cn.png ├── challenge_5_en.png └── tetris.png └── test.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | 140 | .idea 141 | -------------------------------------------------------------------------------- /001_1_minute_math.md: -------------------------------------------------------------------------------- 1 | # 1 minute math 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll run for 1 minute. 7 | 3. For every time it'll show 2 random numbers and random arithmetic operations such as add, subtract, multiply and divide. If the operation is divide then the divisor can not be 0. 8 | 4. It'll judge if your answer is correct or not, then show next question. 9 | 5. When time is up it'll show how many questions you answered and show the correct rate for total questions. 10 | 11 | ## What will we practice in this project? 12 | 13 | - format print 14 | - while loop 15 | - if condition 16 | - list 17 | - exception handle 18 | - function 19 | - time package 20 | - random package 21 | 22 | ## A reference code 23 | 24 | ```python 25 | import time 26 | import random 27 | 28 | 29 | def get_divisor(n): 30 | ''' 31 | Get a random divisor of n. 32 | :param n: The number 33 | :return: a divisor of n 34 | ''' 35 | l = [] 36 | for i in range(1, n + 1): 37 | if n % i == 0: 38 | l.append(i) 39 | return random.choice(l) 40 | 41 | 42 | if __name__ =='__main__': 43 | ops = ['+', '-', '*', '/'] 44 | start_time = time.time() 45 | total = 0 46 | correct = 0 47 | questions = [] 48 | # while seconds is less than 60 49 | while time.time() - start_time <= 60: 50 | a = random.randint(1, 99) 51 | op = random.choice(ops) 52 | if op == '/': 53 | # if op is '/' then b is a divisor of a 54 | b = get_divisor(a) 55 | else: 56 | b = random.randint(1, 99) 57 | # Get the correct answer 58 | a_op_b = '{}{}{}'.format(a, op, b) 59 | c = int(eval(a_op_b)) 60 | 61 | # Let user input answer 62 | try: 63 | ans = int(input('{} = '.format(a_op_b))) 64 | except: 65 | ans = '' 66 | 67 | # To check if correct or not 68 | if time.time() - start_time <= 60: 69 | if c == ans: 70 | print('Correct! Time remain {} seconds.'.format(int(60 - (time.time() - start_time)))) 71 | correct = correct + 1 72 | else: 73 | print('Wrong answer! Time remain {} seconds.'.format(int(60 - (time.time() - start_time)))) 74 | total = total + 1 75 | questions.append('{}={}'.format(a_op_b, ans)) 76 | 77 | print('{} questions and your correct rate is {:.2f}%'.format(total, correct / total * 100)) 78 | for q in questions: 79 | print(q) 80 | 81 | ``` 82 | 83 | ## Run the demo 84 | 85 | Please save the Python as 1.py and run it in console: 86 | 87 | ``` 88 | python 1.py 89 | ``` 90 | 91 | ![Chanllenge 1](images/challenge1_1.png) 92 | 93 | ---- 94 | 95 | # 1分钟数学运算 96 | 97 | ## 项目需求 98 | 99 | - 直接在控制台使用命令行运行 100 | - 程序运行之后倒计时1分钟之后结束 101 | - 随机出100以内的2个整数加减乘除运算题目(除法确保能够除尽,但除数不能为0) 102 | - 每出一道题目,由玩家给出答案,然后程序判断对错,接着出下一题,并且显示剩余时间 103 | - 1分钟时间结束,显示总题数和正确率(正确率精确到小数点后2位),并将之前的题目和答案显示出来 104 | 105 | ## 项目练习 106 | 107 | - 格式化字符串输出 108 | - 循环 109 | - 条件判断 110 | - 列表 111 | - 异常处理 112 | - 自定义函数 113 | - 时间工具包 114 | - 随机工具包 115 | 116 | ## 项目参考代码 117 | 118 | ```python 119 | import time 120 | import random 121 | 122 | 123 | def get_divisor(n): 124 | ''' 125 | 随机获得一个数n的整数除数。 126 | :param n: 一个整数 127 | :return: 一个数n的整数除数 128 | ''' 129 | l = [] 130 | for i in range(1, n + 1): 131 | if n % i == 0: 132 | l.append(i) 133 | return random.choice(l) 134 | 135 | 136 | if __name__ =='__main__': 137 | ops = ['+', '-', '*', '/'] 138 | start_time = time.time() 139 | total = 0 140 | correct = 0 141 | questions = [] 142 | while time.time() - start_time <= 60: 143 | a = random.randint(1, 99) 144 | op = random.choice(ops) 145 | if op == '/': 146 | # 如果是除法,b为a的一个随机整数除数 147 | b = get_divisor(a) 148 | else: 149 | b = random.randint(1, 99) 150 | # 正确答案 151 | a_op_b = '{}{}{}'.format(a, op, b) 152 | c = int(eval(a_op_b)) 153 | 154 | # 让用户输入答案 155 | try: 156 | ans = int(input('{} = '.format(a_op_b))) 157 | except: 158 | ans = '' 159 | 160 | # 检查是否正确 161 | if time.time() - start_time <= 60: 162 | if c == ans: 163 | print('正确!剩余时间{}秒。'.format(int(60 - (time.time() - start_time)))) 164 | correct = correct + 1 165 | else: 166 | print('错误!剩余时间{}秒。'.format(int(60 - (time.time() - start_time)))) 167 | total = total + 1 168 | questions.append('{}={}'.format(a_op_b, ans)) 169 | 170 | print('{}道题目,正确率 {:.2f}%。'.format(total, correct / total * 100)) 171 | for q in questions: 172 | print(q) 173 | 174 | ``` 175 | 176 | ## 测试运行 177 | 178 | 将代码保存为1.py,然后在控制台运行: 179 | 180 | ``` 181 | python 1.py 182 | ``` 183 | 184 | ![挑战1](images/challenge1_1.png) -------------------------------------------------------------------------------- /002_English_Chinese_Translation.md: -------------------------------------------------------------------------------- 1 | # English Chinese Translation 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll ask you to input English or Chinese words or sentence. Then it'll print the related translation text. 7 | 3. If you input 'q' it'll stop to ask then quit the program. 8 | 9 | ## What will we practice in this project? 10 | 11 | - while loop 12 | - input text 13 | - if conditions 14 | - http post request 15 | - dictionary 16 | - requests package (need to install it by `pip install requests`) 17 | 18 | ## A reference code 19 | 20 | ```python 21 | import requests 22 | 23 | url = 'https://fanyi.baidu.com/sug' 24 | 25 | while True: 26 | text = input('Please input English or Chinese word:').strip() 27 | if text == 'q': 28 | break 29 | 30 | data = {'kw': text} 31 | 32 | resp = requests.post(url, data) 33 | 34 | found = False 35 | if resp.status_code == 200: 36 | data = resp.json() 37 | if data['errno'] == 0: 38 | ds = data['data'] 39 | for kv in ds: 40 | if kv['k'] == text: 41 | found = True 42 | print(kv['v']) 43 | if not found: 44 | print('Not found') 45 | else: 46 | print(data) 47 | else: 48 | print(resp.content) 49 | 50 | ``` 51 | 52 | ## Run the demo 53 | 54 | Please save the Python as 2.py and run it in console: 55 | 56 | ![image-20210505170938660](images/challenge2_en.png) 57 | 58 | 59 | # 中英文翻译 60 | 61 | ## 项目需求 62 | 63 | 1. 在命令行窗口运行 64 | 2. 当程序运行时,会要求我们输入中文或者英文单词或者句子,然后程序会自动翻译成对应的英语或者中文 65 | 3. 当输入q字母,程序不再询问并结束 66 | 67 | ## Python编程知识点 68 | 69 | - while循环 70 | - 用户输入字符串 71 | - 条件判断 72 | - 字典数据 73 | - http post请求 74 | - requests 模块 (需要使用`pip install requests`安装) 75 | 76 | ## 参考代码 77 | 78 | ```python 79 | import requests 80 | 81 | url = 'https://fanyi.baidu.com/sug' 82 | 83 | while True: 84 | text = input('请输入中文或者英语:').strip() 85 | if text == 'q': 86 | break 87 | 88 | data = {'kw': text} 89 | 90 | resp = requests.post(url, data) 91 | 92 | found = False 93 | if resp.status_code == 200: 94 | data = resp.json() 95 | if data['errno'] == 0: 96 | ds = data['data'] 97 | for kv in ds: 98 | if kv['k'] == text: 99 | found = True 100 | print(kv['v']) 101 | if not found: 102 | print('没有找到') 103 | else: 104 | print(data) 105 | else: 106 | print(resp.content) 107 | 108 | ``` 109 | 110 | ## 运行测试 111 | 将代码保存为2.py,然后在控制台运行: 112 | 113 | ``` 114 | python 2.py 115 | ``` 116 | 117 | ![image-20210505171540819](images/challenge2_cn.png) 118 | 119 | -------------------------------------------------------------------------------- /003_Add_text_watermark_on_pictures.md: -------------------------------------------------------------------------------- 1 | # Add text watermark on pictures 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll ask you what's the text you want to add as watermark, and the text size, transparency and position. Please use 20, 50% and bottom right as the default values. 7 | 3. It'll add the text watermark on every png pictures in the 'images' dirtionary of the current path, and save these pictures into 'watermark' dirtionary. 8 | 9 | ## What will we practice in this project? 10 | 11 | - for loop 12 | - input text 13 | - if conditions 14 | - functions 15 | - tuple 16 | - Open/save files 17 | - Image RGBA conception 18 | - os package 19 | - PIL package (need to install by `pip install pillow`) 20 | 21 | ## A reference code 22 | 23 | ```python 24 | import os 25 | 26 | from PIL import Image, ImageDraw, ImageFont 27 | 28 | 29 | def get_position(image_width, image_height, text_width, text_height, position_id=9, margin=10): 30 | ''' 31 | Get the position of the text by the position_id 32 | 1: top left, 2: top center, 3: top right 33 | 4: middle left, 5: middle center, 6: middle right 34 | 7: bottom left, 8: bottom center, 9: bottom right 35 | :param image_width: image width 36 | :param image_height: image height 37 | :param text_width: text width 38 | :param text_height: text height 39 | :param position_id: position_id 40 | :param margin: the text position margin value to the image 41 | :return: text position tuple 42 | ''' 43 | margin = 10 44 | if position_id == 1: 45 | return (margin, margin) 46 | elif position_id == 2: 47 | return (image_width // 2 - text_width // 2, margin) 48 | elif position_id == 3: 49 | return (image_width - text_width - margin, margin) 50 | elif position_id == 4: 51 | return (margin, image_height // 2 - text_height // 2) 52 | elif position_id == 5: 53 | return (image_width // 2 - text_width // 2, image_height // 2 - text_height // 2) 54 | elif position_id == 6: 55 | return (image_width - text_width - margin, image_height // 2 - text_height // 2) 56 | elif position_id == 7: 57 | return (margin, image_height - text_height - margin) 58 | elif position_id == 8: 59 | return (image_width // 2 - text_width // 2, image_height - text_height - margin) 60 | elif position_id == 9: 61 | return (image_width - text_width - margin, image_height - text_height - margin) 62 | 63 | 64 | def add_watermark(filename, text, font_name='Roboto-Italic.ttf', font_size=20, font_opacity=50, position_id=9): 65 | ''' 66 | Add watermark function 67 | :param filename: origin image filename 68 | :param text: watermark text 69 | :param font_name: Roboto-Italic.ttf, you can use your font, please make sure your program can find it 70 | :param font_size: font size, default is 20 71 | :param font_opacity: font opacity, default is 50 72 | :param position_id: position id, defalut is 9 (bottom right) 73 | :return: 74 | ''' 75 | # get an image 76 | with Image.open(filename).convert("RGBA") as base: 77 | # make a blank image for the text, initialized to transparent text color 78 | txt = Image.new("RGBA", base.size, (255, 255, 255, 0)) 79 | 80 | # get a font 81 | fnt = ImageFont.truetype(font_name, font_size) 82 | # get a drawing context 83 | d = ImageDraw.Draw(txt) 84 | # get the text widht and height 85 | text_width, text_height = d.textsize(text, font=fnt) 86 | # get the text position of the image 87 | pos = get_position(base.size[0], base.size[1], text_width, text_height, position_id=position_id) 88 | # draw text with opacity 89 | d.text(pos, text, font=fnt, fill=(255, 255, 255, 256 * font_opacity // 100)) 90 | out = Image.alpha_composite(base, txt) 91 | 92 | # save the image file 93 | out_filename = 'watermark/{}'.format(os.path.basename(filename)) 94 | if not os.path.exists('watermark'): 95 | os.makedirs('watermark') 96 | out.save(out_filename, 'PNG') 97 | 98 | 99 | if __name__ == '__main__': 100 | text = input('Please input a watermark text: ').strip() 101 | font_size = int(input('Please input the font size: [20]') or '20') 102 | font_opacity = int(input('Please input the font opacity: [50]') or '50') 103 | # 1: top left, 2: top center, 3: top right 104 | # 4: middle left, 5: middle center, 6: middle right 105 | # 7: bottom left, 8: bottom center, 9: bottom right 106 | position_id = int(input('Please input the position: [9]') or '9') 107 | 108 | for f in os.listdir('images'): 109 | if f.endswith('.png'): 110 | filename = 'images/{}'.format(f) 111 | print('add watermark for {}'.format(filename)) 112 | add_watermark(filename=filename, text=text, font_size=font_size, font_opacity=font_opacity, 113 | position_id=position_id) 114 | 115 | ``` 116 | 117 | ## Run the demo 118 | 119 | - make sure you have a `image` dirtionary and put some `png` files in this dirtionary 120 | - use `pip install requirements.txt` to install packages 121 | - run it in console 122 | 123 | ```shell 124 | python 3.py 125 | ``` 126 | 127 | - it'll add watermark on every picture in `images` dirtionary and save them to `watermark` dirtionary. 128 | 129 | ![](images/challenge_3_1.png) 130 | 131 | ![](images/challenge_3_2.png) 132 | 133 | ![](images/challenge_3_3.png) 134 | 135 | ![](images/challenge_3_4.png) 136 | 137 | ![](images/challenge_3_5.png) 138 | 139 | # 给图片增加文字水印 140 | 141 | ## 项目需求 142 | 143 | 1. 在命令行窗口运行; 144 | 2. 程序运行时,会提示输入水印的文字,以及水印文字大小,透明度和位置,文字大小默认值为20,透明度默认为50%,位置默认为右下角。使用数字1-9分别代表左上、中上、右上、中左、正中、中右、下左、下中、下右; 145 | 3. 程序会给当前目录下的images目录中所有png文件增加水印,并保存到watermark目录中。 146 | 147 | ## Python编程知识点 148 | 149 | - for循环 150 | - 用户输入字符串 151 | - 条件判断 152 | - 自定义函数 153 | - 元组 154 | - 打开、保存图片文件 155 | - 图片RGBA概念 156 | - os模块 157 | - PIL 模块 (需要使用`pip install pillow`安装) 158 | 159 | ## 参考代码 160 | 161 | ```python 162 | import os 163 | 164 | from PIL import Image, ImageDraw, ImageFont 165 | 166 | 167 | def get_position(image_width, image_height, text_width, text_height, position_id=9, margin=10): 168 | ''' 169 | 获取文字位置,position_id 170 | 1: 左上, 2: 中上, 3: 右上 171 | 4: 中左, 5: 正中, 6: 中右 172 | 7: 左下, 8: 下中, 9: 右下 173 | :param image_width: 图片宽度 174 | :param image_height: 图片高度 175 | :param text_width: 文字宽度 176 | :param text_height: 文字高度 177 | :param position_id: 位置ID,1-9,默认是9(右下) 178 | :param margin: 边距值,默认为10px 179 | :return: 文字位置的(x, y)元组 180 | ''' 181 | margin = 10 182 | if position_id == 1: 183 | return (margin, margin) 184 | elif position_id == 2: 185 | return (image_width // 2 - text_width // 2, margin) 186 | elif position_id == 3: 187 | return (image_width - text_width - margin, margin) 188 | elif position_id == 4: 189 | return (margin, image_height // 2 - text_height // 2) 190 | elif position_id == 5: 191 | return (image_width // 2 - text_width // 2, image_height // 2 - text_height // 2) 192 | elif position_id == 6: 193 | return (image_width - text_width - margin, image_height // 2 - text_height // 2) 194 | elif position_id == 7: 195 | return (margin, image_height - text_height - margin) 196 | elif position_id == 8: 197 | return (image_width // 2 - text_width // 2, image_height - text_height - margin) 198 | elif position_id == 9: 199 | return (image_width - text_width - margin, image_height - text_height - margin) 200 | 201 | 202 | def add_watermark(filename, text, font_name='Roboto-Italic.ttf', font_size=20, font_opacity=50, position_id=9): 203 | ''' 204 | 增加水印 205 | :param filename: 要加水印的文件(dir/file.png) 206 | :param text: 水印文字 207 | :param font_name: 默认为Roboto-Italic.ttf字体 208 | 你也可以使用自己的字体,确保代码能够找到这个字体文件(在当前目录或者系统字体目录中) 209 | :param font_size: 字体大小,默认值为20px 210 | :param font_opacity: 透明度,默认为50% 211 | :param position_id: 位置ID,1-9,默认是9(右下) 212 | :return: 213 | ''' 214 | # 打开原图片文件 215 | with Image.open(filename).convert("RGBA") as base: 216 | # 创建一个新的透明画面,大小和原图片一样 217 | txt = Image.new("RGBA", base.size, (255, 255, 255, 0)) 218 | # 使用指定的字体 219 | fnt = ImageFont.truetype(font_name, font_size) 220 | # 准备“画”文字 221 | d = ImageDraw.Draw(txt) 222 | # 得到文字的宽度和高度 223 | text_width, text_height = d.textsize(text, font=fnt) 224 | # 得到文字的位置 225 | pos = get_position(base.size[0], base.size[1], text_width, text_height, position_id=position_id) 226 | # 将文字“画”到画布上 227 | d.text(pos, text, font=fnt, fill=(255, 255, 255, 256 * font_opacity // 100)) 228 | # 将画布和原图片合并 229 | out = Image.alpha_composite(base, txt) 230 | 231 | # 保存图片文件 232 | out_filename = 'watermark/{}'.format(os.path.basename(filename)) 233 | if not os.path.exists('watermark'): 234 | os.makedirs('watermark') 235 | out.save(out_filename, 'PNG') 236 | 237 | 238 | if __name__ == '__main__': 239 | text = input('请输入水印文字: ').strip() 240 | font_size = int(input('请输入文字大小: [20]') or '20') 241 | font_opacity = int(input('请输入文字透明度: [50]') or '50') 242 | # 1: 左上, 2: 中上, 3: 右上 243 | # 4: 中左, 5: 正中, 6: 中右 244 | # 7: 左下, 8: 下中, 9: 右下 245 | position_id = int(input('请输入水印位置: [9]') or '9') 246 | 247 | for f in os.listdir('images'): 248 | if f.endswith('.png'): 249 | filename = 'images/{}'.format(f) 250 | print('给{}增加水印'.format(filename)) 251 | add_watermark(filename=filename, text=text, font_size=font_size, font_opacity=font_opacity, 252 | position_id=position_id) 253 | 254 | 255 | ``` 256 | 257 | ## 运行测试 258 | 259 | - 将需要加水印的图片放到当前目录的`images`目录中 260 | - 使用 `pip install requirements.txt`来安装工具包 261 | - 运行 262 | 263 | ```shell 264 | python 3.py 265 | ``` 266 | 267 | - 程序会将`images`目录中所有png图片增加水印并保存到`watermark`目录中 268 | 269 | ![](images/challenge_3_1.png) 270 | 271 | ![](images/challenge_3_2.png) 272 | 273 | ![](images/challenge_3_3.png) 274 | 275 | ![](images/challenge_3_4.png) 276 | 277 | ![](images/challenge_3_5.png) 278 | 279 | > 注意,如果要增加汉字水印,请使用一个汉字字体,使用Roboto-Italic.ttf无法显示汉字。 280 | 281 | -------------------------------------------------------------------------------- /004_Check_your_English_speech.md: -------------------------------------------------------------------------------- 1 | # Check your English speech 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll let you input a English word or sentence, then it'll let you speak it. 7 | 3. It'll record your voice using mic and check if you speak correctly. If not it'll ask you speak it again until you speak it correctly. 8 | 9 | ## What will we practice in this project? 10 | 11 | - for loop 12 | - input text 13 | - Text lower case 14 | - if conditions 15 | - functions 16 | - exception handle 17 | - SpeechRecognition package (need to install by `pip install SpeechRecognition`) it support these speech recognitions: 18 | - `recognize_bing()`: [Microsoft Bing Speech](https://azure.microsoft.com/en-us/services/cognitive-services/speech/) 19 | - `recognize_google()`: [Google Web Speech API](https://w3c.github.io/speech-api/speechapi.html) 20 | - `recognize_google_cloud()`: [Google Cloud Speech](https://cloud.google.com/speech/) - requires installation of the google-cloud-speech package 21 | - `recognize_houndify()`: [Houndify](https://www.houndify.com/) by SoundHound 22 | - `recognize_ibm()`: [IBM Speech to Text](https://www.ibm.com/watson/services/speech-to-text/) 23 | - `recognize_sphinx()`: [CMU Sphinx](https://cmusphinx.github.io/) - requires installing PocketSphinx 24 | - `recognize_wit()`: [Wit.ai](https://wit.ai/) 25 | - pyaudio package (need to install by `pip install pyaudio`) 26 | 27 | ## A reference code 28 | 29 | ```python 30 | import speech_recognition as sr 31 | 32 | 33 | def recognize_speech_from_mic(recognizer, microphone): 34 | ''' 35 | Transcribe speech from recorded from `microphone`. 36 | :param recognizer: 37 | :param microphone: 38 | :return: `None` if speech could not be transcribed, otherwise a string containing the transcribed text 39 | ''' 40 | print('Please read the English sentence') 41 | # adjust the recognizer sensitivity to ambient noise and record audio 42 | # from the microphone 43 | with microphone as source: 44 | recognizer.adjust_for_ambient_noise(source) 45 | audio = recognizer.listen(source) 46 | 47 | # try recognizing the speech in the recording 48 | try: 49 | text = recognizer.recognize_google(audio) 50 | except Exception as e: 51 | print(e) 52 | text = None 53 | 54 | return text 55 | 56 | 57 | if __name__ == '__main__': 58 | # input a English word or sentence 59 | text = input('Please input a English word or sentence: ').strip() 60 | 61 | # create recognizer and mic instances 62 | recognizer = sr.Recognizer() 63 | microphone = sr.Microphone() 64 | 65 | # get your speech text 66 | speech_text = recognize_speech_from_mic(recognizer, microphone) 67 | 68 | while speech_text != None and text.lower() != speech_text.lower(): 69 | print(speech_text) 70 | # get your speech text 71 | speech_text = recognize_speech_from_mic(recognizer, microphone) 72 | 73 | if speech_text: 74 | print('{} {}'.format(speech_text, '✓')) 75 | else: 76 | print('Please try the speech recognization service later or change another one.') 77 | 78 | ``` 79 | 80 | ## Run the demo 81 | 82 | - use `pip install requirements.txt` to install packages: `pyaudio` and `SpeechRecognition` 83 | - run it in console 84 | 85 | ```shell 86 | python 4.py 87 | ``` 88 | 89 | ![](images/challenge_4_en.png) 90 | 91 | ---- 92 | 93 | 94 | # 检测英语口语 95 | 96 | ## 项目需求 97 | 98 | 1. 在命令行窗口运行; 99 | 2. 程序运行时,会让你输入一句英语,然后你需要对着麦克风读出这句英语; 100 | 3. 程序会判断你读的对不对,如果不对会让你重读,直到读对为止。 101 | 102 | ## Python编程知识点 103 | 104 | - while循环 105 | - 用户输入字符串 106 | - 字符串小写 107 | - 条件判断 108 | - 自定义函数 109 | - 异常处理 110 | - SpeechRecognition 模块 (安装: `pip install SpeechRecognition`) it support these speech recognitions: 111 | - `recognize_bing()`: [Microsoft Bing Speech](https://azure.microsoft.com/en-us/services/cognitive-services/speech/) 112 | - `recognize_google()`: [Google Web Speech API](https://w3c.github.io/speech-api/speechapi.html) 113 | - `recognize_google_cloud()`: [Google Cloud Speech](https://cloud.google.com/speech/) - 需要安装`google-cloud-speech`模块 114 | - `recognize_houndify()`: [Houndify](https://www.houndify.com/) by SoundHound 115 | - `recognize_ibm()`: [IBM Speech to Text](https://www.ibm.com/watson/services/speech-to-text/) 116 | - `recognize_sphinx()`: [CMU Sphinx](https://cmusphinx.github.io/) - 需要安装`PocketSphinx`模块 117 | - `recognize_wit()`: [Wit.ai](https://wit.ai/) 118 | - pyaudio 模块 (安装: `pip install pyaudio`) 119 | 120 | ## 参考代码 121 | 122 | ```python 123 | import speech_recognition as sr 124 | 125 | 126 | def recognize_speech_from_mic(recognizer, microphone): 127 | ''' 128 | 麦克风录音并转文字 `microphone`. 129 | :param recognizer: 语音识别器 130 | :param microphone: 麦克风 131 | :return: `None` 如果识别失败返回None,否则返回语音文字 132 | ''' 133 | print('开始朗读') 134 | # 录音并去除噪音 135 | with microphone as source: 136 | recognizer.adjust_for_ambient_noise(source) 137 | audio = recognizer.listen(source) 138 | 139 | # 调用语音识别,亲测微软bing国内可用,国外建议使用google 140 | try: 141 | text = recognizer.recognize_google(audio) 142 | except Exception as e: 143 | print(e) 144 | text = None 145 | 146 | return text 147 | 148 | 149 | if __name__ == '__main__': 150 | # 输入 151 | text = input('请输入一句英语: ').strip() 152 | 153 | # 创建语音识别器和麦克风 154 | recognizer = sr.Recognizer() 155 | microphone = sr.Microphone() 156 | 157 | # 录音并获取文字 158 | speech_text = recognize_speech_from_mic(recognizer, microphone) 159 | 160 | while speech_text != None and text.lower() != speech_text.lower(): 161 | print(speech_text) 162 | speech_text = recognize_speech_from_mic(recognizer, microphone) 163 | 164 | if speech_text: 165 | print('{} {}'.format(speech_text, '✓')) 166 | else: 167 | print('语音识别服务暂不可用,请稍后再试。') 168 | 169 | ``` 170 | > 注意:本代码使用的是google语音识别,有些地区可能无法正常使用,请注册并使用其他的如微软Bing等语音识别服务等。 171 | 172 | ## 运行测试 173 | 174 | - 使用 `pip install requirements.txt` 安装模块: `pyaudio` and `SpeechRecognition` 175 | - 运行 176 | 177 | ```shell 178 | python 4.py 179 | ``` 180 | 181 | ![image-20210508095608400](images/challenge_4_cn.png) 182 | 183 | -------------------------------------------------------------------------------- /005_Check_your_English_speech_baidu.md: -------------------------------------------------------------------------------- 1 | # Check your English speech using Baidu AI cloud ASR service 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll let you input a English word or sentence, then it'll let you speak it. 7 | 3. It'll record your voice using mic and check if you speak correctly. If not it'll ask you speak it again until you speak it correctly. 8 | 4. It''ll will use Baidu AI Cloud ASR service: https://ai.baidu.com/tech/speech/asr 9 | 10 | ## What will we practice in this project? 11 | 12 | - for loop 13 | - input text 14 | - Text lower case 15 | - if conditions 16 | - functions 17 | - exception handle 18 | - SpeechRecognition package (need to install by `pip install SpeechRecognition`) 19 | - pyaudio package (need to install by `pip install pyaudio`) 20 | - baidu-aip package(need to install by `pip install baidu-aip`) 21 | 22 | ## A reference code 23 | 24 | ```python 25 | import speech_recognition as sr 26 | from aip import AipSpeech 27 | 28 | 29 | # Please signup baidu ASR service:https://ai.baidu.com/tech/speech/asr 30 | VOICE_APP_ID = 'YOUR_ASR_APP_ID' 31 | VOICE_API_KEY = 'YOUR_ASR_APP_KEY' 32 | VOICE_SECRET_KEY = 'YOUR_ASR_SECRET_KEY' 33 | voice_client = AipSpeech(VOICE_APP_ID, VOICE_API_KEY, VOICE_SECRET_KEY) 34 | 35 | 36 | # baidu asr service 37 | def asr(audio_data): 38 | wav_data = audio_data.get_wav_data( 39 | convert_rate=16000, 40 | convert_width=2 41 | ) 42 | res = voice_client.asr(wav_data, 'wav', 16000, { 43 | 'dev_pid': 1737, 44 | }) 45 | if res['err_no'] == 0: 46 | return ''.join(res['result']) 47 | else: 48 | return '' 49 | 50 | 51 | def recognize_speech_from_mic(recognizer, microphone): 52 | ''' 53 | Transcribe speech from recorded from `microphone`. 54 | :param recognizer: 55 | :param microphone: 56 | :return: `None` if speech could not be transcribed, otherwise a string containing the transcribed text 57 | ''' 58 | print('Please read the English sentence') 59 | # adjust the recognizer sensitivity to ambient noise and record audio 60 | # from the microphone 61 | with microphone as source: 62 | recognizer.adjust_for_ambient_noise(source) 63 | audio = recognizer.listen(source) 64 | 65 | # try recognizing the speech in the recording 66 | try: 67 | text = asr(audio) 68 | except Exception as e: 69 | print(e) 70 | text = None 71 | 72 | return text 73 | 74 | 75 | if __name__ == '__main__': 76 | # input a English word or sentence 77 | text = input('Please input a English word or sentence: ').strip() 78 | 79 | # create recognizer and mic instances 80 | recognizer = sr.Recognizer() 81 | microphone = sr.Microphone() 82 | 83 | # get your speech text 84 | speech_text = recognize_speech_from_mic(recognizer, microphone) 85 | 86 | while speech_text != None and text.lower() != speech_text.lower(): 87 | print('{} ×'.format(speech_text)) 88 | # get your speech text 89 | speech_text = recognize_speech_from_mic(recognizer, microphone) 90 | 91 | if speech_text: 92 | print('{} {}'.format(speech_text, '✓')) 93 | else: 94 | print('Please try the speech recognization service later or change another one.') 95 | 96 | ``` 97 | 98 | ## Run the demo 99 | 100 | - use `pip install requirements.txt` to install packages: `pyaudio`,`baidu-aip` and `SpeechRecognition` 101 | - run it in console 102 | 103 | ```shell 104 | python 5.py 105 | ``` 106 | 107 | ![](images/challenge_5_en.png) 108 | 109 | ---- 110 | 111 | 112 | # 检测英语口语(使用百度云语音识别) 113 | 114 | ## 项目需求 115 | 116 | 1. 在命令行窗口运行; 117 | 2. 程序运行时,会让你输入一句英语,然后你需要对着麦克风读出这句英语; 118 | 3. 程序会判断你读的对不对,如果不对会让你重读,直到读对为止; 119 | 4. 使用百度云语音识别:https://ai.baidu.com/tech/speech/asr。 120 | 121 | ## Python编程知识点 122 | 123 | - while循环 124 | - 用户输入字符串 125 | - 字符串小写 126 | - 条件判断 127 | - 自定义函数 128 | - 异常处理 129 | - SpeechRecognition 模块 (安装: `pip install SpeechRecognition`) 130 | - pyaudio 模块 (安装: `pip install pyaudio`) 131 | - baidu-aip 模块(安装: `pip install baidu-aip`) 132 | 133 | ## 参考代码 134 | 135 | ```python 136 | import speech_recognition as sr 137 | from aip import AipSpeech 138 | 139 | # 请自己注册百度云语音识别:https://ai.baidu.com/tech/speech/asr 140 | VOICE_APP_ID = 'YOUR_ASR_APP_ID' 141 | VOICE_API_KEY = 'YOUR_ASR_APP_KEY' 142 | VOICE_SECRET_KEY = 'YOUR_ASR_SECRET_KEY' 143 | voice_client = AipSpeech(VOICE_APP_ID, VOICE_API_KEY, VOICE_SECRET_KEY) 144 | 145 | 146 | # 百度云语音识别 147 | def asr(audio_data): 148 | wav_data = audio_data.get_wav_data( 149 | convert_rate=16000, 150 | convert_width=2 151 | ) 152 | res = voice_client.asr(wav_data, 'wav', 16000, { 153 | 'dev_pid': 1737, 154 | }) 155 | if res['err_no'] == 0: 156 | return ''.join(res['result']) 157 | else: 158 | return '' 159 | 160 | 161 | def recognize_speech_from_mic(recognizer, microphone): 162 | ''' 163 | 麦克风录音并转文字 `microphone`. 164 | :param recognizer: 语音识别器 165 | :param microphone: 麦克风 166 | :return: `None` 如果识别失败返回None,否则返回语音文字 167 | ''' 168 | print('开始朗读') 169 | # 录音并去除噪音 170 | with microphone as source: 171 | recognizer.adjust_for_ambient_noise(source) 172 | audio = recognizer.listen(source) 173 | 174 | # 使用百度云语音识别 175 | try: 176 | text = asr(audio) 177 | except Exception as e: 178 | print(e) 179 | text = None 180 | 181 | return text 182 | 183 | 184 | if __name__ == '__main__': 185 | # 输入 186 | text = input('请输入一句英语: ').strip() 187 | 188 | # 创建语音识别器和麦克风 189 | recognizer = sr.Recognizer() 190 | microphone = sr.Microphone() 191 | 192 | # 录音并获取文字 193 | speech_text = recognize_speech_from_mic(recognizer, microphone) 194 | 195 | while speech_text != None and text.lower() != speech_text.lower(): 196 | print('{} ×'.format(speech_text)) 197 | speech_text = recognize_speech_from_mic(recognizer, microphone) 198 | 199 | if speech_text: 200 | print('{} {}'.format(speech_text, '✓')) 201 | else: 202 | print('语音识别服务暂不可用,请稍后再试。') 203 | 204 | ``` 205 | ## 运行测试 206 | 207 | - 使用 `pip install requirements.txt` 安装模块: `pyaudio` ,`SpeechRecognition`,`baidu-aip` 208 | - 运行 209 | 210 | ```shell 211 | python 5.py 212 | ``` 213 | 214 | ![](images/challenge_5_cn.png) 215 | 216 | -------------------------------------------------------------------------------- /006_Arithmetic_Formatter.md: -------------------------------------------------------------------------------- 1 | > This chanllenge is come from freecodecamp.org website. You can find it from here: https://www.freecodecamp.org/learn/scientific-computing-with-python/scientific-computing-with-python-projects/arithmetic-formatter 2 | 3 | ### Assignment 4 | 5 | Students in primary school often arrange arithmetic problems vertically to make them easier to solve. For example, "235 + 52" becomes: 6 | ``` 7 | 235 8 | + 52 9 | ----- 10 | ``` 11 | 12 | Create a function that receives a list of strings that are arithmetic problems and returns the problems arranged vertically and side-by-side. The function should optionally take a second argument. When the second argument is set to `True`, the answers should be displayed. 13 | 14 | ### For example 15 | 16 | Function Call: 17 | ```py 18 | arithmetic_arranger(["32 + 698", "3801 - 2", "45 + 43", "123 + 49"]) 19 | ``` 20 | 21 | Output: 22 | ``` 23 | 32 3801 45 123 24 | + 698 - 2 + 43 + 49 25 | ----- ------ ---- ----- 26 | ``` 27 | 28 | Function Call: 29 | ```py 30 | arithmetic_arranger(["32 + 8", "1 - 3801", "9999 + 9999", "523 - 49"], True) 31 | ``` 32 | 33 | Output: 34 | ``` 35 | 32 1 9999 523 36 | + 8 - 3801 + 9999 - 49 37 | ---- ------ ------ ----- 38 | 40 -3800 19998 474 39 | ``` 40 | 41 | ### Rules 42 | 43 | The function will return the correct conversion if the supplied problems are properly formatted, otherwise, it will **return** a **string** that describes an error that is meaningful to the user. 44 | 45 | 46 | * Situations that will return an error: 47 | * If there are **too many problems** supplied to the function. The limit is **five**, anything more will return: 48 | `Error: Too many problems.` 49 | * The appropriate operators the function will accept are **addition** and **subtraction**. Multiplication and division will return an error. Other operators not mentioned in this bullet point will not need to be tested. The error returned will be: 50 | `Error: Operator must be '+' or '-'.` 51 | * Each number (operand) should only contain digits. Otherwise, the function will return: 52 | `Error: Numbers must only contain digits.` 53 | * Each operand (aka number on each side of the operator) has a max of four digits in width. Otherwise, the error string returned will be: 54 | `Error: Numbers cannot be more than four digits.` 55 | * If the user supplied the correct format of problems, the conversion you return will follow these rules: 56 | * There should be a single space between the operator and the longest of the two operands, the operator will be on the same line as the second operand, both operands will be in the same order as provided (the first will be the top one and the second will be the bottom. 57 | * Numbers should be right-aligned. 58 | * There should be four spaces between each problem. 59 | * There should be dashes at the bottom of each problem. The dashes should run along the entire length of each problem individually. (The example above shows what this should look like.) 60 | 61 | ### A reference code 62 | 63 | ```python 64 | def f(s): 65 | l = s.split(' ') 66 | try: 67 | a, op, b = int(l[0]), l[1], int(l[2]) 68 | except ValueError: 69 | raise Exception('Error: Numbers must only contain digits.') 70 | if not (op == '+' or op == '-'): 71 | raise Exception('Error: Operator must be \'+\' or \'-\'.') 72 | if a > 9999 or b > 9999: 73 | raise Exception('Error: Numbers cannot be more than four digits.') 74 | c = eval(s) 75 | max_len = len(str(max(a, b))) + 2 76 | 77 | r = [] 78 | r.append(str(a).rjust(max_len, ' ')) 79 | r.append(op + ' ' + str(b).rjust(max_len - 2, ' ')) 80 | r.append('-' * max_len) 81 | r.append(str(c).rjust(max_len, ' ')) 82 | return r 83 | 84 | 85 | def arithmetic_arranger(problems, show_result=False): 86 | if len(problems) > 5: 87 | return 'Error: Too many problems.' 88 | 89 | arranged_problems = '' 90 | d = [] 91 | for problem in problems: 92 | try: 93 | ps = f(problem) 94 | d.append(ps) 95 | except Exception as e: 96 | return str(e) 97 | 98 | n = 3 99 | if show_result: 100 | n = 4 101 | 102 | for i in range(n): 103 | for j in range(len(d)): 104 | ps = d[j] 105 | if j == 0: 106 | arranged_problems = arranged_problems + ps[i] 107 | else: 108 | arranged_problems = arranged_problems + ' ' + ps[i] 109 | if i != n - 1: 110 | arranged_problems = arranged_problems + '\n' 111 | 112 | return arranged_problems 113 | 114 | ``` 115 | 116 | Here is the unit test code: 117 | 118 | ```python 119 | import unittest 120 | from arithmetic_arranger import arithmetic_arranger 121 | 122 | 123 | # the test case 124 | class UnitTests(unittest.TestCase): 125 | def test_arrangement(self): 126 | actual = arithmetic_arranger(["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]) 127 | expected = " 3 3801 45 123\n+ 855 - 2 + 43 + 49\n----- ------ ---- -----" 128 | self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]') 129 | 130 | actual = arithmetic_arranger(["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"]) 131 | expected = " 11 3801 1 123 1\n+ 4 - 2999 + 2 + 49 - 9380\n---- ------ --- ----- ------" 132 | self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"]') 133 | 134 | def test_too_many_problems(self): 135 | actual = arithmetic_arranger(["44 + 815", "909 - 2", "45 + 43", "123 + 49", "888 + 40", "653 + 87"]) 136 | expected = "Error: Too many problems." 137 | self.assertEqual(actual, expected, 'Expected calling "arithmetic_arranger()" with more than five problems to return "Error: Too many problems."') 138 | 139 | def test_incorrect_operator(self): 140 | actual = arithmetic_arranger(["3 / 855", "3801 - 2", "45 + 43", "123 + 49"]) 141 | expected = "Error: Operator must be '+' or '-'." 142 | self.assertEqual(actual, expected, '''Expected calling "arithmetic_arranger()" with a problem that uses the "/" operator to return "Error: Operator must be '+' or '-'."''') 143 | 144 | def test_too_many_digits(self): 145 | actual = arithmetic_arranger(["24 + 85215", "3801 - 2", "45 + 43", "123 + 49"]) 146 | expected = "Error: Numbers cannot be more than four digits." 147 | self.assertEqual(actual, expected, 'Expected calling "arithmetic_arranger()" with a problem that has a number over 4 digits long to return "Error: Numbers cannot be more than four digits."') 148 | 149 | def test_only_digits(self): 150 | actual = arithmetic_arranger(["98 + 3g5", "3801 - 2", "45 + 43", "123 + 49"]) 151 | expected = "Error: Numbers must only contain digits." 152 | self.assertEqual(actual, expected, 'Expected calling "arithmetic_arranger()" with a problem that contains a letter character in the number to return "Error: Numbers must only contain digits."') 153 | 154 | def test_solutions(self): 155 | actual = arithmetic_arranger(["32 - 698", "1 - 3801", "45 + 43", "123 + 49"], True) 156 | expected = " 32 1 45 123\n- 698 - 3801 + 43 + 49\n----- ------ ---- -----\n -666 -3800 88 172" 157 | self.assertEqual(actual, expected, 'Expected solutions to be correctly displayed in output when calling "arithmetic_arranger()" with arithmetic problems and a second argument of `True`.') 158 | 159 | 160 | if __name__ == "__main__": 161 | unittest.main() 162 | 163 | ``` 164 | 165 | -------------------------------------------------------------------------------- /007_OpenCV_Capture_Camera_Video.md: -------------------------------------------------------------------------------- 1 | # OpenCV Capture Camera Video 2 | Use OpenCV to capture computer's camera and show the video. 3 | 4 | ## Requirements 5 | 6 | 1. It'll open the computer's camera and show the video in a window. 7 | 2. When you press "q" key it'll quit. 8 | 9 | ## What will we practice in this project? 10 | 11 | - OpenCV: you need to install the `opencv-python` package via `pip install opencv-python` command in this project environment. 12 | - while loop 13 | - if condition 14 | - keyboard check 15 | 16 | ## A reference code 17 | 18 | ```python 19 | import cv2 20 | 21 | # Open your computer's default camera device. 22 | # If your default camera ID is not 0, please use the correct ID 23 | camera = cv2.VideoCapture(0) 24 | 25 | # while loop to read the camera image 26 | while True: 27 | success, img = camera.read() 28 | # if read success, it'll show the image in a "Video" window 29 | if success: 30 | cv2.imshow('Video', img) 31 | # get the key press, if you pressed "q" key it'll break the while loop 32 | k = cv2.waitKey(1) 33 | if k == ord('q'): 34 | break 35 | 36 | # release your camera device and close the OpenCV windows 37 | camera.release() 38 | cv2.destroyAllWindows() 39 | 40 | ``` 41 | 42 | ## Run the demo 43 | Install the OpenCV: 44 | ```shell 45 | pip install -r requirements.txt 46 | ``` 47 | Please save the Python as opencv_capture_camera_video.py and run it in console: 48 | 49 | ``` 50 | python opencv_capture_camera_video.py 51 | ``` 52 | 53 | ---- 54 | 55 | # 使用OpenCV捕捉电脑摄像头视频 56 | 57 | ## 项目需求 58 | 59 | - 运行程序会打开电脑摄像头,并显示捕捉到的视频 60 | - 按`q`键会退出程序 61 | 62 | ## 项目练习 63 | 64 | - 安装OpenCV,需要使用`pip install opencv-python`将OpenCV安装到项目环境中 65 | - while循环 66 | - if条件判断 67 | - OpenCV窗口按键 68 | 69 | ## 项目参考代码 70 | 71 | ```python 72 | import cv2 73 | 74 | # 打开电脑摄像头 75 | # 默认摄像头编号为0,如果你的电脑默认摄像头编程不为0,请使用其他数字 76 | camera = cv2.VideoCapture(0) 77 | 78 | # 重复去读取摄像头捕捉到的视频 79 | while True: 80 | success, img = camera.read() 81 | # 如果捕捉成功,将捕捉到的视频显示在一个"Video"窗口中 82 | if success: 83 | cv2.imshow('Video', img) 84 | # 当在Video窗口上按下k键退出程序 85 | k = cv2.waitKey(1) 86 | if k == ord('q'): 87 | break 88 | 89 | # 释放摄像头并关闭OpenCV打开的窗口 90 | camera.release() 91 | cv2.destroyAllWindows() 92 | 93 | ``` 94 | 95 | ## 测试运行 96 | 97 | Install OpenCV: 98 | ```shell 99 | pip install -r requirements.txt 100 | ``` 101 | 保存代码为opencv_capture_camera_video.py并运行: 102 | 103 | ``` 104 | python opencv_capture_camera_video.py 105 | ``` 106 | -------------------------------------------------------------------------------- /008_OpenCV_MediaPipe_hand_detection.md: -------------------------------------------------------------------------------- 1 | # OpenCV Capture Camera Video 2 | Use OpenCV and MediaPipe to detect hands. 3 | https://google.github.io/mediapipe/solutions/hands 4 | 5 | ## Requirements 6 | 7 | 1. It'll open the computer's camera and show the video in a window. 8 | 2. When hands show in the video, it'll draw the hands landmarks. 9 | 3. When you press "q" key it'll quit. 10 | 11 | ## What will we practice in this project? 12 | 13 | - OpenCV: you need to install the `opencv-python` package via `pip install opencv-python` command in this project environment. 14 | - while loop 15 | - MediaPipe hands solution 16 | 17 | ## A reference code 18 | 19 | ### handUtils.py 20 | ```python 21 | import cv2 22 | import mediapipe as mp 23 | 24 | class HandDetector(): 25 | def __init__(self): 26 | self.hand_detector = mp.solutions.hands.Hands() 27 | self.drawer = mp.solutions.drawing_utils 28 | 29 | def process(self, img, draw=True): 30 | img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 31 | self.hands_data = self.hand_detector.process(img_rgb) 32 | if draw: 33 | if self.hands_data.multi_hand_landmarks: 34 | for handlms in self.hands_data.multi_hand_landmarks: 35 | self.drawer.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS) 36 | 37 | def find_position(self, img): 38 | h, w, c = img.shape 39 | position = {'Left': {}, 'Right': {}} 40 | if self.hands_data.multi_hand_landmarks: 41 | i = 0 42 | for point in self.hands_data.multi_handedness: 43 | score = point.classification[0].score 44 | if score >= 0.8: 45 | label = point.classification[0].label 46 | hand_lms = self.hands_data.multi_hand_landmarks[i].landmark 47 | for id, lm in enumerate(hand_lms): 48 | x, y = int(lm.x * w), int(lm.y * h) 49 | position[label][id] = (x, y) 50 | i = i + 1 51 | return position 52 | 53 | ``` 54 | ### hand.py 55 | ```python 56 | import cv2 57 | from handUtils import HandDetector 58 | 59 | camera = cv2.VideoCapture(1) 60 | hand_detector = HandDetector() 61 | 62 | while True: 63 | success, img = camera.read() 64 | if success: 65 | img = cv2.flip(img, 1) 66 | hand_detector.process(img, draw=False) 67 | position = hand_detector.find_position(img) 68 | left_finger = position['Left'].get(8, None) 69 | if left_finger: 70 | cv2.circle(img, (left_finger[0], left_finger[1]),10, (0, 0, 255), cv2.FILLED) 71 | right_finger = position['Right'].get(8, None) 72 | if right_finger: 73 | cv2.circle(img, (right_finger[0], right_finger[1]),10, (0, 255, 0), cv2.FILLED) 74 | cv2.imshow('Video', img) 75 | k = cv2.waitKey(1) 76 | if k == ord('q'): 77 | break 78 | 79 | camera.release() 80 | cv2.destroyAllWindows() 81 | 82 | ``` 83 | 84 | ## Run the demo 85 | Install the OpenCV & MediaPipe: 86 | ```shell 87 | pip install opencv-python mediapipe 88 | ``` 89 | Please save the 2 Python files and run it: 90 | 91 | ``` 92 | python hand.py 93 | ``` 94 | 95 | ---- 96 | 97 | # 使用OpenCV和MediaPipe进行手势识别 98 | 99 | ## 项目需求 100 | 101 | - 运行程序会打开电脑摄像头,并显示捕捉到的视频 102 | - 如果视频中出现了手,则显示手势连线 103 | - 按`q`键会退出程序 104 | 105 | ## 项目练习 106 | 107 | - 安装OpenCV,需要使用`pip install opencv-python mediapipe`将OpenCV和MediaPipe安装到项目环境中 108 | - MediaPipe手势识别:https://google.github.io/mediapipe/solutions/hands 109 | 110 | ## 项目参考代码 111 | 112 | ### handUtils.py 113 | ```python 114 | import cv2 115 | import mediapipe as mp 116 | 117 | class HandDetector(): 118 | def __init__(self): 119 | self.hand_detector = mp.solutions.hands.Hands() 120 | self.drawer = mp.solutions.drawing_utils 121 | 122 | def process(self, img, draw=True): 123 | img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 124 | self.hands_data = self.hand_detector.process(img_rgb) 125 | if draw: 126 | if self.hands_data.multi_hand_landmarks: 127 | for handlms in self.hands_data.multi_hand_landmarks: 128 | self.drawer.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS) 129 | 130 | def find_position(self, img): 131 | h, w, c = img.shape 132 | position = {'Left': {}, 'Right': {}} 133 | if self.hands_data.multi_hand_landmarks: 134 | i = 0 135 | for point in self.hands_data.multi_handedness: 136 | score = point.classification[0].score 137 | if score >= 0.8: 138 | label = point.classification[0].label 139 | hand_lms = self.hands_data.multi_hand_landmarks[i].landmark 140 | for id, lm in enumerate(hand_lms): 141 | x, y = int(lm.x * w), int(lm.y * h) 142 | position[label][id] = (x, y) 143 | i = i + 1 144 | return position 145 | 146 | ``` 147 | ### hand.py 148 | ```python 149 | import cv2 150 | from handUtils import HandDetector 151 | 152 | camera = cv2.VideoCapture(1) 153 | hand_detector = HandDetector() 154 | 155 | while True: 156 | success, img = camera.read() 157 | if success: 158 | img = cv2.flip(img, 1) 159 | hand_detector.process(img, draw=False) 160 | position = hand_detector.find_position(img) 161 | left_finger = position['Left'].get(8, None) 162 | if left_finger: 163 | cv2.circle(img, (left_finger[0], left_finger[1]),10, (0, 0, 255), cv2.FILLED) 164 | right_finger = position['Right'].get(8, None) 165 | if right_finger: 166 | cv2.circle(img, (right_finger[0], right_finger[1]),10, (0, 255, 0), cv2.FILLED) 167 | cv2.imshow('Video', img) 168 | k = cv2.waitKey(1) 169 | if k == ord('q'): 170 | break 171 | 172 | camera.release() 173 | cv2.destroyAllWindows() 174 | 175 | ``` 176 | 177 | ## 测试运行 178 | 179 | Install OpenCV and MediaPipe: 180 | ```shell 181 | pip install opencv-python mediapipe 182 | ``` 183 | 保存上面2个代码并运行: 184 | 185 | ``` 186 | python hand.py 187 | ``` 188 | -------------------------------------------------------------------------------- /009_OpenCV_MediaPipe_hands_fingers_count.md: -------------------------------------------------------------------------------- 1 | # OpenCV Capture Camera Video 2 | Use OpenCV and MediaPipe to detect hands and count fingers. 3 | This project is based on the previous one: https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/008_OpenCV_MediaPipe_hand_detection.md 4 | https://google.github.io/mediapipe/solutions/hands 5 | 6 | ## Requirements 7 | 8 | 1. It'll open the computer's camera and show the video in a window. 9 | 2. It'll show how many fingers of both hands you put on the screen. 10 | 3. When you press "q" key it'll quit. 11 | 12 | ## What will we practice in this project? 13 | 14 | - OpenCV: you need to install the `opencv-python` package via `pip install opencv-python` command in this project environment. 15 | - while loop 16 | - MediaPipe hands solution 17 | - list and dict usage 18 | - if condition 19 | 20 | ## A reference code 21 | 22 | ### handUtils.py 23 | ```python 24 | import cv2 25 | import mediapipe as mp 26 | 27 | class HandDetector(): 28 | def __init__(self): 29 | self.hand_detector = mp.solutions.hands.Hands() 30 | self.drawer = mp.solutions.drawing_utils 31 | 32 | def process(self, img, draw=True): 33 | img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 34 | self.hands_data = self.hand_detector.process(img_rgb) 35 | if draw: 36 | if self.hands_data.multi_hand_landmarks: 37 | for handlms in self.hands_data.multi_hand_landmarks: 38 | self.drawer.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS) 39 | 40 | def find_position(self, img): 41 | h, w, c = img.shape 42 | self.position = {'Left': {}, 'Right': {}} 43 | if self.hands_data.multi_hand_landmarks: 44 | i = 0 45 | for point in self.hands_data.multi_handedness: 46 | score = point.classification[0].score 47 | if score >= 0.8: 48 | label = point.classification[0].label 49 | hand_lms = self.hands_data.multi_hand_landmarks[i].landmark 50 | for id, lm in enumerate(hand_lms): 51 | x, y = int(lm.x * w), int(lm.y * h) 52 | self.position[label][id] = (x, y) 53 | i = i + 1 54 | return self.position 55 | 56 | def fingers_count(self, hand='Left'): 57 | tips = [4, 8, 12, 16, 20] 58 | tip_data = {4:0, 8:0, 12:0, 16:0, 20:0} 59 | for tip in tips: 60 | ltp1 = self.position[hand].get(tip, None) 61 | ltp2 = self.position[hand].get(tip-2, None) 62 | if ltp1 and ltp2: 63 | if tip == 4: 64 | if ltp1[0] > ltp2[0]: 65 | if hand == 'Left': 66 | tip_data[tip] = 1 67 | else: 68 | tip_data[tip] = 0 69 | else: 70 | if hand == 'Left': 71 | tip_data[tip] = 0 72 | else: 73 | tip_data[tip] = 1 74 | else: 75 | if ltp1[1] > ltp2[1]: 76 | tip_data[tip] = 0 77 | else: 78 | tip_data[tip] = 1 79 | return list(tip_data.values()).count(1) 80 | 81 | ``` 82 | 83 | ### hand.py 84 | ```python 85 | import cv2 86 | from handUtils import HandDetector 87 | 88 | camera = cv2.VideoCapture(1) 89 | hand_detector = HandDetector() 90 | 91 | while True: 92 | success, img = camera.read() 93 | if success: 94 | img = cv2.flip(img, 1) 95 | h, w, c = img.shape 96 | hand_detector.process(img, draw=False) 97 | position = hand_detector.find_position(img) 98 | left_fingers = hand_detector.fingers_count('Left') 99 | print('左手: ', left_fingers) 100 | cv2.putText(img, str(left_fingers), (100, 150), cv2.FONT_HERSHEY_DUPLEX, 5, (0, 255, 0)) 101 | right_fingers = hand_detector.fingers_count('Right') 102 | print('右手:', right_fingers) 103 | cv2.putText(img, str(right_fingers), (w-200, 150), cv2.FONT_HERSHEY_DUPLEX, 5, (255, 0, 0)) 104 | cv2.imshow('Video', img) 105 | k = cv2.waitKey(1) 106 | if k == ord('q'): 107 | break 108 | 109 | camera.release() 110 | cv2.destroyAllWindows() 111 | 112 | ``` 113 | 114 | ## Run the demo 115 | Install the OpenCV & MediaPipe: 116 | ```shell 117 | pip install opencv-python mediapipe 118 | ``` 119 | Please save the 2 Python files and run it: 120 | 121 | ``` 122 | python hand.py 123 | ``` 124 | 125 | ---- 126 | 127 | # 使用OpenCV和MediaPipe进行手势识别 128 | 129 | ## 项目需求 130 | 131 | - 运行程序会打开电脑摄像头,并显示捕捉到的视频 132 | - 视频窗口上会显示左右手各伸出了多少手指头 133 | - 按`q`键会退出程序 134 | 135 | ## 项目练习 136 | 137 | - 安装OpenCV,需要使用`pip install opencv-python mediapipe`将OpenCV和MediaPipe安装到项目环境中 138 | - MediaPipe手势识别:https://google.github.io/mediapipe/solutions/hands 139 | - list 和 dict 140 | - while 循环 141 | - 条件语句 142 | 143 | ## 项目参考代码 144 | 145 | ### handUtils.py 146 | ```python 147 | import cv2 148 | import mediapipe as mp 149 | 150 | class HandDetector(): 151 | def __init__(self): 152 | self.hand_detector = mp.solutions.hands.Hands() 153 | self.drawer = mp.solutions.drawing_utils 154 | 155 | def process(self, img, draw=True): 156 | img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 157 | self.hands_data = self.hand_detector.process(img_rgb) 158 | if draw: 159 | if self.hands_data.multi_hand_landmarks: 160 | for handlms in self.hands_data.multi_hand_landmarks: 161 | self.drawer.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS) 162 | 163 | def find_position(self, img): 164 | h, w, c = img.shape 165 | self.position = {'Left': {}, 'Right': {}} 166 | if self.hands_data.multi_hand_landmarks: 167 | i = 0 168 | for point in self.hands_data.multi_handedness: 169 | score = point.classification[0].score 170 | if score >= 0.8: 171 | label = point.classification[0].label 172 | hand_lms = self.hands_data.multi_hand_landmarks[i].landmark 173 | for id, lm in enumerate(hand_lms): 174 | x, y = int(lm.x * w), int(lm.y * h) 175 | self.position[label][id] = (x, y) 176 | i = i + 1 177 | return self.position 178 | 179 | def fingers_count(self, hand='Left'): 180 | tips = [4, 8, 12, 16, 20] 181 | tip_data = {4:0, 8:0, 12:0, 16:0, 20:0} 182 | for tip in tips: 183 | ltp1 = self.position[hand].get(tip, None) 184 | ltp2 = self.position[hand].get(tip-2, None) 185 | if ltp1 and ltp2: 186 | if tip == 4: 187 | if ltp1[0] > ltp2[0]: 188 | if hand == 'Left': 189 | tip_data[tip] = 1 190 | else: 191 | tip_data[tip] = 0 192 | else: 193 | if hand == 'Left': 194 | tip_data[tip] = 0 195 | else: 196 | tip_data[tip] = 1 197 | else: 198 | if ltp1[1] > ltp2[1]: 199 | tip_data[tip] = 0 200 | else: 201 | tip_data[tip] = 1 202 | return list(tip_data.values()).count(1) 203 | 204 | ``` 205 | 206 | ### hand.py 207 | ```python 208 | import cv2 209 | from handUtils import HandDetector 210 | 211 | camera = cv2.VideoCapture(1) 212 | hand_detector = HandDetector() 213 | 214 | while True: 215 | success, img = camera.read() 216 | if success: 217 | img = cv2.flip(img, 1) 218 | h, w, c = img.shape 219 | hand_detector.process(img, draw=False) 220 | position = hand_detector.find_position(img) 221 | left_fingers = hand_detector.fingers_count('Left') 222 | print('左手: ', left_fingers) 223 | cv2.putText(img, str(left_fingers), (100, 150), cv2.FONT_HERSHEY_DUPLEX, 5, (0, 255, 0)) 224 | right_fingers = hand_detector.fingers_count('Right') 225 | print('右手:', right_fingers) 226 | cv2.putText(img, str(right_fingers), (w-200, 150), cv2.FONT_HERSHEY_DUPLEX, 5, (255, 0, 0)) 227 | cv2.imshow('Video', img) 228 | k = cv2.waitKey(1) 229 | if k == ord('q'): 230 | break 231 | 232 | camera.release() 233 | cv2.destroyAllWindows() 234 | 235 | ``` 236 | 237 | ## 测试运行 238 | 239 | Install OpenCV and MediaPipe: 240 | ```shell 241 | pip install opencv-python mediapipe 242 | ``` 243 | 保存上面2个代码并运行: 244 | 245 | ``` 246 | python hand.py 247 | ``` 248 | -------------------------------------------------------------------------------- /010_gobang.md: -------------------------------------------------------------------------------- 1 | # 10 gobang 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll open a Python window to let 2 players play gobang game. 7 | 8 | ## What will we practice in this project? 9 | 10 | - turtle draw 11 | - mouse click event handle 12 | - 2d array 13 | - list 14 | - exception handle 15 | - function 16 | 17 | ## A reference code 18 | 19 | ```python 20 | from turtle import * 21 | 22 | win = False 23 | 24 | speed(0) 25 | bgcolor("lightgreen") 26 | yanse="black" 27 | gz=40 28 | 29 | judge = Turtle() 30 | judge.up() 31 | judge.goto(-460, 330) 32 | judge.write("Next", font=("Arial", 40, "bold")) 33 | judge.color(yanse) 34 | judge.goto(-420, 300) 35 | judge.dot(30) 36 | 37 | for i in range(19): 38 | up() 39 | goto(-gz*9, gz*(9-i)) 40 | down() 41 | fd(gz*18) 42 | bk(gz*18) 43 | 44 | rt(90) 45 | 46 | for i in range(19): 47 | up() 48 | goto(-gz*(9-i), gz*9) 49 | down() 50 | fd(gz*18) 51 | bk(gz*18) 52 | 53 | pensize(5) 54 | for i in range(4): 55 | fd(gz*18) 56 | rt(90) 57 | 58 | # m = [[0] * 19 for i in range(19)] 59 | m =[ 60 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 61 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 62 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 63 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 64 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 65 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 66 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 67 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 68 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 69 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 70 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 71 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 72 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 73 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 74 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 75 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 76 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 77 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 78 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 79 | ] 80 | 81 | def check(i, j): 82 | global win 83 | g = [0] * 8 84 | fw = ((0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1)) 85 | for index in range(8): 86 | d = fw[index] 87 | next_i = i + d[0] 88 | next_j = j + d[1] 89 | while next_i in range(19) and next_j in range(19) and m[next_i][next_j] == m[i][j]: 90 | g[index] = g[index] + 1 91 | next_i = next_i + d[0] 92 | next_j = next_j + d[1] 93 | 94 | for index in range(4): 95 | if g[index] + g[index + 4] + 1 >= 5: 96 | win = True 97 | goto(0, 0) 98 | if yanse == "black": 99 | write('Black Win', font=('Arial', 100, ''), align='center') 100 | else: 101 | write('White Win', font=('Arial', 100, ''), align='center') 102 | break 103 | 104 | def play(x, y): 105 | if not win: 106 | global yanse 107 | global gz 108 | color(yanse) 109 | up() 110 | x = round(x/gz)*gz 111 | y = round(y/gz)*gz 112 | i = int(9 - y / gz) 113 | j = int(x / gz + 9) 114 | 115 | if i >= 0 and i <= 18 and j >=0 and j<=18: 116 | if m[i][j] == 0: 117 | goto(x, y) 118 | dot(30) 119 | 120 | if yanse == "black": 121 | m[i][j] = 1 122 | check(i, j) 123 | yanse="white" 124 | else: 125 | m[i][j] = 2 126 | check(i, j) 127 | yanse="black" 128 | 129 | judge.color(yanse) 130 | judge.dot(30) 131 | 132 | onscreenclick(play, 1) 133 | done() 134 | 135 | ``` 136 | 137 | ## Run the demo 138 | 139 | Please save the Python as gobang.py and run it in console: 140 | 141 | ``` 142 | python gobang.py 143 | ``` 144 | 145 | ![Chanllenge 10](images/challenge_10_2.png) 146 | 147 | ---- 148 | 149 | # 1分钟数学运算 150 | 151 | ## 项目需求 152 | 153 | - 直接在控制台使用命令行运行 154 | - 运行之后出现五子棋小游戏 155 | 156 | ## 项目练习 157 | 158 | - turtle工具包 159 | - 自定义函数 160 | - 二维列表 161 | - 鼠标事件 162 | 163 | ## 项目参考代码 164 | 165 | ```python 166 | # 导入turtle工具包 167 | from turtle import * 168 | 169 | # 输赢 170 | win = False 171 | 172 | # 最快速度 173 | speed(0) 174 | # 背景颜色 175 | bgcolor("lightgreen") 176 | # 颜色变量,默认是黑色 177 | yanse="black" 178 | # 格子大小 179 | gz=40 180 | 181 | judge = Turtle() 182 | judge.up() 183 | judge.goto(-460, 330) 184 | judge.write("谁下", font=("Kai", 40, "bold")) 185 | judge.color(yanse) 186 | judge.goto(-420, 300) 187 | judge.dot(30) 188 | 189 | # 画19条横线 190 | for i in range(19): 191 | up() 192 | goto(-gz*9, gz*(9-i)) 193 | down() 194 | fd(gz*18) 195 | bk(gz*18) 196 | 197 | rt(90) 198 | # 画19条竖线 199 | for i in range(19): 200 | up() 201 | goto(-gz*(9-i), gz*9) 202 | down() 203 | fd(gz*18) 204 | bk(gz*18) 205 | 206 | # 画最外面的粗边框 207 | pensize(5) 208 | for i in range(4): 209 | fd(gz*18) 210 | rt(90) 211 | 212 | # 2维列表,存储棋盘棋子数据,0表示没有棋子,1表示黑棋,2表示白棋 213 | # m = [[0] * 19 for i in range(19)] 214 | m =[ 215 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 216 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 217 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 218 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 219 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 220 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 221 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 222 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 223 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 224 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 225 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 226 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 227 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 228 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 229 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 230 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 231 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 232 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 233 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 234 | ] 235 | 236 | # 判断输赢 237 | def check(i, j): 238 | global win 239 | g = [0] * 8 240 | fw = ((0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1)) 241 | for index in range(8): 242 | d = fw[index] 243 | next_i = i + d[0] 244 | next_j = j + d[1] 245 | while next_i in range(19) and next_j in range(19) and m[next_i][next_j] == m[i][j]: 246 | g[index] = g[index] + 1 247 | next_i = next_i + d[0] 248 | next_j = next_j + d[1] 249 | 250 | for index in range(4): 251 | if g[index] + g[index + 4] + 1 >= 5: 252 | win = True 253 | goto(0, 0) 254 | if yanse == "black": 255 | write('黑方胜', font=('', 100, ''), align='center') 256 | else: 257 | write('白方胜', font=('', 100, ''), align='center') 258 | break 259 | 260 | # 放棋子的自定义函数 261 | def play(x, y): 262 | if not win: 263 | global yanse 264 | global gz 265 | color(yanse) 266 | up() 267 | # x变成格子的整数倍,个位数上要进行4舍5入 268 | x = round(x/gz)*gz 269 | # y变成格子的整数倍,个位数上要进行4舍5入 270 | y = round(y/gz)*gz 271 | # 计算棋子在电脑中的位置 272 | i = int(9 - y / gz) 273 | j = int(x / gz + 9) 274 | 275 | # 只有棋子在棋盘范围内才可以下 276 | if i >= 0 and i <= 18 and j >=0 and j<=18: 277 | # 如果[i, j]没有棋子 278 | if m[i][j] == 0: 279 | goto(x, y) 280 | dot(30) 281 | 282 | if yanse == "black": 283 | m[i][j] = 1 284 | # 判断输赢 285 | check(i, j) 286 | yanse="white" 287 | else: 288 | m[i][j] = 2 289 | # 判断输赢 290 | check(i, j) 291 | yanse="black" 292 | 293 | # 裁判变色并重新画点 294 | judge.color(yanse) 295 | judge.dot(30) 296 | 297 | # 当鼠标左键点击屏幕时执行放棋子的自定义函数 298 | onscreenclick(play, 1) 299 | done() 300 | 301 | ``` 302 | 303 | ## 测试运行 304 | 305 | 将代码保存为gobang.py,然后在控制台运行: 306 | 307 | ``` 308 | python gobang.py 309 | ``` 310 | 311 | ![挑战10](images/challenge_10_1.png) -------------------------------------------------------------------------------- /011_snake_game.md: -------------------------------------------------------------------------------- 1 | # 11 Snake game 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll open a Python window to play the snake game. 7 | 8 | ## What will we practice in this project? 9 | 10 | - turtle diagram 11 | - key event handle 12 | - if condition 13 | - timer 14 | - object clone 15 | - list 16 | 17 | ## A reference code 18 | 19 | ```python 20 | from turtle import * 21 | from random import randint 22 | 23 | gz = 22 24 | bc = gz * 8 25 | 26 | screen = Screen() 27 | screen.bgcolor("darkblue") 28 | 29 | food = Turtle() 30 | food.color("red") 31 | food.shape("square") 32 | food.up() 33 | food.speed(0) 34 | food.goto(randint(-bc+gz, bc-gz)//gz*gz, randint(-bc+gz, bc-gz)//gz*gz) 35 | 36 | liner = Turtle() 37 | liner.speed(0) 38 | liner.up() 39 | liner.goto(-bc, bc) 40 | liner.color("white") 41 | liner.pensize(5) 42 | liner.down() 43 | for i in range(4): 44 | liner.fd(bc*2) 45 | liner.rt(90) 46 | liner.ht() 47 | 48 | score = 0 49 | judge = Turtle() 50 | judge.speed(0) 51 | judge.up() 52 | judge.goto(0, bc+20) 53 | judge.color("white") 54 | judge.write("得分:{}".format(score), align="center", font=("Kai", 20, "bold")) 55 | judge.ht() 56 | 57 | head = Turtle() 58 | head.speed(0) 59 | head.up() 60 | head.color("cyan") 61 | head.shape("square") 62 | 63 | snake = [] 64 | snake.append(head) 65 | for i in range(2): 66 | body = head.clone() 67 | body.color("white") 68 | body.goto(head.xcor()+(i+1)*gz, head.ycor()) 69 | snake.append(body) 70 | 71 | d = [-1, 0] 72 | def move(): 73 | last = snake.pop() 74 | first = snake[0] 75 | first.color("white") 76 | last.goto(first.xcor() + d[0] * gz, first.ycor() + d[1] * gz) 77 | last.color("cyan") 78 | snake.insert(0, last) 79 | 80 | if snake[0].xcor() == food.xcor() and snake[0].ycor() == food.ycor(): 81 | food.ht() 82 | food.goto(randint(-bc+gz, bc-gz)//gz*gz, randint(-bc+gz, bc-gz)//gz*gz) 83 | food.st() 84 | body = snake[-1].clone() 85 | snake.append(body) 86 | global score 87 | score += 1 88 | judge.clear() 89 | judge.write("得分:{}".format(score), align="center", font=("Kai", 20, "bold")) 90 | 91 | if (snake[0].xcor() > -bc and snake[0].xcor() < bc) and \ 92 | (snake[0].ycor() > -bc and snake[0].ycor() < bc): 93 | screen.ontimer(move, 500) 94 | 95 | def up(): 96 | global d 97 | if d[1] != -1: 98 | d = [0, 1] 99 | def down(): 100 | global d 101 | if d[1] != 1: 102 | d = [0, -1] 103 | def left(): 104 | global d 105 | if d[0] != 1: 106 | d = [-1, 0] 107 | def right(): 108 | global d 109 | if d[0] != -1: 110 | d = [1, 0] 111 | 112 | screen.onkey(up, "Up") 113 | screen.onkey(down, "Down") 114 | screen.onkey(left, "Left") 115 | screen.onkey(right, "Right") 116 | 117 | screen.listen() 118 | 119 | move() 120 | 121 | ``` 122 | 123 | ## Run the demo 124 | 125 | Please save the Python as snake.py and run it in console: 126 | 127 | ``` 128 | python snake.py 129 | ``` 130 | 131 | ![Chanllenge 11](images/011_snake.png) 132 | 133 | ---- 134 | 135 | # 贪吃蛇小游戏 136 | 137 | ## 项目需求 138 | 139 | - 直接在控制台使用命令行运行 140 | - 运行之后出现贪吃蛇小游戏 141 | 142 | ## 项目练习 143 | 144 | - turtle 145 | - 键盘事件响应 146 | - 条件语句 147 | - 定时器 148 | - 对象克隆 149 | - 列表 150 | 151 | ## 项目参考代码 152 | 153 | ```python 154 | from turtle import * 155 | from random import randint 156 | 157 | gz = 22 158 | bc = gz * 8 159 | 160 | screen = Screen() 161 | screen.bgcolor("darkblue") 162 | 163 | food = Turtle() 164 | food.color("red") 165 | food.shape("square") 166 | food.up() 167 | food.speed(0) 168 | food.goto(randint(-bc+gz, bc-gz)//gz*gz, randint(-bc+gz, bc-gz)//gz*gz) 169 | 170 | liner = Turtle() 171 | liner.speed(0) 172 | liner.up() 173 | liner.goto(-bc, bc) 174 | liner.color("white") 175 | liner.pensize(5) 176 | liner.down() 177 | for i in range(4): 178 | liner.fd(bc*2) 179 | liner.rt(90) 180 | liner.ht() 181 | 182 | score = 0 183 | judge = Turtle() 184 | judge.speed(0) 185 | judge.up() 186 | judge.goto(0, bc+20) 187 | judge.color("white") 188 | judge.write("得分:{}".format(score), align="center", font=("Kai", 20, "bold")) 189 | judge.ht() 190 | 191 | head = Turtle() 192 | head.speed(0) 193 | head.up() 194 | head.color("cyan") 195 | head.shape("square") 196 | 197 | snake = [] 198 | snake.append(head) 199 | for i in range(2): 200 | body = head.clone() 201 | body.color("white") 202 | body.goto(head.xcor()+(i+1)*gz, head.ycor()) 203 | snake.append(body) 204 | 205 | d = [-1, 0] 206 | def move(): 207 | last = snake.pop() 208 | first = snake[0] 209 | first.color("white") 210 | last.goto(first.xcor() + d[0] * gz, first.ycor() + d[1] * gz) 211 | last.color("cyan") 212 | snake.insert(0, last) 213 | 214 | if snake[0].xcor() == food.xcor() and snake[0].ycor() == food.ycor(): 215 | food.ht() 216 | food.goto(randint(-bc+gz, bc-gz)//gz*gz, randint(-bc+gz, bc-gz)//gz*gz) 217 | food.st() 218 | body = snake[-1].clone() 219 | snake.append(body) 220 | global score 221 | score += 1 222 | judge.clear() 223 | judge.write("得分:{}".format(score), align="center", font=("Kai", 20, "bold")) 224 | 225 | if (snake[0].xcor() > -bc and snake[0].xcor() < bc) and \ 226 | (snake[0].ycor() > -bc and snake[0].ycor() < bc): 227 | screen.ontimer(move, 500) 228 | 229 | def up(): 230 | global d 231 | if d[1] != -1: 232 | d = [0, 1] 233 | def down(): 234 | global d 235 | if d[1] != 1: 236 | d = [0, -1] 237 | def left(): 238 | global d 239 | if d[0] != 1: 240 | d = [-1, 0] 241 | def right(): 242 | global d 243 | if d[0] != -1: 244 | d = [1, 0] 245 | 246 | screen.onkey(up, "Up") 247 | screen.onkey(down, "Down") 248 | screen.onkey(left, "Left") 249 | screen.onkey(right, "Right") 250 | 251 | screen.listen() 252 | 253 | move() 254 | 255 | ``` 256 | 257 | ## 测试运行 258 | 259 | 将代码保存为snake.py,然后在控制台运行: 260 | 261 | ``` 262 | python snake.py 263 | ``` 264 | 265 | ![挑战11](images/011_snake.png) -------------------------------------------------------------------------------- /012_Minesweeper.md: -------------------------------------------------------------------------------- 1 | # 12 Minesweeper 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll open a Python window to play the Minesweeper game. 7 | 8 | ## What will we practice in this project? 9 | 10 | - turtle diagram 11 | - mouse click event handle 12 | - key event handle 13 | - if condition 14 | - for loop 15 | - list 16 | - recursion 17 | 18 | ## A reference code 19 | 20 | ```python 21 | from turtle import * 22 | from math import floor 23 | from random import randint 24 | 25 | n = 10 26 | gz = 40 27 | bc = n * gz 28 | win = False 29 | dead = False 30 | can_start = True 31 | fx = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]] 32 | # random Mines count 33 | booms = randint(n * n // 10, n * n // 2) 34 | d = [] 35 | m = [] 36 | c = [] 37 | b = [] 38 | 39 | t = Turtle() 40 | t.ht() 41 | t.up() 42 | t.speed(0) 43 | 44 | judge = Turtle() 45 | judge.ht() 46 | judge.up() 47 | judge.speed(0) 48 | 49 | 50 | # draw 51 | def draw(): 52 | t.clear() 53 | t.seth(0) 54 | t.color("black") 55 | t.goto(-bc / 2, bc / 2) 56 | for i in range(n + 1): 57 | t.down() 58 | t.fd(bc) 59 | t.bk(bc) 60 | t.up() 61 | t.goto(-bc / 2, bc / 2 - (i + 1) * gz) 62 | t.goto(-bc / 2, bc / 2) 63 | t.rt(90) 64 | for i in range(n + 1): 65 | t.down() 66 | t.fd(bc) 67 | t.bk(bc) 68 | t.up() 69 | t.goto(-bc / 2 + (i + 1) * gz, bc / 2) 70 | 71 | 72 | # write the booms count 73 | def write_booms(): 74 | judge.clear() 75 | judge.goto(-gz, bc / 2 + gz - gz / 8) 76 | judge.color("red") 77 | judge.dot(20) 78 | judge.goto(0, bc / 2 + gz / 2) 79 | judge.write(": {}".format(booms), align="center", font=("Kai", 30, "bold")) 80 | 81 | 82 | # init list method 83 | def init_list(n, default=0): 84 | lines = [] 85 | for i in range(n): 86 | line = [] 87 | for j in range(n): 88 | line.append(default) 89 | lines.append(line) 90 | return lines 91 | 92 | 93 | # print list for debug useage 94 | def print_list(lines): 95 | print() 96 | for line in lines: 97 | for item in line: 98 | print(item, end=' ') 99 | print() 100 | print() 101 | 102 | 103 | # x,y -> i, j 104 | def xytoij(x, y): 105 | ix = floor(x / gz) * gz 106 | iy = floor(y / gz) * gz 107 | j = (ix + bc / 2) / gz 108 | i = (bc / 2 - iy) / gz - 1 109 | return int(i), int(j) 110 | 111 | 112 | # i, j -> x, y 113 | def ijtoxy(i, j): 114 | x = -bc / 2 + gz / 2 + j * gz 115 | y = bc / 2 - gz / 2 - i * gz - gz / 4 116 | return x, y 117 | 118 | 119 | # set color base booms count 120 | def set_color(booms): 121 | if booms <= 1: 122 | t.color("green") 123 | elif booms == 2: 124 | t.color("blue") 125 | elif booms == 3: 126 | t.color("brown") 127 | elif booms == 4: 128 | t.color("orange") 129 | elif booms == 5: 130 | t.color("red") 131 | elif booms >= 6: 132 | t.color("purple") 133 | 134 | 135 | # start game 136 | def start(): 137 | global d, m, c, b, booms, can_start, win, dead 138 | if can_start: 139 | win = False 140 | dead = False 141 | can_start = False 142 | draw() 143 | # 0 not boom, 1 boom 144 | d = init_list(n) 145 | # 0 not mark, 1 markd 146 | m = init_list(n) 147 | # 0 not click, 1 clicked 148 | c = init_list(n) 149 | # count how many booms around 150 | b = init_list(n) 151 | booms = randint(n * n // 10, n * n // 2) 152 | # random boom count 153 | for k in range(booms): 154 | i = randint(0, n - 1) 155 | j = randint(0, n - 1) 156 | d[i][j] = 1 157 | 158 | write_booms() 159 | 160 | # count around booms (-1 means boom) 161 | for i in range(n): 162 | for j in range(n): 163 | if d[i][j] == 1: 164 | b[i][j] = -1 165 | for f in fx: 166 | ni = i + f[0] 167 | nj = j + f[1] 168 | if (ni >= 0 and ni < n and nj >= 0 and nj < n and b[ni][nj] != -1): 169 | b[ni][nj] += 1 170 | 171 | 172 | # check i, j around 173 | def check_around(i, j): 174 | cnt = 0 175 | for f in fx: 176 | ni = i + f[0] 177 | nj = j + f[1] 178 | 179 | if (ni >= 0 and ni < n and nj >= 0 and nj < n): 180 | if d[ni][nj] == 1 and m[ni][nj] == 1: 181 | cnt += 1 182 | return b[i][j] == cnt 183 | 184 | 185 | # check 8 directions of i, j and do the recursion 186 | def check_and_auto_click(i, j): 187 | if (i >= 0 and i < n and j >= 0 and j < n and check_around(i, j)): 188 | for f in fx: 189 | ni = i + f[0] 190 | nj = j + f[1] 191 | if (ni >= 0 and ni < n and nj >= 0 and nj < n and b[ni][nj] != -1 and c[ni][nj] == 0): 192 | c[ni][nj] = 1 193 | check_and_auto_click(ni, nj) 194 | x, y = ijtoxy(ni, nj) 195 | t.goto(x, y) 196 | set_color(b[ni][nj]) 197 | t.write(b[ni][nj], align="center", font=("Arial", 20, "normal")) 198 | 199 | 200 | # check if win 201 | def check_win(): 202 | for i in range(n): 203 | for j in range(n): 204 | if m[i][j] != d[i][j]: 205 | return False 206 | return True 207 | 208 | 209 | # left mouse click 210 | def click(x, y): 211 | global dead, win, can_start 212 | if not dead and not win: 213 | i, j = xytoij(x, y) 214 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 215 | c[i][j] = 1 216 | if d[i][j] == 1: 217 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 218 | t.color("red") 219 | t.dot(20) 220 | dead = True 221 | can_start = True 222 | judge.clear() 223 | judge.color("red") 224 | judge.write("Failed, press Sapce to restart.", align="center", font=("Kai", 40, "bold")) 225 | else: 226 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 4) 227 | set_color(b[i][j]) 228 | t.write(b[i][j], align="center", font=("Arial", 20, "normal")) 229 | check_and_auto_click(i, j) 230 | if check_win(): 231 | win = True 232 | can_start = True 233 | judge.clear() 234 | judge.color("green") 235 | judge.write("Success, press Sapce to restart.", align="center", font=("Kai", 40, "bold")) 236 | 237 | 238 | # mouse right click to mark 239 | def mark(x, y): 240 | global booms, win, can_start 241 | if not dead and not win: 242 | i, j = xytoij(x, y) 243 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 244 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 245 | if m[i][j] == 0: 246 | m[i][j] = 1 247 | t.color("green") 248 | t.dot(20) 249 | booms -= 1 250 | else: 251 | m[i][j] = 0 252 | t.color("white") 253 | t.dot(22) 254 | booms += 1 255 | write_booms() 256 | if check_win(): 257 | win = True 258 | can_start = True 259 | judge.clear() 260 | judge.color("green") 261 | judge.write("Success, press Sapce to restart.", align="center", font=("Kai", 40, "bold")) 262 | 263 | start() 264 | screen = Screen() 265 | screen.onscreenclick(click, 1) 266 | screen.onscreenclick(mark, 2) 267 | screen.onkey(start, "space") 268 | screen.listen() 269 | done() 270 | 271 | ``` 272 | 273 | ## Run the demo 274 | 275 | Please save the Python as minesweeper.py and run it in console: 276 | 277 | ``` 278 | python minesweeper.py 279 | ``` 280 | 281 | ![Chanllenge 10](images/012_minesweeper.png) 282 | 283 | ---- 284 | 285 | # 扫雷小游戏 286 | 287 | ## 项目需求 288 | 289 | - 直接在控制台使用命令行运行 290 | - 运行之后出现扫雷小游戏 291 | 292 | ## 项目练习 293 | 294 | - turtle 295 | - 鼠标响应事件 296 | - 键盘事件响应 297 | - 条件语句 298 | - 递归函数 299 | - 列表 300 | 301 | ## 项目参考代码 302 | 303 | ```python 304 | from turtle import * 305 | from math import ceil, floor 306 | from random import randint 307 | 308 | n = 10 309 | gz = 40 310 | bc = n * gz 311 | win = False 312 | dead = False 313 | can_start = True 314 | fx = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]] 315 | # 随机生成地雷数量 316 | booms = randint(n * n // 10, n * n // 2) 317 | d = [] 318 | m = [] 319 | c = [] 320 | b = [] 321 | 322 | t = Turtle() 323 | t.ht() 324 | t.up() 325 | t.speed(0) 326 | 327 | judge = Turtle() 328 | judge.ht() 329 | judge.up() 330 | judge.speed(0) 331 | 332 | 333 | # 画边框 334 | def draw(): 335 | t.clear() 336 | t.seth(0) 337 | t.color("black") 338 | t.goto(-bc / 2, bc / 2) 339 | for i in range(n + 1): 340 | t.down() 341 | t.fd(bc) 342 | t.bk(bc) 343 | t.up() 344 | t.goto(-bc / 2, bc / 2 - (i + 1) * gz) 345 | t.goto(-bc / 2, bc / 2) 346 | t.rt(90) 347 | for i in range(n + 1): 348 | t.down() 349 | t.fd(bc) 350 | t.bk(bc) 351 | t.up() 352 | t.goto(-bc / 2 + (i + 1) * gz, bc / 2) 353 | 354 | 355 | # 写地雷数 356 | def write_booms(): 357 | judge.clear() 358 | judge.goto(-gz, bc / 2 + gz - gz / 8) 359 | judge.color("red") 360 | judge.dot(20) 361 | judge.goto(0, bc / 2 + gz / 2) 362 | judge.write(": {}".format(booms), align="center", font=("Kai", 30, "bold")) 363 | 364 | 365 | # 初始化列表 366 | def init_list(n, default=0): 367 | lines = [] 368 | for i in range(n): 369 | line = [] 370 | for j in range(n): 371 | line.append(default) 372 | lines.append(line) 373 | return lines 374 | 375 | 376 | # 打印列表 377 | def print_list(lines): 378 | print() 379 | for line in lines: 380 | for item in line: 381 | print(item, end=' ') 382 | print() 383 | print() 384 | 385 | 386 | # x,y -> i, j 387 | def xytoij(x, y): 388 | ix = floor(x / gz) * gz 389 | iy = floor(y / gz) * gz 390 | j = (ix + bc / 2) / gz 391 | i = (bc / 2 - iy) / gz - 1 392 | return int(i), int(j) 393 | 394 | 395 | # i, j -> x, y 396 | def ijtoxy(i, j): 397 | x = -bc / 2 + gz / 2 + j * gz 398 | y = bc / 2 - gz / 2 - i * gz - gz / 4 399 | return x, y 400 | 401 | 402 | def set_color(booms): 403 | if booms <= 1: 404 | t.color("green") 405 | elif booms == 2: 406 | t.color("blue") 407 | elif booms == 3: 408 | t.color("brown") 409 | elif booms == 4: 410 | t.color("orange") 411 | elif booms == 5: 412 | t.color("red") 413 | elif booms >= 6: 414 | t.color("purple") 415 | 416 | 417 | def start(): 418 | global d, m, c, b, booms, can_start, win, dead 419 | if can_start: 420 | win = False 421 | dead = False 422 | can_start = False 423 | draw() 424 | # 地雷列表:0表示没雷,1表示有雷 425 | d = init_list(n) 426 | # 标记列表:0表示没雷,1表示有雷 427 | m = init_list(n) 428 | # 点击列表:0表示没点击,1表示点击 429 | c = init_list(n) 430 | # 计算得出地雷数量列表:-1表示地雷,其他数字表示周围有多少地雷 431 | b = init_list(n) 432 | booms = randint(n * n // 10, n * n // 2) 433 | # 随机生成地雷 434 | for k in range(booms): 435 | i = randint(0, n - 1) 436 | j = randint(0, n - 1) 437 | d[i][j] = 1 438 | 439 | write_booms() 440 | 441 | # 计算每个位置周围有多少雷,存放b列表 442 | for i in range(n): 443 | for j in range(n): 444 | if d[i][j] == 1: 445 | b[i][j] = -1 446 | for f in fx: 447 | ni = i + f[0] 448 | nj = j + f[1] 449 | if (ni >= 0 and ni < n and nj >= 0 and nj < n and b[ni][nj] != -1): 450 | b[ni][nj] += 1 451 | 452 | 453 | # 检查i, j周围8个方向(一圈),如果没有雷或者已经全部正确标记,则返回True 454 | def check_around(i, j): 455 | cnt = 0 456 | for f in fx: 457 | ni = i + f[0] 458 | nj = j + f[1] 459 | 460 | if (ni >= 0 and ni < n and nj >= 0 and nj < n): 461 | if d[ni][nj] == 1 and m[ni][nj] == 1: 462 | cnt += 1 463 | return b[i][j] == cnt 464 | 465 | 466 | # 如果i, j位置周围已经全部确认,则在i, j的8个方向上的下一个位置,递归再检查 467 | def check_and_auto_click(i, j): 468 | if (i >= 0 and i < n and j >= 0 and j < n and check_around(i, j)): 469 | for f in fx: 470 | ni = i + f[0] 471 | nj = j + f[1] 472 | if (ni >= 0 and ni < n and nj >= 0 and nj < n and b[ni][nj] != -1 and c[ni][nj] == 0): 473 | c[ni][nj] = 1 474 | check_and_auto_click(ni, nj) 475 | x, y = ijtoxy(ni, nj) 476 | t.goto(x, y) 477 | set_color(b[ni][nj]) 478 | t.write(b[ni][nj], align="center", font=("Arial", 20, "normal")) 479 | 480 | 481 | # 检查是否已经胜利 482 | def check_win(): 483 | for i in range(n): 484 | for j in range(n): 485 | if m[i][j] != d[i][j]: 486 | return False 487 | return True 488 | 489 | 490 | # 鼠标左键点击扫雪 491 | def click(x, y): 492 | global dead, win, can_start 493 | if not dead and not win: 494 | i, j = xytoij(x, y) 495 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 496 | c[i][j] = 1 497 | if d[i][j] == 1: 498 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 499 | t.color("red") 500 | t.dot(20) 501 | dead = True 502 | can_start = True 503 | judge.clear() 504 | judge.color("red") 505 | judge.write("失败,按空格键重新开始", align="center", font=("Kai", 40, "bold")) 506 | else: 507 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 4) 508 | set_color(b[i][j]) 509 | t.write(b[i][j], align="center", font=("Arial", 20, "normal")) 510 | check_and_auto_click(i, j) 511 | if check_win(): 512 | win = True 513 | can_start = True 514 | judge.clear() 515 | judge.color("green") 516 | judge.write("胜利,按空格键重新开始", align="center", font=("Kai", 40, "bold")) 517 | 518 | 519 | # 右键标记雷 520 | def mark(x, y): 521 | global booms, win, can_start 522 | if not dead and not win: 523 | i, j = xytoij(x, y) 524 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 525 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 526 | if m[i][j] == 0: 527 | m[i][j] = 1 528 | t.color("green") 529 | t.dot(20) 530 | booms -= 1 531 | else: 532 | m[i][j] = 0 533 | t.color("white") 534 | t.dot(22) 535 | booms += 1 536 | write_booms() 537 | if check_win(): 538 | win = True 539 | can_start = True 540 | judge.clear() 541 | judge.color("green") 542 | judge.write("胜利,按空格键重新开始", align="center", font=("Kai", 40, "bold")) 543 | 544 | 545 | start() 546 | screen = Screen() 547 | screen.onscreenclick(click, 1) 548 | screen.onscreenclick(mark, 2) 549 | screen.onkey(start, "space") 550 | screen.listen() 551 | done() 552 | 553 | ``` 554 | 555 | ## 测试运行 556 | 557 | 将代码保存为minesweeper.py,然后在控制台运行: 558 | 559 | ``` 560 | python minesweeper.py 561 | ``` 562 | 563 | ![挑战12](images/012_minesweeper.png) 564 | -------------------------------------------------------------------------------- /013_Posegame.md: -------------------------------------------------------------------------------- 1 | # 13 Pose game 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll open a Python window to play the pose game. 7 | 8 | ## What can we practice in this project? 9 | 10 | - Pygame 11 | - Pygame Zero lib 12 | - OpenCV 13 | - MediaPipe 14 | - numpy 15 | - Python while/for loop, if condition, list, etc. 16 | 17 | ## A reference code 18 | 19 | ```python 20 | import cv2 21 | import math 22 | import numpy as np 23 | import pgzrun 24 | import pygame 25 | from random import randint 26 | 27 | from pose_util import PoseDetector 28 | from utils import find_angle, is_touch 29 | 30 | pd = PoseDetector() 31 | 32 | camera = cv2.VideoCapture(0) 33 | camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) 34 | camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) 35 | 36 | WIDTH = 1280 37 | HEIGHT = 720 38 | TITLE = "Python体感游戏:守护家园" 39 | 40 | frame = None 41 | score = Actor("score", (80, 50)) 42 | score.score = 0 43 | covids = [] 44 | lasers = [] 45 | 46 | 47 | def generate_covid(): 48 | covid = Actor("covid", (WIDTH, randint(0, HEIGHT))) 49 | covid.bombed = False 50 | covid.i = 1 51 | covids.append(covid) 52 | clock.schedule(generate_covid, randint(1, 3)) 53 | 54 | 55 | def pose_detect(): 56 | global frame 57 | success, frame = camera.read() 58 | if success: 59 | frame = cv2.flip(frame, 1) 60 | pd.detect(frame, draw=False) 61 | angle = pd.get_angle(frame, 11, 13, 15, draw=False) 62 | if abs(angle) > 165 and abs(angle) < 190: 63 | x3, y3 = pd.positions[15][1], pd.positions[15][2] 64 | x2, y2 = pd.positions[13][1], pd.positions[13][2] 65 | x1, y1 = WIDTH, pd.positions[13][2] 66 | laser_angle = find_angle((x1, y1), (x2, y2), (x3, y3)) 67 | laser = Actor("laser", (pd.positions[15][1], pd.positions[15][2])) 68 | laser.angle = laser_angle 69 | sounds.pew.play() 70 | lasers.append(laser) 71 | 72 | 73 | def update_covids(): 74 | for covid in covids: 75 | if covid.bombed == False and is_touch(covid, lasers): 76 | covid.bombed = True 77 | sounds.explode.play() 78 | score.score += 1 79 | if covid.bombed: 80 | if covid.i > 25: 81 | covid.i = 25 82 | covids.remove(covid) 83 | covid.image = "b_" + str(covid.i) 84 | covid.i += 1 85 | covid.x -= 1 86 | 87 | 88 | def update_lasers(): 89 | for laser in lasers: 90 | rad = math.radians(laser.angle) 91 | dx = 50 * math.cos(rad) 92 | dy = 50 * math.sin(rad) 93 | laser.x += dx 94 | laser.y -= dy 95 | 96 | 97 | def update(): 98 | pose_detect() 99 | update_covids() 100 | update_lasers() 101 | 102 | 103 | def draw(): 104 | global frame 105 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 106 | frame = np.rot90(frame) 107 | frame = cv2.flip(frame, 0) 108 | frame = pygame.surfarray.make_surface(frame) 109 | screen.blit(frame, (0, 0)) 110 | for covid in covids: 111 | covid.draw() 112 | for laser in lasers: 113 | laser.draw() 114 | score.draw() 115 | screen.draw.text(str(score.score), (150, 20), fontsize=100, color="white") 116 | 117 | 118 | generate_covid() 119 | 120 | pgzrun.go() 121 | 122 | ``` 123 | 124 | ## Run the demo 125 | 126 | Please save the Python as game.py and run it in console: 127 | 128 | ``` 129 | python game.py 130 | ``` 131 | 132 | ![挑战13](images/013_posegame.png) 133 | 134 | ---- 135 | 136 | # 体感游戏 137 | 138 | ## 项目需求 139 | 140 | - 直接在控制台使用命令行运行 141 | - 运行之后出现体感小游戏 142 | 143 | ## 项目练习 144 | 145 | - Pygame 146 | - Pygame Zero lib 147 | - OpenCV 148 | - MediaPipe 149 | - numpy 150 | - Python while/for loop, if condition, list, etc. 151 | 152 | ## 项目参考代码 153 | 154 | - game.py 主程序 155 | - pose_util.py 人体姿势识别模块 156 | - utils.py 工具模块 157 | - video.py 测试安装代码 158 | 159 | ## 测试运行 160 | 161 | 将代码保存为game.py,然后在控制台运行: 162 | 163 | ``` 164 | python game.py 165 | ``` 166 | 167 | ![挑战13](images/013_posegame.png) 168 | -------------------------------------------------------------------------------- /014_Tetris.md: -------------------------------------------------------------------------------- 1 | # 14 Tetris 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll open a Python window to play the Tetris game. 7 | 8 | ## What can we practice in this project? 9 | 10 | - Turtle 11 | - Class/Object 12 | - 2D list 13 | 14 | ## A reference code 15 | 16 | ```python 17 | from turtle import * 18 | from random import randint, choice 19 | 20 | SHAPES = [ 21 | [[1, 1, 1, 1]], 22 | 23 | [[1], 24 | [1], 25 | [1], 26 | [1]], 27 | 28 | [[0, 0, 1], 29 | [1, 1, 1]], 30 | 31 | [[1, 0, 0], 32 | [1, 1, 1]], 33 | 34 | [[0, 1, 1], 35 | [1, 1, 0]], 36 | 37 | [[1, 1, 0], 38 | [0, 1, 1]], 39 | 40 | [[1, 1], 41 | [1, 1]], 42 | 43 | [[0, 1, 0], 44 | [1, 1, 1]] 45 | ] 46 | 47 | 48 | class Block(): 49 | def __init__(self, grid): 50 | """ 51 | 初始化 52 | :param grid: 游戏grid 53 | """ 54 | self.grid = grid 55 | self.color = randint(1, 7) 56 | self.shape = choice(SHAPES) 57 | self.i = 0 58 | self.j = 5 59 | self.width = len(self.shape[0]) 60 | self.height = len(self.shape) 61 | 62 | def fill(self): 63 | """ 64 | 将方块数据填充到grid中 65 | """ 66 | for i in range(self.height): 67 | for j in range(self.width): 68 | if self.shape[i][j] == 1: 69 | self.grid[self.i + i][self.j + j] = self.color 70 | 71 | def erase(self): 72 | """ 73 | 从grid中擦除方块 74 | """ 75 | for i in range(self.height): 76 | for j in range(self.width): 77 | if self.shape[i][j] == 1: 78 | self.grid[self.i + i][self.j + j] = 0 79 | 80 | def move_left(self): 81 | """ 82 | 向左移动一格 83 | """ 84 | if self.j > 0: 85 | for row in range(self.height): 86 | for col in range(self.width): 87 | if self.shape[row][col] == 1: 88 | if self.grid[self.i + row][self.j + col - 1] != 0: 89 | return False 90 | break 91 | 92 | self.erase() 93 | self.j -= 1 94 | self.fill() 95 | 96 | def move_right(self): 97 | """ 98 | 向右移动一格 99 | """ 100 | if self.j + self.width < len(self.grid[0]): 101 | for row in range(self.height): 102 | for col in range(self.width - 1, -1, -1): 103 | if self.shape[row][col] == 1: 104 | if self.grid[self.i + row][self.j + col + 1] != 0: 105 | return False 106 | break 107 | 108 | self.erase() 109 | self.j += 1 110 | self.fill() 111 | 112 | def move_down(self): 113 | """ 114 | 快速下移 115 | """ 116 | i = self.i 117 | while self.check_down(i): 118 | i += 1 119 | self.erase() 120 | self.i = i 121 | self.fill() 122 | 123 | def check_down(self, i): 124 | """ 125 | 判断方块在i行时是否可以下落 126 | """ 127 | if i + self.height >= len(self.grid): 128 | return False 129 | for col in range(self.width): 130 | for row in range(self.height - 1, -1, -1): 131 | if self.shape[row][col] == 1: 132 | if self.grid[i + row + 1][self.j + col] != 0: 133 | return False 134 | break 135 | return True 136 | 137 | def can_fall(self): 138 | """ 139 | 判断方块是否可以下落 140 | """ 141 | return self.check_down(self.i) 142 | 143 | def rotate(self): 144 | """ 145 | 旋转 146 | """ 147 | rotated = [] 148 | for j in range(len(self.shape[0])): 149 | new_row = [] 150 | for i in range(len(self.shape) - 1, -1, -1): 151 | new_row.append(self.shape[i][j]) 152 | rotated.append(new_row) 153 | 154 | for i in range(len(rotated)): 155 | for j in range(len(rotated[0])): 156 | if rotated[i][j] == 1: 157 | # 如果旋转后,有任何位置超过边界,则不能旋转 158 | if self.i + i >= len(self.grid) or self.j + j >= len(self.grid[0]): 159 | return 160 | # 如果旋转后的位置有方块了,则不能旋转 161 | if self.grid[self.i + i][self.j + j] != 0 and (i not in range(len(self.shape)) or j not in range( 162 | len(self.shape[0]))): 163 | return 164 | self.erase() 165 | self.shape = rotated 166 | self.height = len(self.shape) 167 | self.width = len(self.shape[0]) 168 | self.fill() 169 | 170 | 171 | gz = 32 172 | WIDTH = 12 173 | HEIGHT = 24 174 | COLORS = ("black", "red", "orange", "yellow", "green", "cyan", "blue", "purple") 175 | 176 | grid = [[0 for col in range(WIDTH)] for row in range(HEIGHT)] 177 | 178 | title("Tetris 俄罗斯方块") 179 | bgcolor("lightgreen") 180 | shapesize(1.5) 181 | tracer(False) 182 | speed(0) 183 | shape("square") 184 | up() 185 | 186 | score = 0 187 | score_pen = Turtle() 188 | score_pen.ht() 189 | score_pen.up() 190 | score_pen.goto(0, HEIGHT / 2 * gz) 191 | score_pen.down() 192 | score_pen.write("分数:{}".format(score), font=("", 20, ""), align="center") 193 | 194 | block_pen = Turtle() 195 | block_pen.speed(0) 196 | block_pen.shapesize(1.5) 197 | block_pen.shape("square") 198 | block_pen.up() 199 | block_pen.ht() 200 | 201 | 202 | def draw_next_block(block): 203 | block_pen.clear() 204 | block_pen.color(COLORS[block.color]) 205 | for i in range(len(block.shape)): 206 | for j in range(len(block.shape[0])): 207 | if block.shape[i][j] == 1: 208 | block_pen.goto(WIDTH / 2 * gz + 50 + j * gz, HEIGHT / 2 * gz - 50 - i * gz) 209 | block_pen.stamp() 210 | 211 | 212 | def draw_grid(): 213 | clear() 214 | for row in range(len(grid)): 215 | for col in range(len(grid[row])): 216 | goto(-WIDTH / 2 * gz + col * gz, HEIGHT / 2 * gz - row * gz - 20) 217 | color(COLORS[grid[row][col]]) 218 | stamp() 219 | 220 | 221 | def check_grid(): 222 | """ 223 | 检查是否要消除满格的行 224 | """ 225 | global score 226 | for i in range(HEIGHT): 227 | is_full = True 228 | for j in range(WIDTH): 229 | if grid[i][j] == 0: 230 | is_full = False 231 | break 232 | if is_full: 233 | score += 10 234 | score_pen.clear() 235 | score_pen.write("分数:{}".format(score), font=("", 20, ""), align="center") 236 | grid.pop(i) 237 | grid.insert(0, [0 for x in range(WIDTH)]) 238 | 239 | 240 | blocks = [] 241 | block1 = Block(grid) 242 | block2 = Block(grid) 243 | blocks.append(block1) 244 | blocks.append(block2) 245 | draw_next_block(block2) 246 | 247 | 248 | def left(): 249 | blocks[0].move_left() 250 | 251 | 252 | def right(): 253 | blocks[0].move_right() 254 | 255 | 256 | def down(): 257 | blocks[0].move_down() 258 | 259 | 260 | def rotate(): 261 | blocks[0].rotate() 262 | 263 | 264 | onkey(left, "Left") 265 | onkey(right, "Right") 266 | onkey(rotate, "Up") 267 | onkey(down, "Down") 268 | listen() 269 | 270 | 271 | def run(): 272 | b = blocks[0] 273 | if b.can_fall(): 274 | b.erase() 275 | b.i += 1 276 | b.fill() 277 | else: 278 | if b.i == 0: 279 | b.fill() 280 | draw_grid() 281 | goto(0, 0) 282 | color("white") 283 | write("游戏结束", font=("", 50, ""), align="center") 284 | return 285 | check_grid() 286 | blocks.pop(0) 287 | block = Block(grid) 288 | blocks.append(block) 289 | draw_next_block(blocks[1]) 290 | 291 | draw_grid() 292 | update() 293 | ontimer(run, 400) 294 | 295 | 296 | run() 297 | done() 298 | 299 | 300 | ``` 301 | 302 | ## Run the demo 303 | 304 | Please save the Python as game.py and run it in console: 305 | 306 | ``` 307 | python game.py 308 | ``` 309 | 310 | ![挑战14](images/tetris.png) 311 | 312 | ---- 313 | 314 | # 俄罗斯方块 315 | 316 | ## 项目需求 317 | 318 | - 直接在控制台使用命令行运行 319 | - 运行之后出现俄罗斯方块小游戏 320 | 321 | ## 项目练习 322 | 323 | - Turtle 324 | - Class/Object 325 | - 2D list 326 | 327 | ## 项目参考代码 328 | 329 | ## 测试运行 330 | 331 | 将代码保存为game.py,然后在控制台运行: 332 | 333 | ``` 334 | python game.py 335 | ``` 336 | 337 | ![挑战14](images/tetris.png) 338 | -------------------------------------------------------------------------------- /015_2048.md: -------------------------------------------------------------------------------- 1 | # 15 2048 2 | 3 | ## Requirements 4 | 5 | 1. Run the code in console using command line. 6 | 2. It'll open a Python window to play the 2048 game. 7 | 8 | ## What can we practice in this project? 9 | 10 | - Turtle 11 | - 2D List 12 | 13 | ## A reference code 14 | 15 | ```python 16 | from turtle import * 17 | from random import randint 18 | 19 | title("2048") 20 | gz = 176 # shapesize=8是连长160的正方形,我们可以将格子设置为162,这边就可以画出边框线 21 | N = 4 22 | bc = gz * N # 边长 23 | tracer(False) # 不显示绘制动画 24 | bgcolor("gray") 25 | ht() 26 | up() 27 | speed(0) 28 | shape("square") 29 | shapesize(8) # shapesize为8是一个连长为160的正方形 30 | 31 | # 二维列表对应游戏表格 32 | grid = [ 33 | [0, 0, 0, 0], 34 | [0, 0, 0, 0], 35 | [0, 0, 0, 0], 36 | [0, 0, 0, 0] 37 | ] 38 | 39 | maxx = 2 40 | steps = 0 41 | tj = Turtle() 42 | tj.speed(0) 43 | tj.up() 44 | tj.ht() 45 | tj.color("white") 46 | tj.goto(-bc / 2, bc / 2 + 20) 47 | tj.write("步数:{},最大值:{}".format(steps, maxx), font=("", 20, "")) 48 | 49 | # 颜色字典 50 | COLORS = { 51 | 0: "white", 52 | 2: "yellow", 53 | 4: "orange", 54 | 8: "pink", 55 | 16: "red", 56 | 32: "lightblue", 57 | 64: "lightgreen", 58 | 128: "green", 59 | 256: "purple", 60 | 512: "cyan", 61 | 1024: "silver", 62 | 2048: "gold" 63 | } 64 | 65 | 66 | # 绘制二维列表 67 | def draw_grid(): 68 | global steps 69 | global maxx 70 | tj.clear() 71 | tj.write("步数:{},最大值:{}".format(steps, maxx), font=("", 20, "")) 72 | steps += 1 73 | clear() 74 | for row in range(N): 75 | for col in range(N): 76 | # 从左上角(-bc/2 + gz/2, bc/2 - gz/2)开始从上往下、从左往右绘制 77 | goto(-bc / 2 + gz / 2 + col * gz, bc / 2 - gz / 2 - row * gz) 78 | # 根据grid[row][col]的数字,来设置对应的颜色 79 | color(COLORS[grid[row][col]]) 80 | stamp() 81 | # 在单元格中写下对应的数字 82 | sety(bc / 2 - gz / 2 - row * gz - 30) 83 | color("black") 84 | if grid[row][col] > 0: 85 | write(grid[row][col], font=("", 50, ""), align="center") 86 | # 找最大值 87 | if grid[row][col] > maxx: 88 | maxx = grid[row][col] 89 | # 刷新游戏画面 90 | update() 91 | if maxx == 2048: 92 | goto(0, 0) 93 | color("red") 94 | write("游戏胜利", font=("", 100, ""), align="center") 95 | 96 | 97 | def can_add(): 98 | for i in range(N): 99 | for j in range(N): 100 | if grid[i][j] == 0: 101 | return True 102 | return False 103 | 104 | 105 | def generate_random(): 106 | # 如果能加 107 | if can_add(): 108 | added = False 109 | # 随机选择一个空白位置,将这个位置数字设置为2 110 | while not added: 111 | i = randint(0, N - 1) 112 | j = randint(0, N - 1) 113 | if grid[i][j] == 0: 114 | grid[i][j] = 2 115 | added = True 116 | 117 | 118 | generate_random() 119 | draw_grid() 120 | 121 | 122 | def up(): 123 | # 每列 124 | for col in range(N): 125 | # 从第2行到最后一行 126 | for row in range(1, N): 127 | # 记下这个格子的数字 128 | value = grid[row][col] 129 | r = row 130 | # 找到最上面为0的格子r 131 | while r > 0 and grid[r - 1][col] == 0: 132 | r = r - 1 133 | # 如果r-1存在并且其中的数字和row数字一样,则将r变为r-1 134 | if r - 1 >= 0 and grid[r - 1][col] == value: 135 | r = r - 1 136 | # 如果r不等于原来的row,2者合并(此时r位置数字为0或者和row相等) 137 | if r != row: 138 | grid[r][col] += value 139 | grid[row][col] = 0 # 原来row的数字要变为0 140 | 141 | # 随机生成2 142 | generate_random() 143 | # 重新绘制格子 144 | draw_grid() 145 | 146 | 147 | def down(): 148 | for col in range(N): 149 | for row in range(N - 2, -1, -1): 150 | value = grid[row][col] 151 | r = row 152 | while r < N - 1 and grid[r + 1][col] == 0: 153 | r = r + 1 154 | if r + 1 < N and grid[r + 1][col] == value: 155 | r = r + 1 156 | if r != row: 157 | grid[r][col] += value 158 | grid[row][col] = 0 159 | generate_random() 160 | draw_grid() 161 | 162 | 163 | def left(): 164 | for row in range(N): 165 | for col in range(1, N): 166 | value = grid[row][col] 167 | c = col 168 | while c > 0 and grid[row][c - 1] == 0: 169 | c = c - 1 170 | if c - 1 >= 0 and grid[row][c - 1] == value: 171 | c = c - 1 172 | if c != col: 173 | grid[row][c] += value 174 | grid[row][col] = 0 175 | generate_random() 176 | draw_grid() 177 | 178 | 179 | def right(): 180 | for row in range(N): 181 | for col in range(N - 2, -1, -1): 182 | value = grid[row][col] 183 | c = col 184 | while c < N - 1 and grid[row][c + 1] == 0: 185 | c = c + 1 186 | if c + 1 < N and grid[row][c + 1] == value: 187 | c = c + 1 188 | if c != col: 189 | grid[row][c] += value 190 | grid[row][col] = 0 191 | generate_random() 192 | draw_grid() 193 | 194 | 195 | onkeypress(up, "Up") # 按向上键("Up"),执行up响应函数 196 | onkeypress(down, "Down") # 按向下键("Down"),执行down响应函数 197 | onkeypress(left, "Left") # 按向上键("Left"),执行left响应函数 198 | onkeypress(right, "Right") # 按向上键("Right"),执行right响应函数 199 | listen() # 开始监听 200 | 201 | DONE() 202 | 203 | ``` 204 | 205 | ## Run the demo 206 | 207 | Please save the Python as game.py and run it in console: 208 | 209 | ``` 210 | python game.py 211 | ``` 212 | 213 | ![挑战15](images/2048.png) 214 | 215 | ---- 216 | 217 | # 2048 218 | 219 | ## 项目需求 220 | 221 | - 直接在控制台使用命令行运行 222 | - 运行之后出现2048小游戏 223 | 224 | ## 项目练习 225 | 226 | - Turtle 227 | - Class/Object 228 | 229 | ## 项目参考代码 230 | 231 | ## 测试运行 232 | 233 | 将代码保存为game.py,然后在控制台运行: 234 | 235 | ``` 236 | python game.py 237 | ``` 238 | 239 | ![挑战15](images/2048.png) 240 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 100+ Python Projects Challenge 2 | 3 | ## 001 1 minute math 4 | 5 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/001_1_minute_math.md 6 | 7 | ## 002 Chinese English Translation 8 | 9 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/002_English_Chinese_Translation.md 10 | 11 | ## 003 Add text watermark on pictures 12 | 13 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/003_Add_text_watermark_on_pictures.md 14 | 15 | ## 004 Check your English speech 16 | 17 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/004_Check_your_English_speech.md 18 | 19 | ## 005 Check your English speech using baidu ai cloud ASR service 20 | 21 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/005_Check_your_English_speech_baidu.md 22 | 23 | ## 006 Arithmetic Formatter 24 | 25 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/006_Arithmetic_Formatter.md 26 | 27 | ## 007 OpenCV Capture Camera Video 28 | 29 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/007_OpenCV_Capture_Camera_Video.md 30 | 31 | ## 008 OpenCV MediaPipe Hands Detection 32 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/008_OpenCV_MediaPipe_hand_detection.md 33 | 34 | ## 009 OpenCV MediaPipe Hands Fingers Count 35 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/009_OpenCV_MediaPipe_hands_fingers_count.md 36 | 37 | ## 010 Gobang game 38 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/010_gobang.md 39 | 40 | ## 011 Snake game 41 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/011_snake_game.md 42 | 43 | ## 012 Minesweeper game 44 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/012_Minesweeper.md 45 | 46 | ## 013 Pose game 47 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/013_Posegame.md 48 | 49 | ## 014 Tetris game 50 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/014_Tetris.md 51 | 52 | ## 015 2048 game 53 | https://github.com/zhiwehu/100_plus_Python_Projects_Challenge/blob/main/015_2048.md 54 | -------------------------------------------------------------------------------- /code/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/.DS_Store -------------------------------------------------------------------------------- /code/1/1.py: -------------------------------------------------------------------------------- 1 | import time 2 | import random 3 | 4 | 5 | def get_divisor(n): 6 | ''' 7 | Get a random divisor of n. 8 | :param n: The number 9 | :return: a divisor of n 10 | ''' 11 | l = [] 12 | for i in range(1, n + 1): 13 | if n % i == 0: 14 | l.append(i) 15 | return random.choice(l) 16 | 17 | 18 | if __name__ == '__main__': 19 | ops = ['+', '-', '*', '/'] 20 | start_time = time.time() 21 | total = 0 22 | correct = 0 23 | questions = [] 24 | # while seconds is less than 60 25 | while time.time() - start_time <= 60: 26 | a = random.randint(1, 99) 27 | op = random.choice(ops) 28 | if op == '/': 29 | # if op is '/' then b is a divisor of a 30 | b = get_divisor(a) 31 | else: 32 | b = random.randint(1, 99) 33 | # Get the correct answer 34 | a_op_b = '{}{}{}'.format(a, op, b) 35 | c = int(eval(a_op_b)) 36 | 37 | # Let user input answer 38 | try: 39 | ans = int(input('{} = '.format(a_op_b))) 40 | except: 41 | ans = '' 42 | 43 | # To check if correct or not 44 | if time.time() - start_time <= 60: 45 | if c == ans: 46 | print('Correct! Time remain {} seconds.'.format(int(60 - (time.time() - start_time)))) 47 | correct = correct + 1 48 | else: 49 | print('Wrong answer! Time remain {} seconds.'.format(int(60 - (time.time() - start_time)))) 50 | total = total + 1 51 | questions.append('{}={}'.format(a_op_b, ans)) 52 | 53 | print('{} questions and your correct rate is {:.2f}%'.format(total, correct / total * 100)) 54 | for q in questions: 55 | print(q) 56 | -------------------------------------------------------------------------------- /code/10/gobang.py: -------------------------------------------------------------------------------- 1 | from turtle import * 2 | 3 | win = False 4 | 5 | speed(0) 6 | bgcolor("lightgreen") 7 | yanse="black" 8 | gz=40 9 | 10 | judge = Turtle() 11 | judge.up() 12 | judge.goto(-460, 330) 13 | judge.write("Next", font=("Arial", 40, "bold")) 14 | judge.color(yanse) 15 | judge.goto(-420, 300) 16 | judge.dot(30) 17 | 18 | for i in range(19): 19 | up() 20 | goto(-gz*9, gz*(9-i)) 21 | down() 22 | fd(gz*18) 23 | bk(gz*18) 24 | 25 | rt(90) 26 | 27 | for i in range(19): 28 | up() 29 | goto(-gz*(9-i), gz*9) 30 | down() 31 | fd(gz*18) 32 | bk(gz*18) 33 | 34 | pensize(5) 35 | for i in range(4): 36 | fd(gz*18) 37 | rt(90) 38 | 39 | # m = [[0] * 19 for i in range(19)] 40 | m =[ 41 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 42 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 43 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 44 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 45 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 46 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 47 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 48 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 49 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 50 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 51 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 52 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 53 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 54 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 55 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 56 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 57 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 58 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 59 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 60 | ] 61 | 62 | def check(i, j): 63 | global win 64 | g = [0] * 8 65 | fw = ((0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1)) 66 | for index in range(8): 67 | d = fw[index] 68 | next_i = i + d[0] 69 | next_j = j + d[1] 70 | while next_i in range(19) and next_j in range(19) and m[next_i][next_j] == m[i][j]: 71 | g[index] = g[index] + 1 72 | next_i = next_i + d[0] 73 | next_j = next_j + d[1] 74 | 75 | for index in range(4): 76 | if g[index] + g[index + 4] + 1 >= 5: 77 | win = True 78 | goto(0, 0) 79 | if yanse == "black": 80 | write('Black Win', font=('Arial', 100, ''), align='center') 81 | else: 82 | write('White Win', font=('Arial', 100, ''), align='center') 83 | break 84 | 85 | def play(x, y): 86 | if not win: 87 | global yanse 88 | global gz 89 | color(yanse) 90 | up() 91 | x = round(x/gz)*gz 92 | y = round(y/gz)*gz 93 | i = int(9 - y / gz) 94 | j = int(x / gz + 9) 95 | 96 | if i >= 0 and i <= 18 and j >=0 and j<=18: 97 | if m[i][j] == 0: 98 | goto(x, y) 99 | dot(30) 100 | 101 | if yanse == "black": 102 | m[i][j] = 1 103 | check(i, j) 104 | yanse="white" 105 | else: 106 | m[i][j] = 2 107 | check(i, j) 108 | yanse="black" 109 | 110 | judge.color(yanse) 111 | judge.dot(30) 112 | 113 | onscreenclick(play, 1) 114 | done() -------------------------------------------------------------------------------- /code/11/snake.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/11/snake.py -------------------------------------------------------------------------------- /code/12/minesweeper.py: -------------------------------------------------------------------------------- 1 | from turtle import * 2 | from math import floor 3 | from random import randint 4 | 5 | n = 10 6 | gz = 40 7 | bc = n * gz 8 | win = False 9 | dead = False 10 | can_start = True 11 | fx = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]] 12 | # random Mines count 13 | booms = randint(n * n // 10, n * n // 2) 14 | d = [] 15 | m = [] 16 | c = [] 17 | b = [] 18 | 19 | t = Turtle() 20 | t.ht() 21 | t.up() 22 | t.speed(0) 23 | 24 | judge = Turtle() 25 | judge.ht() 26 | judge.up() 27 | judge.speed(0) 28 | 29 | 30 | # draw 31 | def draw(): 32 | t.clear() 33 | t.seth(0) 34 | t.color("black") 35 | t.goto(-bc / 2, bc / 2) 36 | for i in range(n + 1): 37 | t.down() 38 | t.fd(bc) 39 | t.bk(bc) 40 | t.up() 41 | t.goto(-bc / 2, bc / 2 - (i + 1) * gz) 42 | t.goto(-bc / 2, bc / 2) 43 | t.rt(90) 44 | for i in range(n + 1): 45 | t.down() 46 | t.fd(bc) 47 | t.bk(bc) 48 | t.up() 49 | t.goto(-bc / 2 + (i + 1) * gz, bc / 2) 50 | 51 | 52 | # write the booms count 53 | def write_booms(): 54 | judge.clear() 55 | judge.goto(-gz, bc / 2 + gz - gz / 8) 56 | judge.color("red") 57 | judge.dot(20) 58 | judge.goto(0, bc / 2 + gz / 2) 59 | judge.write(": {}".format(booms), align="center", font=("Kai", 30, "bold")) 60 | 61 | 62 | # init list method 63 | def init_list(n, default=0): 64 | lines = [] 65 | for i in range(n): 66 | line = [] 67 | for j in range(n): 68 | line.append(default) 69 | lines.append(line) 70 | return lines 71 | 72 | 73 | # print list for debug useage 74 | def print_list(lines): 75 | print() 76 | for line in lines: 77 | for item in line: 78 | print(item, end=' ') 79 | print() 80 | print() 81 | 82 | 83 | # x,y -> i, j 84 | def xytoij(x, y): 85 | ix = floor(x / gz) * gz 86 | iy = floor(y / gz) * gz 87 | j = (ix + bc / 2) / gz 88 | i = (bc / 2 - iy) / gz - 1 89 | return int(i), int(j) 90 | 91 | 92 | # i, j -> x, y 93 | def ijtoxy(i, j): 94 | x = -bc / 2 + gz / 2 + j * gz 95 | y = bc / 2 - gz / 2 - i * gz - gz / 4 96 | return x, y 97 | 98 | 99 | # set color base booms count 100 | def set_color(booms): 101 | if booms <= 1: 102 | t.color("green") 103 | elif booms == 2: 104 | t.color("blue") 105 | elif booms == 3: 106 | t.color("brown") 107 | elif booms == 4: 108 | t.color("orange") 109 | elif booms == 5: 110 | t.color("red") 111 | elif booms >= 6: 112 | t.color("purple") 113 | 114 | 115 | # start game 116 | def start(): 117 | global d, m, c, b, booms, can_start, win, dead 118 | if can_start: 119 | win = False 120 | dead = False 121 | can_start = False 122 | draw() 123 | # 0 not boom, 1 boom 124 | d = init_list(n) 125 | # 0 not mark, 1 markd 126 | m = init_list(n) 127 | # 0 not click, 1 clicked 128 | c = init_list(n) 129 | # count how many booms around 130 | b = init_list(n) 131 | booms = randint(n * n // 10, n * n // 2) 132 | # random boom count 133 | for k in range(booms): 134 | i = randint(0, n - 1) 135 | j = randint(0, n - 1) 136 | d[i][j] = 1 137 | 138 | write_booms() 139 | 140 | # count around booms (-1 means boom) 141 | for i in range(n): 142 | for j in range(n): 143 | if d[i][j] == 1: 144 | b[i][j] = -1 145 | for f in fx: 146 | ni = i + f[0] 147 | nj = j + f[1] 148 | if (ni >= 0 and ni < n and ni >= 0 and nj < n and b[ni][nj] != -1): 149 | b[ni][nj] += 1 150 | 151 | 152 | # check i, j around 153 | def check_around(i, j): 154 | cnt = 0 155 | for f in fx: 156 | ni = i + f[0] 157 | nj = j + f[1] 158 | 159 | if (ni >= 0 and ni < n and nj >= 0 and nj < n): 160 | if d[ni][nj] == 1 and m[ni][nj] == 1: 161 | cnt += 1 162 | return b[i][j] == cnt 163 | 164 | 165 | # check 8 directions of i, j and do the recursion 166 | def check_and_auto_click(i, j): 167 | if (i >= 0 and i < n and j >= 0 and j < n and check_around(i, j)): 168 | for f in fx: 169 | ni = i + f[0] 170 | nj = j + f[1] 171 | if (ni >= 0 and ni < n and nj >= 0 and nj < n and b[ni][nj] != -1 and c[ni][nj] == 0): 172 | c[ni][nj] = 1 173 | check_and_auto_click(ni, nj) 174 | x, y = ijtoxy(ni, nj) 175 | t.goto(x, y) 176 | set_color(b[ni][nj]) 177 | t.write(b[ni][nj], align="center", font=("Arial", 20, "normal")) 178 | 179 | 180 | # check if win 181 | def check_win(): 182 | for i in range(n): 183 | for j in range(n): 184 | if m[i][j] != d[i][j]: 185 | return False 186 | return True 187 | 188 | 189 | # left mouse click 190 | def click(x, y): 191 | global dead, win, can_start 192 | if not dead and not win: 193 | i, j = xytoij(x, y) 194 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 195 | c[i][j] = 1 196 | if d[i][j] == 1: 197 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 198 | t.color("red") 199 | t.dot(20) 200 | dead = True 201 | can_start = True 202 | judge.clear() 203 | judge.color("red") 204 | judge.write("Failed, press Sapce to restart.", align="center", font=("Kai", 40, "bold")) 205 | else: 206 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 4) 207 | set_color(b[i][j]) 208 | t.write(b[i][j], align="center", font=("Arial", 20, "normal")) 209 | check_and_auto_click(i, j) 210 | if check_win(): 211 | win = True 212 | can_start = True 213 | judge.clear() 214 | judge.color("green") 215 | judge.write("Success, press Sapce to restart.", align="center", font=("Kai", 40, "bold")) 216 | 217 | 218 | # mouse right click to mark 219 | def mark(x, y): 220 | global booms, win, can_start 221 | if not dead and not win: 222 | i, j = xytoij(x, y) 223 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 224 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 225 | if m[i][j] == 0: 226 | m[i][j] = 1 227 | t.color("green") 228 | t.dot(20) 229 | booms -= 1 230 | else: 231 | m[i][j] = 0 232 | t.color("white") 233 | t.dot(22) 234 | booms += 1 235 | write_booms() 236 | if check_win(): 237 | win = True 238 | can_start = True 239 | judge.clear() 240 | judge.color("green") 241 | judge.write("Success, press Sapce to restart.", align="center", font=("Kai", 40, "bold")) 242 | 243 | start() 244 | screen = Screen() 245 | screen.onscreenclick(click, 1) 246 | screen.onscreenclick(mark, 2) 247 | screen.onkey(start, "space") 248 | screen.listen() 249 | done() -------------------------------------------------------------------------------- /code/13/game.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import math 3 | import numpy as np 4 | import pgzrun 5 | import pygame 6 | from random import randint 7 | 8 | from pose_util import PoseDetector 9 | from utils import find_angle, is_touch 10 | 11 | pd = PoseDetector() 12 | 13 | camera = cv2.VideoCapture(0) 14 | camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) 15 | camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) 16 | 17 | WIDTH = 1280 18 | HEIGHT = 720 19 | TITLE = "Python体感游戏:守护家园" 20 | 21 | frame = None 22 | score = Actor("score", (80, 50)) 23 | score.score = 0 24 | covids = [] 25 | lasers = [] 26 | 27 | 28 | def generate_covid(): 29 | covid = Actor("covid", (WIDTH, randint(0, HEIGHT))) 30 | covid.bombed = False 31 | covid.i = 1 32 | covids.append(covid) 33 | clock.schedule(generate_covid, randint(1, 3)) 34 | 35 | 36 | def pose_detect(): 37 | global frame 38 | success, frame = camera.read() 39 | if success: 40 | frame = cv2.flip(frame, 1) 41 | pd.detect(frame, draw=False) 42 | angle = pd.get_angle(frame, 11, 13, 15, draw=False) 43 | if abs(angle) > 165 and abs(angle) < 190: 44 | x3, y3 = pd.positions[15][1], pd.positions[15][2] 45 | x2, y2 = pd.positions[13][1], pd.positions[13][2] 46 | x1, y1 = WIDTH, pd.positions[13][2] 47 | laser_angle = find_angle((x1, y1), (x2, y2), (x3, y3)) 48 | laser = Actor("laser", (pd.positions[15][1], pd.positions[15][2])) 49 | laser.angle = laser_angle 50 | sounds.pew.play() 51 | lasers.append(laser) 52 | 53 | 54 | def update_covids(): 55 | for covid in covids: 56 | if covid.bombed == False and is_touch(covid, lasers): 57 | covid.bombed = True 58 | sounds.explode.play() 59 | score.score += 1 60 | if covid.bombed: 61 | if covid.i > 25: 62 | covid.i = 25 63 | covids.remove(covid) 64 | covid.image = "b_" + str(covid.i) 65 | covid.i += 1 66 | covid.x -= 1 67 | 68 | 69 | def update_lasers(): 70 | for laser in lasers: 71 | rad = math.radians(laser.angle) 72 | dx = 50 * math.cos(rad) 73 | dy = 50 * math.sin(rad) 74 | laser.x += dx 75 | laser.y -= dy 76 | 77 | 78 | def update(): 79 | pose_detect() 80 | update_covids() 81 | update_lasers() 82 | 83 | 84 | def draw(): 85 | global frame 86 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 87 | frame = np.rot90(frame) 88 | frame = cv2.flip(frame, 0) 89 | frame = pygame.surfarray.make_surface(frame) 90 | screen.blit(frame, (0, 0)) 91 | for covid in covids: 92 | covid.draw() 93 | for laser in lasers: 94 | laser.draw() 95 | score.draw() 96 | screen.draw.text(str(score.score), (150, 20), fontsize=100, color="white") 97 | 98 | 99 | generate_covid() 100 | 101 | pgzrun.go() 102 | -------------------------------------------------------------------------------- /code/13/images/b_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_1.png -------------------------------------------------------------------------------- /code/13/images/b_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_10.png -------------------------------------------------------------------------------- /code/13/images/b_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_11.png -------------------------------------------------------------------------------- /code/13/images/b_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_12.png -------------------------------------------------------------------------------- /code/13/images/b_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_13.png -------------------------------------------------------------------------------- /code/13/images/b_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_14.png -------------------------------------------------------------------------------- /code/13/images/b_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_15.png -------------------------------------------------------------------------------- /code/13/images/b_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_16.png -------------------------------------------------------------------------------- /code/13/images/b_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_17.png -------------------------------------------------------------------------------- /code/13/images/b_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_18.png -------------------------------------------------------------------------------- /code/13/images/b_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_19.png -------------------------------------------------------------------------------- /code/13/images/b_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_2.png -------------------------------------------------------------------------------- /code/13/images/b_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_20.png -------------------------------------------------------------------------------- /code/13/images/b_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_21.png -------------------------------------------------------------------------------- /code/13/images/b_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_22.png -------------------------------------------------------------------------------- /code/13/images/b_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_23.png -------------------------------------------------------------------------------- /code/13/images/b_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_24.png -------------------------------------------------------------------------------- /code/13/images/b_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_25.png -------------------------------------------------------------------------------- /code/13/images/b_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_3.png -------------------------------------------------------------------------------- /code/13/images/b_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_4.png -------------------------------------------------------------------------------- /code/13/images/b_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_5.png -------------------------------------------------------------------------------- /code/13/images/b_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_6.png -------------------------------------------------------------------------------- /code/13/images/b_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_7.png -------------------------------------------------------------------------------- /code/13/images/b_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_8.png -------------------------------------------------------------------------------- /code/13/images/b_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/b_9.png -------------------------------------------------------------------------------- /code/13/images/covid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/covid.png -------------------------------------------------------------------------------- /code/13/images/laser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/laser.png -------------------------------------------------------------------------------- /code/13/images/score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/images/score.png -------------------------------------------------------------------------------- /code/13/music/bg.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/music/bg.mp3 -------------------------------------------------------------------------------- /code/13/pose_util.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | 4 | from utils import find_angle 5 | 6 | class PoseDetector(): 7 | def __init__(self): 8 | self.pose = mp.solutions.pose.Pose() 9 | self.draw_util = mp.solutions.drawing_utils 10 | 11 | def detect(self, img, draw=True): 12 | self.positions = [] 13 | results = self.pose.process(img) 14 | if results and results.pose_landmarks: 15 | if draw: 16 | self.draw_util.draw_landmarks(img, results.pose_landmarks, mp.solutions.pose.POSE_CONNECTIONS) 17 | 18 | for id, lm in enumerate(results.pose_landmarks.landmark): 19 | h, w, c = img.shape 20 | cx, cy = int(lm.x * w), int(lm.y * h) 21 | self.positions.append([id, cx, cy]) 22 | 23 | def get_angle(self, img, p1, p2, p3, draw=True): 24 | ''' 25 | 获取人体姿势中3个点p1-p2-p3的角度 26 | :param img: 一帧图像 27 | :param p1: 第1个点 28 | :param p2: 第2个点 29 | :param p3: 第3个点 30 | :param draw: 是否画出3个点的连接图 31 | :return: 角度 32 | ''' 33 | angle = 0 34 | if self.positions: 35 | x1, y1 = self.positions[p1][1],self.positions[p1][2] 36 | x2, y2 = self.positions[p2][1],self.positions[p2][2] 37 | x3, y3 = self.positions[p3][1],self.positions[p3][2] 38 | angle = find_angle((x1, y1), (x2, y2), (x3, y3)) 39 | 40 | if draw: 41 | cv2.circle(img, (x1, y1), 8, (0, 255, 255), cv2.FILLED) 42 | cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED) 43 | cv2.circle(img, (x3, y3), 8, (0, 255, 255), cv2.FILLED) 44 | cv2.line(img, (x1, y1), (x2, y2), (255, 255, 255, 3)) 45 | cv2.line(img, (x2, y2), (x3, y3), (255, 255, 255, 3)) 46 | cv2.putText(img, str(angle), (x2-50, y2+50),cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 255), 2) 47 | 48 | return angle -------------------------------------------------------------------------------- /code/13/requirements.txt: -------------------------------------------------------------------------------- 1 | opencv-python 2 | mediapipe 3 | pgzero -------------------------------------------------------------------------------- /code/13/sounds/boom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/boom.wav -------------------------------------------------------------------------------- /code/13/sounds/coin.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/coin.wav -------------------------------------------------------------------------------- /code/13/sounds/cut.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/cut.wav -------------------------------------------------------------------------------- /code/13/sounds/explode.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/explode.wav -------------------------------------------------------------------------------- /code/13/sounds/jump.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/jump.wav -------------------------------------------------------------------------------- /code/13/sounds/lose.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/lose.wav -------------------------------------------------------------------------------- /code/13/sounds/pew.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/pew.wav -------------------------------------------------------------------------------- /code/13/sounds/rip.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/13/sounds/rip.wav -------------------------------------------------------------------------------- /code/13/utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def find_angle(p1, p2, p3): 4 | (x1, y1) = p1 5 | (x2, y2) = p2 6 | (x3, y3) = p3 7 | 8 | # 使用三角函数公式获取3个点p1-p2-p3,以p2为角的角度值,0-180度之间 9 | angle = int(math.degrees(math.atan2(y1-y2, x1-x2) - math.atan2(y3-y2, x3-x2))) 10 | '''if angle < 0: 11 | angle = angle + 360 12 | if angle > 180: 13 | angle = 360 - angle''' 14 | 15 | return angle 16 | 17 | 18 | # 判断actor是否被到objects列表里的任意一个角色 19 | def is_touch(actor, objects): 20 | for obj in objects: 21 | if actor.colliderect(obj): 22 | return True 23 | return False -------------------------------------------------------------------------------- /code/13/video.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | camera = cv2.VideoCapture(1) 4 | camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) 5 | camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) 6 | 7 | while True: 8 | success, frame = camera.read() 9 | if success: 10 | cv2.imshow("Video", frame) 11 | key = cv2.waitKey(1) 12 | if key == ord("q"): 13 | break 14 | 15 | camera.release() 16 | cv2.destroyAllWindows() 17 | -------------------------------------------------------------------------------- /code/2/2.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | url = 'https://fanyi.baidu.com/sug' 4 | 5 | while True: 6 | text = input('Please input English or Chinese word:').strip() 7 | if text == 'q': 8 | break 9 | 10 | data = {'kw': text} 11 | 12 | resp = requests.post(url, data) 13 | 14 | found = False 15 | if resp.status_code == 200: 16 | data = resp.json() 17 | if data['errno'] == 0: 18 | ds = data['data'] 19 | for kv in ds: 20 | if kv['k'] == text: 21 | found = True 22 | print(kv['v']) 23 | if not found: 24 | print('Not found') 25 | else: 26 | print(data) 27 | else: 28 | print(resp.content) 29 | 30 | -------------------------------------------------------------------------------- /code/3/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/3/.DS_Store -------------------------------------------------------------------------------- /code/3/3.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from PIL import Image, ImageDraw, ImageFont 4 | 5 | 6 | def get_position(image_width, image_height, text_width, text_height, position_id=9, margin=10): 7 | ''' 8 | Get the position of the text by the position_id 9 | 1: top left, 2: top center, 3: top right 10 | 4: middle left, 5: middle center, 6: middle right 11 | 7: bottom left, 8: bottom center, 9: bottom right 12 | :param image_width: image width 13 | :param image_height: image height 14 | :param text_width: text width 15 | :param text_height: text height 16 | :param position_id: position_id 17 | :param margin: the text position margin value to the image 18 | :return: text position tuple 19 | ''' 20 | margin = 10 21 | if position_id == 1: 22 | return (margin, margin) 23 | elif position_id == 2: 24 | return (image_width // 2 - text_width // 2, margin) 25 | elif position_id == 3: 26 | return (image_width - text_width - margin, margin) 27 | elif position_id == 4: 28 | return (margin, image_height // 2 - text_height // 2) 29 | elif position_id == 5: 30 | return (image_width // 2 - text_width // 2, image_height // 2 - text_height // 2) 31 | elif position_id == 6: 32 | return (image_width - text_width - margin, image_height // 2 - text_height // 2) 33 | elif position_id == 7: 34 | return (margin, image_height - text_height - margin) 35 | elif position_id == 8: 36 | return (image_width // 2 - text_width // 2, image_height - text_height - margin) 37 | elif position_id == 9: 38 | return (image_width - text_width - margin, image_height - text_height - margin) 39 | 40 | 41 | def add_watermark(filename, text, font_name='PMingLiU.ttf', font_size=20, font_opacity=50, position_id=9): 42 | ''' 43 | Add watermark function 44 | :param filename: origin image filename 45 | :param text: watermark text 46 | :param font_name: Roboto-Italic.ttf, you can use your font, please make sure your program can find it 47 | :param font_size: font size, default is 20 48 | :param font_opacity: font opacity, default is 50 49 | :param position_id: position id, defalut is 9 (bottom right) 50 | :return: 51 | ''' 52 | # get an image 53 | with Image.open(filename).convert("RGBA") as base: 54 | # make a blank image for the text, initialized to transparent text color 55 | txt = Image.new("RGBA", base.size, (255, 255, 255, 0)) 56 | 57 | # get a font 58 | fnt = ImageFont.truetype(font_name, font_size) 59 | # get a drawing context 60 | d = ImageDraw.Draw(txt) 61 | # get the text widht and height 62 | text_width, text_height = d.textsize(text, font=fnt) 63 | # get the text position of the image 64 | pos = get_position(base.size[0], base.size[1], text_width, text_height, position_id=position_id) 65 | # draw text with opacity 66 | d.text(pos, text, font=fnt, fill=(255, 255, 255, 256 * font_opacity // 100)) 67 | out = Image.alpha_composite(base, txt) 68 | 69 | # save the image file 70 | out_filename = 'watermark/{}'.format(os.path.basename(filename)) 71 | if not os.path.exists('watermark'): 72 | os.makedirs('watermark') 73 | out.save(out_filename, 'PNG') 74 | 75 | 76 | if __name__ == '__main__': 77 | text = input('Please input a watermark text: ').strip() 78 | font_size = int(input('Please input the font size: [20]') or '20') 79 | font_opacity = int(input('Please input the font opacity: [50]') or '50') 80 | # 1: top left, 2: top center, 3: top right 81 | # 4: middle left, 5: middle center, 6: middle right 82 | # 7: bottom left, 8: bottom center, 9: bottom right 83 | position_id = int(input('Please input the position: [9]') or '9') 84 | 85 | for f in os.listdir('images'): 86 | if f.endswith('.png'): 87 | filename = 'images/{}'.format(f) 88 | print('add watermark for {}'.format(filename)) 89 | add_watermark(filename=filename, text=text, font_size=font_size, font_opacity=font_opacity, 90 | position_id=position_id) 91 | -------------------------------------------------------------------------------- /code/3/PMingLiU.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/3/PMingLiU.ttf -------------------------------------------------------------------------------- /code/3/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/3/Roboto-Italic.ttf -------------------------------------------------------------------------------- /code/3/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/3/images/1.png -------------------------------------------------------------------------------- /code/3/requirements.txt: -------------------------------------------------------------------------------- 1 | pillow -------------------------------------------------------------------------------- /code/3/watermark/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/code/3/watermark/1.png -------------------------------------------------------------------------------- /code/4/4.py: -------------------------------------------------------------------------------- 1 | import speech_recognition as sr 2 | 3 | 4 | def recognize_speech_from_mic(recognizer, microphone): 5 | ''' 6 | Transcribe speech from recorded from `microphone`. 7 | :param recognizer: 8 | :param microphone: 9 | :return: `None` if speech could not be transcribed, otherwise a string containing the transcribed text 10 | ''' 11 | print('Please read the English sentence') 12 | # adjust the recognizer sensitivity to ambient noise and record audio 13 | # from the microphone 14 | with microphone as source: 15 | recognizer.adjust_for_ambient_noise(source) 16 | audio = recognizer.listen(source) 17 | 18 | # try recognizing the speech in the recording 19 | try: 20 | text = recognizer.recognize_google(audio) 21 | except Exception as e: 22 | print(e) 23 | text = None 24 | 25 | return text 26 | 27 | 28 | if __name__ == '__main__': 29 | # input a English word or sentence 30 | text = input('Please input a English word or sentence: ').strip() 31 | 32 | # create recognizer and mic instances 33 | recognizer = sr.Recognizer() 34 | microphone = sr.Microphone() 35 | 36 | # get your speech text 37 | speech_text = recognize_speech_from_mic(recognizer, microphone) 38 | 39 | while speech_text != None and text.lower() != speech_text.lower(): 40 | print(speech_text) 41 | # get your speech text 42 | speech_text = recognize_speech_from_mic(recognizer, microphone) 43 | 44 | if speech_text: 45 | print('{} {}'.format(speech_text, '✓')) 46 | else: 47 | print('Please try the speech recognization service later or change another one.') 48 | -------------------------------------------------------------------------------- /code/4/requirements.txt: -------------------------------------------------------------------------------- 1 | SpeechRecognition 2 | pyaudio 3 | -------------------------------------------------------------------------------- /code/5/5.py: -------------------------------------------------------------------------------- 1 | import speech_recognition as sr 2 | from aip import AipSpeech 3 | 4 | # Please signup baidu ASR service:https://ai.baidu.com/tech/speech/asr 5 | VOICE_APP_ID = 'YOUR_ASR_APP_ID' 6 | VOICE_API_KEY = 'YOUR_ASR_APP_KEY' 7 | VOICE_SECRET_KEY = 'YOUR_ASR_SECRET_KEY' 8 | voice_client = AipSpeech(VOICE_APP_ID, VOICE_API_KEY, VOICE_SECRET_KEY) 9 | 10 | 11 | # baidu asr service 12 | def asr(audio_data): 13 | wav_data = audio_data.get_wav_data( 14 | convert_rate=16000, 15 | convert_width=2 16 | ) 17 | res = voice_client.asr(wav_data, 'wav', 16000, { 18 | 'dev_pid': 1737, 19 | }) 20 | if res['err_no'] == 0: 21 | return ''.join(res['result']) 22 | else: 23 | return '' 24 | 25 | 26 | def recognize_speech_from_mic(recognizer, microphone): 27 | ''' 28 | Transcribe speech from recorded from `microphone`. 29 | :param recognizer: 30 | :param microphone: 31 | :return: `None` if speech could not be transcribed, otherwise a string containing the transcribed text 32 | ''' 33 | print('Please read the English sentence') 34 | # adjust the recognizer sensitivity to ambient noise and record audio 35 | # from the microphone 36 | with microphone as source: 37 | recognizer.adjust_for_ambient_noise(source) 38 | audio = recognizer.listen(source) 39 | 40 | # try recognizing the speech in the recording 41 | try: 42 | text = asr(audio) 43 | except Exception as e: 44 | print(e) 45 | text = None 46 | 47 | return text 48 | 49 | 50 | if __name__ == '__main__': 51 | # input a English word or sentence 52 | text = input('Please input a English word or sentence: ').strip() 53 | 54 | # create recognizer and mic instances 55 | recognizer = sr.Recognizer() 56 | microphone = sr.Microphone() 57 | 58 | # get your speech text 59 | speech_text = recognize_speech_from_mic(recognizer, microphone) 60 | 61 | while speech_text != None and text.lower() != speech_text.lower(): 62 | print('{} ×'.format(speech_text)) 63 | # get your speech text 64 | speech_text = recognize_speech_from_mic(recognizer, microphone) 65 | 66 | if speech_text: 67 | print('{} {}'.format(speech_text, '✓')) 68 | else: 69 | print('Please try the speech recognization service later or change another one.') 70 | -------------------------------------------------------------------------------- /code/5/requirements.txt: -------------------------------------------------------------------------------- 1 | baidu-aip 2 | SpeechRecognition 3 | pyaudio 4 | -------------------------------------------------------------------------------- /code/6/arithmetic_arranger.py: -------------------------------------------------------------------------------- 1 | def f(s): 2 | l = s.split(' ') 3 | try: 4 | a, op, b = int(l[0]), l[1], int(l[2]) 5 | except ValueError: 6 | raise Exception('Error: Numbers must only contain digits.') 7 | if not (op == '+' or op == '-'): 8 | raise Exception('Error: Operator must be \'+\' or \'-\'.') 9 | if a > 9999 or b > 9999: 10 | raise Exception('Error: Numbers cannot be more than four digits.') 11 | c = eval(s) 12 | max_len = len(str(max(a, b))) + 2 13 | 14 | r = [] 15 | r.append(str(a).rjust(max_len, ' ')) 16 | r.append(op + ' ' + str(b).rjust(max_len - 2, ' ')) 17 | r.append('-' * max_len) 18 | r.append(str(c).rjust(max_len, ' ')) 19 | return r 20 | 21 | 22 | def arithmetic_arranger(problems, show_result=False): 23 | if len(problems) > 5: 24 | return 'Error: Too many problems.' 25 | 26 | arranged_problems = '' 27 | d = [] 28 | for problem in problems: 29 | try: 30 | ps = f(problem) 31 | d.append(ps) 32 | except Exception as e: 33 | return str(e) 34 | 35 | n = 3 36 | if show_result: 37 | n = 4 38 | 39 | for i in range(n): 40 | for j in range(len(d)): 41 | ps = d[j] 42 | if j == 0: 43 | arranged_problems = arranged_problems + ps[i] 44 | else: 45 | arranged_problems = arranged_problems + ' ' + ps[i] 46 | if i != n - 1: 47 | arranged_problems = arranged_problems + '\n' 48 | 49 | return arranged_problems 50 | -------------------------------------------------------------------------------- /code/6/test_module.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from arithmetic_arranger import arithmetic_arranger 3 | 4 | 5 | # the test case 6 | class UnitTests(unittest.TestCase): 7 | def test_arrangement(self): 8 | actual = arithmetic_arranger(["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]) 9 | expected = " 3 3801 45 123\n+ 855 - 2 + 43 + 49\n----- ------ ---- -----" 10 | self.assertEqual(actual, expected, 11 | 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]') 12 | 13 | actual = arithmetic_arranger(["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"]) 14 | expected = " 11 3801 1 123 1\n+ 4 - 2999 + 2 + 49 - 9380\n---- ------ --- ----- ------" 15 | self.assertEqual(actual, expected, 16 | 'Expected different output when calling "arithmetic_arranger()" with ["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"]') 17 | 18 | def test_too_many_problems(self): 19 | actual = arithmetic_arranger(["44 + 815", "909 - 2", "45 + 43", "123 + 49", "888 + 40", "653 + 87"]) 20 | expected = "Error: Too many problems." 21 | self.assertEqual(actual, expected, 22 | 'Expected calling "arithmetic_arranger()" with more than five problems to return "Error: Too many problems."') 23 | 24 | def test_incorrect_operator(self): 25 | actual = arithmetic_arranger(["3 / 855", "3801 - 2", "45 + 43", "123 + 49"]) 26 | expected = "Error: Operator must be '+' or '-'." 27 | self.assertEqual(actual, expected, 28 | '''Expected calling "arithmetic_arranger()" with a problem that uses the "/" operator to return "Error: Operator must be '+' or '-'."''') 29 | 30 | def test_too_many_digits(self): 31 | actual = arithmetic_arranger(["24 + 85215", "3801 - 2", "45 + 43", "123 + 49"]) 32 | expected = "Error: Numbers cannot be more than four digits." 33 | self.assertEqual(actual, expected, 34 | 'Expected calling "arithmetic_arranger()" with a problem that has a number over 4 digits long to return "Error: Numbers cannot be more than four digits."') 35 | 36 | def test_only_digits(self): 37 | actual = arithmetic_arranger(["98 + 3g5", "3801 - 2", "45 + 43", "123 + 49"]) 38 | expected = "Error: Numbers must only contain digits." 39 | self.assertEqual(actual, expected, 40 | 'Expected calling "arithmetic_arranger()" with a problem that contains a letter character in the number to return "Error: Numbers must only contain digits."') 41 | 42 | def test_solutions(self): 43 | actual = arithmetic_arranger(["32 - 698", "1 - 3801", "45 + 43", "123 + 49"], True) 44 | expected = " 32 1 45 123\n- 698 - 3801 + 43 + 49\n----- ------ ---- -----\n -666 -3800 88 172" 45 | self.assertEqual(actual, expected, 46 | 'Expected solutions to be correctly displayed in output when calling "arithmetic_arranger()" with arithmetic problems and a second argument of `True`.') 47 | 48 | 49 | if __name__ == "__main__": 50 | unittest.main() 51 | -------------------------------------------------------------------------------- /code/7/opencv_capture_camera_video.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | # Open your computer's default camera device. 4 | # If your default camera ID is not 0, please use the correct ID 5 | camera = cv2.VideoCapture(0) 6 | 7 | # while loop to read the camera image 8 | while True: 9 | success, img = camera.read() 10 | # if read success, it'll show the image in a "Video" window 11 | if success: 12 | cv2.imshow('Video', img) 13 | # get the key press, if you pressed "q" key it'll break the while loop 14 | k = cv2.waitKey(1) 15 | if k == ord('q'): 16 | break 17 | 18 | # release your camera device and close the OpenCV windows 19 | camera.release() 20 | cv2.destroyAllWindows() 21 | -------------------------------------------------------------------------------- /code/7/requirements.txt: -------------------------------------------------------------------------------- 1 | # My Python version is: 3.8.9 2 | opencv-python==4.5.4.60 3 | -------------------------------------------------------------------------------- /code/8/hand.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from handUtils import HandDetector 3 | 4 | camera = cv2.VideoCapture(1) 5 | hand_detector = HandDetector() 6 | 7 | while True: 8 | success, img = camera.read() 9 | if success: 10 | img = cv2.flip(img, 1) 11 | hand_detector.process(img, draw=False) 12 | position = hand_detector.find_position(img) 13 | left_finger = position['Left'].get(8, None) 14 | if left_finger: 15 | cv2.circle(img, (left_finger[0], left_finger[1]),10, (0, 0, 255), cv2.FILLED) 16 | right_finger = position['Right'].get(8, None) 17 | if right_finger: 18 | cv2.circle(img, (right_finger[0], right_finger[1]),10, (0, 255, 0), cv2.FILLED) 19 | cv2.imshow('Video', img) 20 | k = cv2.waitKey(1) 21 | if k == ord('q'): 22 | break 23 | 24 | camera.release() 25 | cv2.destroyAllWindows() 26 | -------------------------------------------------------------------------------- /code/8/handUtils.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | 4 | class HandDetector(): 5 | def __init__(self): 6 | self.hand_detector = mp.solutions.hands.Hands() 7 | self.drawer = mp.solutions.drawing_utils 8 | 9 | def process(self, img, draw=True): 10 | img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 11 | self.hands_data = self.hand_detector.process(img_rgb) 12 | if draw: 13 | if self.hands_data.multi_hand_landmarks: 14 | for handlms in self.hands_data.multi_hand_landmarks: 15 | self.drawer.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS) 16 | 17 | def find_position(self, img): 18 | h, w, c = img.shape 19 | position = {'Left': {}, 'Right': {}} 20 | if self.hands_data.multi_hand_landmarks: 21 | i = 0 22 | for point in self.hands_data.multi_handedness: 23 | score = point.classification[0].score 24 | if score >= 0.8: 25 | label = point.classification[0].label 26 | hand_lms = self.hands_data.multi_hand_landmarks[i].landmark 27 | for id, lm in enumerate(hand_lms): 28 | x, y = int(lm.x * w), int(lm.y * h) 29 | position[label][id] = (x, y) 30 | i = i + 1 31 | return position -------------------------------------------------------------------------------- /code/8/requirements.txt: -------------------------------------------------------------------------------- 1 | # My Python version is: 3.8.9 2 | opencv-python==4.5.4.60 3 | mediapipe==0.8.9 4 | -------------------------------------------------------------------------------- /code/9/hand.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from handUtils import HandDetector 3 | 4 | camera = cv2.VideoCapture(1) 5 | hand_detector = HandDetector() 6 | 7 | while True: 8 | success, img = camera.read() 9 | if success: 10 | img = cv2.flip(img, 1) 11 | h, w, c = img.shape 12 | hand_detector.process(img, draw=False) 13 | position = hand_detector.find_position(img) 14 | left_fingers = hand_detector.fingers_count('Left') 15 | print('左手: ', left_fingers) 16 | cv2.putText(img, str(left_fingers), (100, 150), cv2.FONT_HERSHEY_DUPLEX, 5, (0, 255, 0)) 17 | right_fingers = hand_detector.fingers_count('Right') 18 | print('右手:', right_fingers) 19 | cv2.putText(img, str(right_fingers), (w-200, 150), cv2.FONT_HERSHEY_DUPLEX, 5, (255, 0, 0)) 20 | cv2.imshow('Video', img) 21 | k = cv2.waitKey(1) 22 | if k == ord('q'): 23 | break 24 | 25 | camera.release() 26 | cv2.destroyAllWindows() 27 | -------------------------------------------------------------------------------- /code/9/handUtils.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | 4 | class HandDetector(): 5 | def __init__(self): 6 | self.hand_detector = mp.solutions.hands.Hands() 7 | self.drawer = mp.solutions.drawing_utils 8 | 9 | def process(self, img, draw=True): 10 | img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 11 | self.hands_data = self.hand_detector.process(img_rgb) 12 | if draw: 13 | if self.hands_data.multi_hand_landmarks: 14 | for handlms in self.hands_data.multi_hand_landmarks: 15 | self.drawer.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS) 16 | 17 | def find_position(self, img): 18 | h, w, c = img.shape 19 | self.position = {'Left': {}, 'Right': {}} 20 | if self.hands_data.multi_hand_landmarks: 21 | i = 0 22 | for point in self.hands_data.multi_handedness: 23 | score = point.classification[0].score 24 | if score >= 0.8: 25 | label = point.classification[0].label 26 | hand_lms = self.hands_data.multi_hand_landmarks[i].landmark 27 | for id, lm in enumerate(hand_lms): 28 | x, y = int(lm.x * w), int(lm.y * h) 29 | self.position[label][id] = (x, y) 30 | i = i + 1 31 | return self.position 32 | 33 | def fingers_count(self, hand='Left'): 34 | tips = [4, 8, 12, 16, 20] 35 | tip_data = {4:0, 8:0, 12:0, 16:0, 20:0} 36 | for tip in tips: 37 | ltp1 = self.position[hand].get(tip, None) 38 | ltp2 = self.position[hand].get(tip-2, None) 39 | if ltp1 and ltp2: 40 | if tip == 4: 41 | if ltp1[0] > ltp2[0]: 42 | if hand == 'Left': 43 | tip_data[tip] = 1 44 | else: 45 | tip_data[tip] = 0 46 | else: 47 | if hand == 'Left': 48 | tip_data[tip] = 0 49 | else: 50 | tip_data[tip] = 1 51 | else: 52 | if ltp1[1] > ltp2[1]: 53 | tip_data[tip] = 0 54 | else: 55 | tip_data[tip] = 1 56 | return list(tip_data.values()).count(1) -------------------------------------------------------------------------------- /code/9/requirements.txt: -------------------------------------------------------------------------------- 1 | # My Python version is: 3.8.9 2 | opencv-python==4.5.4.60 3 | mediapipe==0.8.9 4 | -------------------------------------------------------------------------------- /images/011_snake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/011_snake.png -------------------------------------------------------------------------------- /images/012_minesweeper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/012_minesweeper.png -------------------------------------------------------------------------------- /images/013_posegame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/013_posegame.png -------------------------------------------------------------------------------- /images/2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/2048.png -------------------------------------------------------------------------------- /images/challenge1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge1_1.png -------------------------------------------------------------------------------- /images/challenge2_cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge2_cn.png -------------------------------------------------------------------------------- /images/challenge2_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge2_en.png -------------------------------------------------------------------------------- /images/challenge4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge4.png -------------------------------------------------------------------------------- /images/challenge_10_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_10_1.png -------------------------------------------------------------------------------- /images/challenge_10_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_10_2.png -------------------------------------------------------------------------------- /images/challenge_3_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_3_1.png -------------------------------------------------------------------------------- /images/challenge_3_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_3_2.png -------------------------------------------------------------------------------- /images/challenge_3_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_3_3.png -------------------------------------------------------------------------------- /images/challenge_3_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_3_4.png -------------------------------------------------------------------------------- /images/challenge_3_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_3_5.png -------------------------------------------------------------------------------- /images/challenge_4_cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_4_cn.png -------------------------------------------------------------------------------- /images/challenge_4_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_4_en.png -------------------------------------------------------------------------------- /images/challenge_5_cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_5_cn.png -------------------------------------------------------------------------------- /images/challenge_5_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/challenge_5_en.png -------------------------------------------------------------------------------- /images/tetris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhiwehu/100_plus_Python_Projects_Challenge/57efa2ab7463969c74c100868510ed490f8ffc14/images/tetris.png -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | from turtle import * 2 | from math import ceil, floor 3 | from random import randint 4 | 5 | n = 10 6 | gz = 40 7 | bc = n * gz 8 | win = False 9 | dead = False 10 | can_start = True 11 | fx = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]] 12 | # 随机生成地雷数量 13 | booms = randint(n * n // 10, n * n // 2) 14 | d = [] 15 | m = [] 16 | c = [] 17 | b = [] 18 | 19 | t = Turtle() 20 | t.ht() 21 | t.up() 22 | t.speed(0) 23 | 24 | judge = Turtle() 25 | judge.ht() 26 | judge.up() 27 | judge.speed(0) 28 | 29 | 30 | # 画边框 31 | def draw(): 32 | t.clear() 33 | t.seth(0) 34 | t.color("black") 35 | t.goto(-bc / 2, bc / 2) 36 | for i in range(n + 1): 37 | t.down() 38 | t.fd(bc) 39 | t.bk(bc) 40 | t.up() 41 | t.goto(-bc / 2, bc / 2 - (i + 1) * gz) 42 | t.goto(-bc / 2, bc / 2) 43 | t.rt(90) 44 | for i in range(n + 1): 45 | t.down() 46 | t.fd(bc) 47 | t.bk(bc) 48 | t.up() 49 | t.goto(-bc / 2 + (i + 1) * gz, bc / 2) 50 | 51 | 52 | # 写地雷数 53 | def write_booms(): 54 | judge.clear() 55 | judge.goto(-gz, bc / 2 + gz - gz / 8) 56 | judge.color("red") 57 | judge.dot(20) 58 | judge.goto(0, bc / 2 + gz / 2) 59 | judge.write(": {}".format(booms), align="center", font=("Kai", 30, "bold")) 60 | 61 | 62 | # 初始化列表 63 | def init_list(n, default=0): 64 | lines = [] 65 | for i in range(n): 66 | line = [] 67 | for j in range(n): 68 | line.append(default) 69 | lines.append(line) 70 | return lines 71 | 72 | 73 | # 打印列表 74 | def print_list(lines): 75 | print() 76 | for line in lines: 77 | for item in line: 78 | print(item, end=' ') 79 | print() 80 | print() 81 | 82 | 83 | # x,y -> i, j 84 | def xytoij(x, y): 85 | ix = floor(x / gz) * gz 86 | iy = floor(y / gz) * gz 87 | j = (ix + bc / 2) / gz 88 | i = (bc / 2 - iy) / gz - 1 89 | return int(i), int(j) 90 | 91 | 92 | # i, j -> x, y 93 | def ijtoxy(i, j): 94 | x = -bc / 2 + gz / 2 + j * gz 95 | y = bc / 2 - gz / 2 - i * gz - gz / 4 96 | return x, y 97 | 98 | 99 | def set_color(booms): 100 | if booms <= 1: 101 | t.color("green") 102 | elif booms == 2: 103 | t.color("blue") 104 | elif booms == 3: 105 | t.color("brown") 106 | elif booms == 4: 107 | t.color("orange") 108 | elif booms == 5: 109 | t.color("red") 110 | elif booms >= 6: 111 | t.color("purple") 112 | 113 | 114 | def start(): 115 | global d, m, c, b, booms, can_start, win, dead 116 | if can_start: 117 | win = False 118 | dead = False 119 | can_start = False 120 | draw() 121 | # 地雷列表:0表示没雷,1表示有雷 122 | d = init_list(n) 123 | # 标记列表:0表示没雷,1表示有雷 124 | m = init_list(n) 125 | # 点击列表:0表示没点击,1表示点击 126 | c = init_list(n) 127 | # 计算得出地雷数量列表:-1表示地雷,其他数字表示周围有多少地雷 128 | b = init_list(n) 129 | booms = randint(n * n // 10, n * n // 2) 130 | # 随机生成地雷 131 | for k in range(booms): 132 | i = randint(0, n - 1) 133 | j = randint(0, n - 1) 134 | d[i][j] = 1 135 | 136 | write_booms() 137 | 138 | # 计算每个位置周围有多少雷,存放b列表 139 | for i in range(n): 140 | for j in range(n): 141 | if d[i][j] == 1: 142 | b[i][j] = -1 143 | for f in fx: 144 | ni = i + f[0] 145 | nj = j + f[1] 146 | if (ni >= 0 and ni < n and nj >= 0 and nj < n and b[ni][nj] != -1): 147 | b[ni][nj] += 1 148 | 149 | 150 | # 检查i, j周围8个方向(一圈),如果没有雷或者已经全部正确标记,则返回True 151 | def check_around(i, j): 152 | cnt = 0 153 | for f in fx: 154 | ni = i + f[0] 155 | nj = j + f[1] 156 | 157 | if (ni >= 0 and ni < n and nj >= 0 and nj < n): 158 | if d[ni][nj] == 1 and m[ni][nj] == 1: 159 | cnt += 1 160 | return b[i][j] == cnt 161 | 162 | 163 | # 如果i, j位置周围已经全部确认,则在i, j的8个方向上的下一个位置,递归再检查 164 | def check_and_auto_click(i, j): 165 | if (i >= 0 and i < n and j >= 0 and j < n and check_around(i, j)): 166 | for f in fx: 167 | ni = i + f[0] 168 | nj = j + f[1] 169 | if (ni >= 0 and ni < n and nj >= 0 and nj < n and b[ni][nj] != -1 and c[ni][nj] == 0): 170 | c[ni][nj] = 1 171 | check_and_auto_click(ni, nj) 172 | x, y = ijtoxy(ni, nj) 173 | t.goto(x, y) 174 | set_color(b[ni][nj]) 175 | t.write(b[ni][nj], align="center", font=("Arial", 20, "normal")) 176 | 177 | 178 | # 检查是否已经胜利 179 | def check_win(): 180 | for i in range(n): 181 | for j in range(n): 182 | if m[i][j] != d[i][j]: 183 | return False 184 | return True 185 | 186 | 187 | # 鼠标左键点击扫雪 188 | def click(x, y): 189 | global dead, win, can_start 190 | if not dead and not win: 191 | i, j = xytoij(x, y) 192 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 193 | c[i][j] = 1 194 | if d[i][j] == 1: 195 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 196 | t.color("red") 197 | t.dot(20) 198 | dead = True 199 | can_start = True 200 | judge.clear() 201 | judge.color("red") 202 | judge.write("失败,按空格键重新开始", align="center", font=("Kai", 40, "bold")) 203 | else: 204 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 4) 205 | set_color(b[i][j]) 206 | t.write(b[i][j], align="center", font=("Arial", 20, "normal")) 207 | check_and_auto_click(i, j) 208 | if check_win(): 209 | win = True 210 | can_start = True 211 | judge.clear() 212 | judge.color("green") 213 | judge.write("胜利,按空格键重新开始", align="center", font=("Kai", 40, "bold")) 214 | 215 | 216 | # 右键标记雷 217 | def mark(x, y): 218 | global booms, win, can_start 219 | if not dead and not win: 220 | i, j = xytoij(x, y) 221 | if (i >= 0 and i < n and j >= 0 and j < n and c[i][j] == 0): 222 | t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2) 223 | if m[i][j] == 0: 224 | m[i][j] = 1 225 | t.color("green") 226 | t.dot(20) 227 | booms -= 1 228 | else: 229 | m[i][j] = 0 230 | t.color("white") 231 | t.dot(22) 232 | booms += 1 233 | write_booms() 234 | if check_win(): 235 | win = True 236 | can_start = True 237 | judge.clear() 238 | judge.color("green") 239 | judge.write("胜利,按空格键重新开始", align="center", font=("Kai", 40, "bold")) 240 | 241 | 242 | start() 243 | screen = Screen() 244 | screen.onscreenclick(click, 1) 245 | screen.onscreenclick(mark, 2) 246 | screen.onkey(start, "space") 247 | screen.listen() 248 | done() 249 | --------------------------------------------------------------------------------