调整了目录结构

This commit is contained in:
jackfrued 2019-06-05 23:44:31 +08:00
parent 36ffd6c281
commit 6a7f860227
281 changed files with 628 additions and 634 deletions

View File

@ -6,7 +6,7 @@
### for-in循环 ### for-in循环
如果明确的知道循环执行的次数或者是要对一个容器进行迭代(后面会讲到),那么我们推荐使用`for-in`循环,例如下面代码中计算![$\sum_{n=1}^{100}n$](./res/formula_1.png)。 如果明确的知道循环执行的次数或者是要对一个容器进行迭代(后面会讲到),那么我们推荐使用`for-in`循环,例如下面代码中计算![$\sum_{n=1}^{100}n$](./res/formula_2.png)。
```Python ```Python
""" """

View File

@ -2,11 +2,11 @@
在讲解本章节的内容之前,我们先来研究一道数学题,请说出下面的方程有多少组正整数解。 在讲解本章节的内容之前,我们先来研究一道数学题,请说出下面的方程有多少组正整数解。
![$$x_1 + x_2 + x_3 + x_4 = 8$$](./res/formula_1.png) ![$$x_1 + x_2 + x_3 + x_4 = 8$$](./res/formula_3.png)
事实上上面的问题等同于将8个苹果分成四组每组至少一个苹果有多少种方案。想到这一点问题的答案就呼之欲出了。 事实上上面的问题等同于将8个苹果分成四组每组至少一个苹果有多少种方案。想到这一点问题的答案就呼之欲出了。
![$$C_M^N =\frac{M!}{N!(M-N)!}, \text{(M=7, N=3)} $$](./res/formula_2.png) ![$$C_M^N =\frac{M!}{N!(M-N)!}, \text{(M=7, N=3)} $$](./res/formula_4.png)
可以用Python的程序来计算出这个值代码如下所示。 可以用Python的程序来计算出这个值代码如下所示。

View File

@ -2,7 +2,7 @@
### 使用字符串 ### 使用字符串
第二次世界大战促使了现代电子计算机的诞生当初的想法很简单就是用计算机来计算导弹的弹道因此在计算机刚刚诞生的那个年代计算机处理的信息主要是数值而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移虽然对数值运算仍然是计算机日常工作中最为重要的事情之一但是今天的计算机处理得更多的数据都是以文本信息的方式存在的而Python表示文本信息的方式我们在很早以前就说过了那就是字符串类型。所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为![$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](./res/formula_1.png)。 第二次世界大战促使了现代电子计算机的诞生当初的想法很简单就是用计算机来计算导弹的弹道因此在计算机刚刚诞生的那个年代计算机处理的信息主要是数值而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移虽然对数值运算仍然是计算机日常工作中最为重要的事情之一但是今天的计算机处理得更多的数据都是以文本信息的方式存在的而Python表示文本信息的方式我们在很早以前就说过了那就是字符串类型。所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为![$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](./res/formula_5.png)。
我们可以通过下面的代码来了解字符串的使用。 我们可以通过下面的代码来了解字符串的使用。
@ -183,11 +183,11 @@ if __name__ == '__main__':
除了上面提到的生成器语法Python中还有另外一种定义生成器的方式就是通过`yield`关键字将一个普通函数改造成生成器函数。下面的代码演示了如何实现一个生成[斐波拉切数列](https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97)的生成器。所谓斐波拉切数列可以通过下面[递归](https://zh.wikipedia.org/wiki/%E9%80%92%E5%BD%92)的方法来进行定义: 除了上面提到的生成器语法Python中还有另外一种定义生成器的方式就是通过`yield`关键字将一个普通函数改造成生成器函数。下面的代码演示了如何实现一个生成[斐波拉切数列](https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97)的生成器。所谓斐波拉切数列可以通过下面[递归](https://zh.wikipedia.org/wiki/%E9%80%92%E5%BD%92)的方法来进行定义:
![$${\displaystyle F_{0}=0}$$](./res/formula_2.png) ![$${\displaystyle F_{0}=0}$$](./res/formula_6.png)
![$${\displaystyle F_{1}=1}$$](./res/formula_3.png) ![$${\displaystyle F_{1}=1}$$](./res/formula_7.png)
![$${\displaystyle F_{n}=F_{n-1}+F_{n-2}}({n}\geq{2})$$](./res/formula_4.png) ![$${\displaystyle F_{n}=F_{n-1}+F_{n-2}}({n}\geq{2})$$](./res/formula_8.png)
![](./res/fibonacci-blocks.png) ![](./res/fibonacci-blocks.png)

View File

@ -297,3 +297,123 @@ if __name__ == '__main__':
传输层除了有可靠的传输协议TCP之外还有一种非常轻便的传输协议叫做用户数据报协议简称UDP。TCP和UDP都是提供端到端传输服务的协议二者的差别就如同打电话和发短信的区别后者不对传输的可靠性和可达性做出任何承诺从而避免了TCP中握手和重传的开销所以在强调性能和而不是数据完整性的场景中例如传输网络音视频数据UDP可能是更好的选择。可能大家会注意到一个现象就是在观看网络视频时有时会出现卡顿有时会出现花屏这无非就是部分数据传丢或传错造成的。在Python中也可以使用UDP套接字来创建网络应用对此我们不进行赘述有兴趣的读者可以自行研究。 传输层除了有可靠的传输协议TCP之外还有一种非常轻便的传输协议叫做用户数据报协议简称UDP。TCP和UDP都是提供端到端传输服务的协议二者的差别就如同打电话和发短信的区别后者不对传输的可靠性和可达性做出任何承诺从而避免了TCP中握手和重传的开销所以在强调性能和而不是数据完整性的场景中例如传输网络音视频数据UDP可能是更好的选择。可能大家会注意到一个现象就是在观看网络视频时有时会出现卡顿有时会出现花屏这无非就是部分数据传丢或传错造成的。在Python中也可以使用UDP套接字来创建网络应用对此我们不进行赘述有兴趣的读者可以自行研究。
### 网络应用开发
#### 发送电子邮件
在即时通信软件如此发达的今天,电子邮件仍然是互联网上使用最为广泛的应用之一,公司向应聘者发出录用通知、网站向用户发送一个激活账号的链接、银行向客户推广它们的理财产品等几乎都是通过电子邮件来完成的,而这些任务应该都是由程序自动完成的。
就像我们可以用HTTP超文本传输协议来访问一个网站一样发送邮件要使用SMTP简单邮件传输协议SMTP也是一个建立在TCP传输控制协议提供的可靠数据传输服务的基础上的应用级协议它规定了邮件的发送者如何跟发送邮件的服务器进行通信的细节而Python中的smtplib模块将这些操作简化成了几个简单的函数。
下面的代码演示了如何在Python发送邮件。
```Python
from smtplib import SMTP
from email.header import Header
from email.mime.text import MIMEText
def main():
# 请自行修改下面的邮件发送者和接收者
sender = 'abcdefg@126.com'
receivers = ['uvwxyz@qq.com', 'uvwxyz@126.com']
message = MIMEText('用Python发送邮件的示例代码.', 'plain', 'utf-8')
message['From'] = Header('王大锤', 'utf-8')
message['To'] = Header('骆昊', 'utf-8')
message['Subject'] = Header('示例代码实验邮件', 'utf-8')
smtper = SMTP('smtp.126.com')
# 请自行修改下面的登录口令
smtper.login(sender, 'secretpass')
smtper.sendmail(sender, receivers, message.as_string())
print('邮件发送完成!')
if __name__ == '__main__':
main()
```
如果要发送带有附件的邮件,那么可以按照下面的方式进行操作。
```Python
from smtplib import SMTP
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
import urllib
def main():
# 创建一个带附件的邮件消息对象
message = MIMEMultipart()
# 创建文本内容
text_content = MIMEText('附件中有本月数据请查收', 'plain', 'utf-8')
message['Subject'] = Header('本月数据', 'utf-8')
# 将文本内容添加到邮件消息对象中
message.attach(text_content)
# 读取文件并将文件作为附件添加到邮件消息对象中
with open('/Users/Hao/Desktop/hello.txt', 'rb') as f:
txt = MIMEText(f.read(), 'base64', 'utf-8')
txt['Content-Type'] = 'text/plain'
txt['Content-Disposition'] = 'attachment; filename=hello.txt'
message.attach(txt)
# 读取文件并将文件作为附件添加到邮件消息对象中
with open('/Users/Hao/Desktop/汇总数据.xlsx', 'rb') as f:
xls = MIMEText(f.read(), 'base64', 'utf-8')
xls['Content-Type'] = 'application/vnd.ms-excel'
xls['Content-Disposition'] = 'attachment; filename=month-data.xlsx'
message.attach(xls)
# 创建SMTP对象
smtper = SMTP('smtp.126.com')
# 开启安全连接
# smtper.starttls()
sender = 'abcdefg@126.com'
receivers = ['uvwxyz@qq.com']
# 登录到SMTP服务器
# 请注意此处不是使用密码而是邮件客户端授权码进行登录
# 对此有疑问的读者可以联系自己使用的邮件服务器客服
smtper.login(sender, 'secretpass')
# 发送邮件
smtper.sendmail(sender, receivers, message.as_string())
# 与邮件服务器断开连接
smtper.quit()
print('发送完成!')
if __name__ == '__main__':
main()
```
#### 发送短信
发送短信也是项目中常见的功能,网站的注册码、验证码、营销信息基本上都是通过短信来发送给用户的。在下面的代码中我们使用了[互亿无线](http://www.ihuyi.com/)短信平台该平台为注册用户提供了50条免费短信以及常用开发语言发送短信的demo可以登录该网站并在用户自服务页面中对短信进行配置提供的API接口实现了发送短信的服务当然国内的短信平台很多读者可以根据自己的需要进行选择通常会考虑费用预算、短信达到率、使用的难易程度等指标如果需要在商业项目中使用短信服务建议购买短信平台提供的套餐服务。
```Python
import urllib.parse
import http.client
import json
def main():
host = "106.ihuyi.com"
sms_send_uri = "/webservice/sms.php?method=Submit"
# 下面的参数需要填入自己注册的账号和对应的密码
params = urllib.parse.urlencode({'account': '你自己的账号', 'password' : '你自己的密码', 'content': '您的验证码是147258。请不要把验证码泄露给其他人。', 'mobile': '接收者的手机号', 'format':'json' })
print(params)
headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
conn = http.client.HTTPConnection(host, port=80, timeout=30)
conn.request('POST', sms_send_uri, params, headers)
response = conn.getresponse()
response_str = response.read()
jsonstr = response_str.decode('utf-8')
print(json.loads(jsonstr))
conn.close()
if __name__ == '__main__':
main()
```

File diff suppressed because one or more lines are too long

View File

@ -1,121 +0,0 @@
## 网络应用开发
### 发送电子邮件
在即时通信软件如此发达的今天,电子邮件仍然是互联网上使用最为广泛的应用之一,公司向应聘者发出录用通知、网站向用户发送一个激活账号的链接、银行向客户推广它们的理财产品等几乎都是通过电子邮件来完成的,而这些任务应该都是由程序自动完成的。
就像我们可以用HTTP超文本传输协议来访问一个网站一样发送邮件要使用SMTP简单邮件传输协议SMTP也是一个建立在TCP传输控制协议提供的可靠数据传输服务的基础上的应用级协议它规定了邮件的发送者如何跟发送邮件的服务器进行通信的细节而Python中的smtplib模块将这些操作简化成了几个简单的函数。
下面的代码演示了如何在Python发送邮件。
```Python
from smtplib import SMTP
from email.header import Header
from email.mime.text import MIMEText
def main():
# 请自行修改下面的邮件发送者和接收者
sender = 'abcdefg@126.com'
receivers = ['uvwxyz@qq.com', 'uvwxyz@126.com']
message = MIMEText('用Python发送邮件的示例代码.', 'plain', 'utf-8')
message['From'] = Header('王大锤', 'utf-8')
message['To'] = Header('骆昊', 'utf-8')
message['Subject'] = Header('示例代码实验邮件', 'utf-8')
smtper = SMTP('smtp.126.com')
# 请自行修改下面的登录口令
smtper.login(sender, 'secretpass')
smtper.sendmail(sender, receivers, message.as_string())
print('邮件发送完成!')
if __name__ == '__main__':
main()
```
如果要发送带有附件的邮件,那么可以按照下面的方式进行操作。
```Python
from smtplib import SMTP
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
import urllib
def main():
# 创建一个带附件的邮件消息对象
message = MIMEMultipart()
# 创建文本内容
text_content = MIMEText('附件中有本月数据请查收', 'plain', 'utf-8')
message['Subject'] = Header('本月数据', 'utf-8')
# 将文本内容添加到邮件消息对象中
message.attach(text_content)
# 读取文件并将文件作为附件添加到邮件消息对象中
with open('/Users/Hao/Desktop/hello.txt', 'rb') as f:
txt = MIMEText(f.read(), 'base64', 'utf-8')
txt['Content-Type'] = 'text/plain'
txt['Content-Disposition'] = 'attachment; filename=hello.txt'
message.attach(txt)
# 读取文件并将文件作为附件添加到邮件消息对象中
with open('/Users/Hao/Desktop/汇总数据.xlsx', 'rb') as f:
xls = MIMEText(f.read(), 'base64', 'utf-8')
xls['Content-Type'] = 'application/vnd.ms-excel'
xls['Content-Disposition'] = 'attachment; filename=month-data.xlsx'
message.attach(xls)
# 创建SMTP对象
smtper = SMTP('smtp.126.com')
# 开启安全连接
# smtper.starttls()
sender = 'abcdefg@126.com'
receivers = ['uvwxyz@qq.com']
# 登录到SMTP服务器
# 请注意此处不是使用密码而是邮件客户端授权码进行登录
# 对此有疑问的读者可以联系自己使用的邮件服务器客服
smtper.login(sender, 'secretpass')
# 发送邮件
smtper.sendmail(sender, receivers, message.as_string())
# 与邮件服务器断开连接
smtper.quit()
print('发送完成!')
if __name__ == '__main__':
main()
```
### 发送短信
发送短信也是项目中常见的功能,网站的注册码、验证码、营销信息基本上都是通过短信来发送给用户的。在下面的代码中我们使用了[互亿无线](http://www.ihuyi.com/)短信平台该平台为注册用户提供了50条免费短信以及常用开发语言发送短信的demo可以登录该网站并在用户自服务页面中对短信进行配置提供的API接口实现了发送短信的服务当然国内的短信平台很多读者可以根据自己的需要进行选择通常会考虑费用预算、短信达到率、使用的难易程度等指标如果需要在商业项目中使用短信服务建议购买短信平台提供的套餐服务。
```Python
import urllib.parse
import http.client
import json
def main():
host = "106.ihuyi.com"
sms_send_uri = "/webservice/sms.php?method=Submit"
# 下面的参数需要填入自己注册的账号和对应的密码
params = urllib.parse.urlencode({'account': '你自己的账号', 'password' : '你自己的密码', 'content': '您的验证码是147258。请不要把验证码泄露给其他人。', 'mobile': '接收者的手机号', 'format':'json' })
print(params)
headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
conn = http.client.HTTPConnection(host, port=80, timeout=30)
conn.request('POST', sms_send_uri, params, headers)
response = conn.getresponse()
response_str = response.read()
jsonstr = response_str.decode('utf-8')
print(json.loads(jsonstr))
conn.close()
if __name__ == '__main__':
main()
```

View File

@ -1,78 +1,78 @@
import pygame import pygame
EMPTY = 0 EMPTY = 0
BLACK = 1 BLACK = 1
WHITE = 2 WHITE = 2
black_color = [0, 0, 0] black_color = [0, 0, 0]
white_color = [255, 255, 255] white_color = [255, 255, 255]
class RenjuBoard(object): class RenjuBoard(object):
def __init__(self): def __init__(self):
self._board = [[]] * 15 self._board = [[]] * 15
self.reset() self.reset()
def reset(self): def reset(self):
for row in range(len(self._board)): for row in range(len(self._board)):
self._board[row] = [EMPTY] * 15 self._board[row] = [EMPTY] * 15
def move(self, row, col, is_black): def move(self, row, col, is_black):
if self._board[row][col] == EMPTY: if self._board[row][col] == EMPTY:
self._board[row][col] = BLACK if is_black else WHITE self._board[row][col] = BLACK if is_black else WHITE
return True return True
return False return False
def draw(self, screen): def draw(self, screen):
for index in range(1, 16): for index in range(1, 16):
pygame.draw.line(screen, black_color, pygame.draw.line(screen, black_color,
[40, 40 * index], [600, 40 * index], 1) [40, 40 * index], [600, 40 * index], 1)
pygame.draw.line(screen, black_color, pygame.draw.line(screen, black_color,
[40 * index, 40], [40 * index, 600], 1) [40 * index, 40], [40 * index, 600], 1)
pygame.draw.rect(screen, black_color, [36, 36, 568, 568], 4) pygame.draw.rect(screen, black_color, [36, 36, 568, 568], 4)
pygame.draw.circle(screen, black_color, [320, 320], 5, 0) pygame.draw.circle(screen, black_color, [320, 320], 5, 0)
pygame.draw.circle(screen, black_color, [160, 160], 5, 0) pygame.draw.circle(screen, black_color, [160, 160], 5, 0)
pygame.draw.circle(screen, black_color, [480, 480], 5, 0) pygame.draw.circle(screen, black_color, [480, 480], 5, 0)
pygame.draw.circle(screen, black_color, [480, 160], 5, 0) pygame.draw.circle(screen, black_color, [480, 160], 5, 0)
pygame.draw.circle(screen, black_color, [160, 480], 5, 0) pygame.draw.circle(screen, black_color, [160, 480], 5, 0)
for row in range(len(self._board)): for row in range(len(self._board)):
for col in range(len(self._board[row])): for col in range(len(self._board[row])):
if self._board[row][col] != EMPTY: if self._board[row][col] != EMPTY:
ccolor = black_color \ ccolor = black_color \
if self._board[row][col] == BLACK else white_color if self._board[row][col] == BLACK else white_color
pos = [40 * (col + 1), 40 * (row + 1)] pos = [40 * (col + 1), 40 * (row + 1)]
pygame.draw.circle(screen, ccolor, pos, 20, 0) pygame.draw.circle(screen, ccolor, pos, 20, 0)
def main(): def main():
board = RenjuBoard() board = RenjuBoard()
is_black = True is_black = True
pygame.init() pygame.init()
pygame.display.set_caption('五子棋') pygame.display.set_caption('五子棋')
screen = pygame.display.set_mode([640, 640]) screen = pygame.display.set_mode([640, 640])
screen.fill([255, 255, 0]) screen.fill([255, 255, 0])
board.draw(screen) board.draw(screen)
pygame.display.flip() pygame.display.flip()
running = True running = True
while running: while running:
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.QUIT: if event.type == pygame.QUIT:
running = False running = False
elif event.type == pygame.KEYUP: elif event.type == pygame.KEYUP:
pass pass
elif event.type == pygame.MOUSEBUTTONDOWN\ elif event.type == pygame.MOUSEBUTTONDOWN\
and event.button == 1: and event.button == 1:
x, y = event.pos x, y = event.pos
row = round((y - 40) / 40) row = round((y - 40) / 40)
col = round((x - 40) / 40) col = round((x - 40) / 40)
if board.move(row, col, is_black): if board.move(row, col, is_black):
is_black = not is_black is_black = not is_black
screen.fill([255, 255, 0]) screen.fill([255, 255, 0])
board.draw(screen) board.draw(screen)
pygame.display.flip() pygame.display.flip()
pygame.quit() pygame.quit()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -1,334 +1,334 @@
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from enum import Enum, unique from enum import Enum, unique
from random import randrange from random import randrange
from threading import Thread from threading import Thread
import pygame import pygame
class Color(object): class Color(object):
"""颜色""" """颜色"""
GRAY = (242, 242, 242) GRAY = (242, 242, 242)
BLACK = (0, 0, 0) BLACK = (0, 0, 0)
GREEN = (0, 255, 0) GREEN = (0, 255, 0)
PINK = (255, 20, 147) PINK = (255, 20, 147)
@unique @unique
class Direction(Enum): class Direction(Enum):
"""方向""" """方向"""
UP = 0 UP = 0
RIGHT = 1 RIGHT = 1
DOWN = 2 DOWN = 2
LEFT = 3 LEFT = 3
class GameObject(object, metaclass=ABCMeta): class GameObject(object, metaclass=ABCMeta):
"""游戏中的对象""" """游戏中的对象"""
def __init__(self, x=0, y=0, color=Color.BLACK): def __init__(self, x=0, y=0, color=Color.BLACK):
""" """
初始化方法 初始化方法
:param x: 横坐标 :param x: 横坐标
:param y: 纵坐标 :param y: 纵坐标
:param color: 颜色 :param color: 颜色
""" """
self._x = x self._x = x
self._y = y self._y = y
self._color = color self._color = color
@property @property
def x(self): def x(self):
return self._x return self._x
@property @property
def y(self): def y(self):
return self._y return self._y
@abstractmethod @abstractmethod
def draw(self, screen): def draw(self, screen):
""" """
绘制 绘制
:param screen: 屏幕 :param screen: 屏幕
""" """
pass pass
class Wall(GameObject): class Wall(GameObject):
"""围墙""" """围墙"""
def __init__(self, x, y, width, height, color=Color.BLACK): def __init__(self, x, y, width, height, color=Color.BLACK):
""" """
初始化方法 初始化方法
:param x: 横坐标 :param x: 横坐标
:param y: 纵坐标 :param y: 纵坐标
:param width: 宽度 :param width: 宽度
:param height: 高度 :param height: 高度
:param color: 颜色 :param color: 颜色
""" """
super().__init__(x, y, color) super().__init__(x, y, color)
self._width = width self._width = width
self._height = height self._height = height
@property @property
def width(self): def width(self):
return self._width return self._width
@property @property
def height(self): def height(self):
return self._height return self._height
def draw(self, screen): def draw(self, screen):
pygame.draw.rect(screen, self._color, pygame.draw.rect(screen, self._color,
(self._x, self._y, self._width, self._height), 4) (self._x, self._y, self._width, self._height), 4)
class Food(GameObject): class Food(GameObject):
"""食物""" """食物"""
def __init__(self, x, y, size, color=Color.PINK): def __init__(self, x, y, size, color=Color.PINK):
""" """
初始化方法 初始化方法
:param x: 横坐标 :param x: 横坐标
:param y: 纵坐标 :param y: 纵坐标
:param size: 大小 :param size: 大小
:param color: 颜色 :param color: 颜色
""" """
super().__init__(x, y, color) super().__init__(x, y, color)
self._size = size self._size = size
self._hidden = False self._hidden = False
def draw(self, screen): def draw(self, screen):
if not self._hidden: if not self._hidden:
pygame.draw.circle(screen, self._color, pygame.draw.circle(screen, self._color,
(self._x + self._size // 2, self._y + self._size // 2), (self._x + self._size // 2, self._y + self._size // 2),
self._size // 2, 0) self._size // 2, 0)
self._hidden = not self._hidden self._hidden = not self._hidden
class SnakeNode(GameObject): class SnakeNode(GameObject):
"""蛇身上的节点""" """蛇身上的节点"""
def __init__(self, x, y, size, color=Color.GREEN): def __init__(self, x, y, size, color=Color.GREEN):
""" """
初始化方法 初始化方法
:param x: 横坐标 :param x: 横坐标
:param y: 纵坐标 :param y: 纵坐标
:param size: 大小 :param size: 大小
:param color: 颜色 :param color: 颜色
""" """
super().__init__(x, y, color) super().__init__(x, y, color)
self._size = size self._size = size
@property @property
def size(self): def size(self):
return self._size return self._size
def draw(self, screen): def draw(self, screen):
pygame.draw.rect(screen, self._color, pygame.draw.rect(screen, self._color,
(self._x, self._y, self._size, self._size), 0) (self._x, self._y, self._size, self._size), 0)
pygame.draw.rect(screen, Color.BLACK, pygame.draw.rect(screen, Color.BLACK,
(self._x, self._y, self._size, self._size), 1) (self._x, self._y, self._size, self._size), 1)
class Snake(GameObject): class Snake(GameObject):
"""""" """"""
def __init__(self, x, y, size=20, length=5): def __init__(self, x, y, size=20, length=5):
""" """
初始化方法 初始化方法
:param x: 横坐标 :param x: 横坐标
:param y: 纵坐标 :param y: 纵坐标
:param size: 大小 :param size: 大小
:param length: 初始长度 :param length: 初始长度
""" """
super().__init__() super().__init__()
self._dir = Direction.LEFT self._dir = Direction.LEFT
self._nodes = [] self._nodes = []
self._alive = True self._alive = True
self._new_dir = None self._new_dir = None
for index in range(length): for index in range(length):
node = SnakeNode(x + index * size, y, size) node = SnakeNode(x + index * size, y, size)
self._nodes.append(node) self._nodes.append(node)
@property @property
def dir(self): def dir(self):
return self._dir return self._dir
@property @property
def alive(self): def alive(self):
return self._alive return self._alive
@property @property
def head(self): def head(self):
return self._nodes[0] return self._nodes[0]
def change_dir(self, new_dir): def change_dir(self, new_dir):
""" """
改变方向 改变方向
:param new_dir: 新方向 :param new_dir: 新方向
""" """
if new_dir != self._dir and \ if new_dir != self._dir and \
(self._dir.value + new_dir.value) % 2 != 0: (self._dir.value + new_dir.value) % 2 != 0:
self._new_dir = new_dir self._new_dir = new_dir
def move(self): def move(self):
"""移动""" """移动"""
if self._new_dir: if self._new_dir:
self._dir, self._new_dir = self._new_dir, None self._dir, self._new_dir = self._new_dir, None
snake_dir = self._dir snake_dir = self._dir
x, y, size = self.head.x, self.head.y, self.head.size x, y, size = self.head.x, self.head.y, self.head.size
if snake_dir == Direction.UP: if snake_dir == Direction.UP:
y -= size y -= size
elif snake_dir == Direction.RIGHT: elif snake_dir == Direction.RIGHT:
x += size x += size
elif snake_dir == Direction.DOWN: elif snake_dir == Direction.DOWN:
y += size y += size
else: else:
x -= size x -= size
new_head = SnakeNode(x, y, size) new_head = SnakeNode(x, y, size)
self._nodes.insert(0, new_head) self._nodes.insert(0, new_head)
self._nodes.pop() self._nodes.pop()
def collide(self, wall): def collide(self, wall):
""" """
撞墙 撞墙
:param wall: 围墙 :param wall: 围墙
""" """
head = self.head head = self.head
if head.x < wall.x or head.x + head.size > wall.x + wall.width \ if head.x < wall.x or head.x + head.size > wall.x + wall.width \
or head.y < wall.y or head.y + head.size > wall.y + wall.height: or head.y < wall.y or head.y + head.size > wall.y + wall.height:
self._alive = False self._alive = False
def eat_food(self, food): def eat_food(self, food):
""" """
吃食物 吃食物
:param food: 食物 :param food: 食物
:return: 吃到食物返回True否则返回False :return: 吃到食物返回True否则返回False
""" """
if self.head.x == food.x and self.head.y == food.y: if self.head.x == food.x and self.head.y == food.y:
tail = self._nodes[-1] tail = self._nodes[-1]
self._nodes.append(tail) self._nodes.append(tail)
return True return True
return False return False
def eat_self(self): def eat_self(self):
"""咬自己""" """咬自己"""
for index in range(4, len(self._nodes)): for index in range(4, len(self._nodes)):
node = self._nodes[index] node = self._nodes[index]
if node.x == self.head.x and node.y == self.head.y: if node.x == self.head.x and node.y == self.head.y:
self._alive = False self._alive = False
def draw(self, screen): def draw(self, screen):
for node in self._nodes: for node in self._nodes:
node.draw(screen) node.draw(screen)
def main(): def main():
def refresh(): def refresh():
"""刷新游戏窗口""" """刷新游戏窗口"""
screen.fill(Color.GRAY) screen.fill(Color.GRAY)
wall.draw(screen) wall.draw(screen)
food.draw(screen) food.draw(screen)
snake.draw(screen) snake.draw(screen)
pygame.display.flip() pygame.display.flip()
def handle_key_event(key_event): def handle_key_event(key_event):
"""处理按键事件""" """处理按键事件"""
key = key_event.key key = key_event.key
if key == pygame.K_F2: if key == pygame.K_F2:
reset_game() reset_game()
elif key in (pygame.K_a, pygame.K_w, pygame.K_d, pygame.K_s): elif key in (pygame.K_a, pygame.K_w, pygame.K_d, pygame.K_s):
if snake.alive: if snake.alive:
if key == pygame.K_w: if key == pygame.K_w:
new_dir = Direction.UP new_dir = Direction.UP
elif key == pygame.K_d: elif key == pygame.K_d:
new_dir = Direction.RIGHT new_dir = Direction.RIGHT
elif key == pygame.K_s: elif key == pygame.K_s:
new_dir = Direction.DOWN new_dir = Direction.DOWN
else: else:
new_dir = Direction.LEFT new_dir = Direction.LEFT
snake.change_dir(new_dir) snake.change_dir(new_dir)
def create_food(): def create_food():
"""创建食物""" """创建食物"""
unit_size = snake.head.size unit_size = snake.head.size
max_row = wall.height // unit_size max_row = wall.height // unit_size
max_col = wall.width // unit_size max_col = wall.width // unit_size
row = randrange(0, max_row) row = randrange(0, max_row)
col = randrange(0, max_col) col = randrange(0, max_col)
return Food(wall.x + unit_size * col, wall.y + unit_size * row, unit_size) return Food(wall.x + unit_size * col, wall.y + unit_size * row, unit_size)
def reset_game(): def reset_game():
"""重置游戏""" """重置游戏"""
nonlocal food, snake nonlocal food, snake
food = create_food() food = create_food()
snake = Snake(250, 290) snake = Snake(250, 290)
def background_task(): def background_task():
nonlocal running, food nonlocal running, food
while running: while running:
if snake.alive: if snake.alive:
refresh() refresh()
clock.tick(10) clock.tick(10)
if snake.alive: if snake.alive:
snake.move() snake.move()
snake.collide(wall) snake.collide(wall)
if snake.eat_food(food): if snake.eat_food(food):
food = create_food() food = create_food()
snake.eat_self() snake.eat_self()
""" """
class BackgroundTask(Thread): class BackgroundTask(Thread):
def run(self): def run(self):
nonlocal running, food nonlocal running, food
while running: while running:
if snake.alive: if snake.alive:
refresh() refresh()
clock.tick(10) clock.tick(10)
if snake.alive: if snake.alive:
snake.move() snake.move()
snake.collide(wall) snake.collide(wall)
if snake.eat_food(food): if snake.eat_food(food):
food = create_food() food = create_food()
snake.eat_self() snake.eat_self()
""" """
wall = Wall(10, 10, 600, 600) wall = Wall(10, 10, 600, 600)
snake = Snake(250, 290) snake = Snake(250, 290)
food = create_food() food = create_food()
pygame.init() pygame.init()
screen = pygame.display.set_mode((620, 620)) screen = pygame.display.set_mode((620, 620))
pygame.display.set_caption('贪吃蛇') pygame.display.set_caption('贪吃蛇')
# 创建控制游戏每秒帧数的时钟 # 创建控制游戏每秒帧数的时钟
clock = pygame.time.Clock() clock = pygame.time.Clock()
running = True running = True
# 启动后台线程负责刷新窗口和让蛇移动 # 启动后台线程负责刷新窗口和让蛇移动
# BackgroundTask().start() # BackgroundTask().start()
Thread(target=background_task).start() Thread(target=background_task).start()
# 处理事件的消息循环 # 处理事件的消息循环
while running: while running:
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.QUIT: if event.type == pygame.QUIT:
running = False running = False
elif event.type == pygame.KEYDOWN: elif event.type == pygame.KEYDOWN:
handle_key_event(event) handle_key_event(event)
pygame.quit() pygame.quit()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

Some files were not shown because too many files have changed in this diff Show More