pygame实现井字棋之第二步逻辑实现
本文详解pygame井字棋开发的第二步,重点实现游戏核心逻辑。内容涵盖玩家通过鼠标点击下棋的事件处理、电脑随机落子的算法实现,以及基于列表解析的输赢判断机制。同时介绍了文字渲染、屏幕刷新及界面显示的具体代码实现,为后续逻辑优化奠定基础。
一、前言
在上一篇博客中,我们已经完成了九宫格的视觉绘制工作,这为后续的功能开发奠定了视觉基础。 本次内容将聚焦于游戏核心逻辑的实现,包括判断胜负的条件、玩家与电脑分别下棋的具体流程。
二、下棋
2.1 玩家
我们在之前的Lattice类中,定义了一个stats变量用于表示格子的当前状态。
# 0表示初始,1表示个人-1表示电脑
self.stats = 0
因此,下棋的本质操作就是修改这个stats变量的值。 为了实现通过鼠标点击来下棋的功能,我们需要对事件响应部分进行修改:
for event in pygame.event.get():
# 退出
if event.type == pygame.QUIT:
sys.exit()
# 点击鼠标
elif event.type == pygame.MOUSEBUTTONDOWN:
# 获得鼠标点击的位置
mouse_x, mouse_y = pygame.mouse.get_pos()
for i in rect:
# 确定玩家下了一步
if not i.stats and i.rect.collidepoint(mouse_x,mouse_y):
i.stats = -1
pygame.event模块主要用于处理游戏过程中的各类事件。 第一个事件处理点击界面右上角关闭按钮的情况,触发后退出程序; 第二个事件处理鼠标点击动作,可以通过pygame.mouse.get_pos()获取点击时的坐标位置。 由于之前的格子(Lattice类)中包含一个rect类的实例,我们可以利用collidepoint函数,传入坐标参数来判断点击位置是否落在某个格子内。 随后,我们需要检查该格子是否已被占用;若未被占用,则允许修改stats变量以记录落子。
2.2 电脑
对于电脑而言,逻辑与玩家类似,但这里我们采用随机生成的策略:
def computer():
"""电脑的回合,随机生成一个位置"""
global judge
random_num = [i for i in range(len(rect)) if not rect[i].stats]
# 没位子下了,平局
if not random_num:
judge = 1
print("draw")
exit()
rect[random.choice(random_num)].stats = 1
return #result = Button("your choice")
首先,我们列出所有未被占用的格子,并通过列表解析生成一个可用位置列表。 如果该列表为空,说明棋盘已满,此时判定为平局(每次落子后都会进行胜负判断,具体逻辑稍后详述); 否则,我们使用random.choice函数从列表中随机选择一个元素(该元素为Lattice类的实例),并将其stats值修改为1。
变量judge用于标记游戏是否结束,初始值为0。
三、输赢判断
这部分逻辑可能相对复杂。 我的思路是为每个格子分配一个下标,并预先列出所有可能获胜的格子组合的下标。
win_list = [
# 行
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
# 列
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
# 对角
[0, 4, 8],
[2, 4, 6]
]

接着,我们同样使用列表解析,将所有stats值为1和-1的格子下标分别组成两个列表:
stats1 = [i for i in range(len(rect)) if rect[i].stats == 1]
stats2 = [i for i in range(len(rect)) if rect[i].stats == -1]
这里存在一个问题:stats1和stats2列表中可能只包含部分元素,而这些元素恰好位于win_list中,这让人联想到LeetCode上的算法题。
for i in win_list:
# 取出每一个可能获胜的条件
if i == [j for j in i if j in stats1]:
judge = 1
print("Computer win!")
exit()
elif i == [j for j in i if j in stats2]:
judge = 1
print("You win!")
exit()
我们的逻辑是:针对每一个获胜可能组合,分别取出其中的每一个元素,并在stats列表中进行查找。如果所有元素都能找到,那么列表解析的结果必然与原始的获胜组合完全一致,此时即可判定一方获胜。
四、一人一子
井字棋与五子棋的玩法相似,因此必须确保在玩家下子后,电脑能立即响应并下子。 (虽然正常电脑的反应速度远快于玩家,)
当然,我们可以设置一个变量,用0和1分别表示轮到谁下子,但我有更简洁的选择——直接在玩家下子后调用相关函数。
if not i.stats and i.rect.collidepoint(mouse_x,mouse_y):
# 玩家下棋
i.stats = -1
win_or_lose()
# 电脑下棋
computer()
win_or_lose()
此外,无论哪一方下子,我们都必须对输赢情况进行判断。
五、显示问题
当你完成上述操作后,可能会发现屏幕上没有任何内容显示。 这是因为我们尚未在格子中显示具体的图标。 这里我选择使用经典的'x'和'o'字符,通过渲染文字的方式来实现(这部分也可以自行查找图片进行贴图)。
渲染文字的具体步骤如下:
- 使用self.font = pygame.font.SysFont设置字体。
- 调用self.font.render函数,生成包含文本信息的图像对象。
- 利用get_rect方法处理图像,生成矩形对象以进行对齐操作。
- 使用blit方法将图像渲染到屏幕上。
在lattice.py文件中:
import pygame
class Lattice():
def __init__(self,rect,screen):
self.rect = rect
self.screen = screen
# 0表示初始,1表示个人-1表示电脑
self.stats = 0
# 文本颜色
self.text_color = (30, 30, 30)
# 背景颜色,也就是我们screen渲染的颜色
self.bg_color = (255, 255, 255)
# 设置字体
self.font = pygame.font.SysFont(None,48)
def draw(self):
# 按照状态赋值文本信息
msg = ""
if self.stats == -1:
msg = "x"
elif self.stats == 1:
msg = "o"
if msg:
self.msg_image = self.font.render(msg,True,self.text_color,self.bg_color)
self.msg_rect = self.msg_image.get_rect()
self.msg_rect.center = self.rect.center
self.screen.blit(self.msg_image,self.msg_rect)
render函数说明: 传入参数包括:文本信息、Boolean值(控制曲线是否光滑,此处未测试)、文本颜色、背景颜色(即screen渲染的颜色)。 返回一个图片类型对象。
get_rect()方法说明: 将图片处理为矩形对象。pygame的一个优点是,无论图形形状如何,都可以统一作为矩形处理。
rect对象拥有centerx、centery、x、y等一系列属性,便于进行对齐操作,此处不再展开详述。
blit方法说明: 输入图片和矩形对象(这里的矩形实质上是向方法指明显示的坐标位置), 最终在screen上显示图像。
在主模块中:
def update():
for i in rect:
i.draw()
# 将界面显示
pygame.display.flip()
如果仅在while循环的开始处调用update,会发现无法及时看到结果,这显然会影响体验。因此,我们在每次落子后都会进行一次刷新操作,然后再判断输赢。
if not i.stats and i.rect.collidepoint(mouse_x,mouse_y):
# 玩家下棋
i.stats = -1
update()
win_or_lose()
# 电脑下棋
computer()
update()
win_or_lose()
六、结语
至此,我们的井字棋游戏已基本可以运行,但仍需进行一些细节修改。 在下一篇博客中,我将对代码细节进行整改和优化。
下一篇:pygame实现井字棋——3.逻辑优化 上一篇:pygame实现井字棋——1.绘制九宫格
到此这篇关于pygame实现井字棋之第二步逻辑实现的文章就介绍到这了,更多相关pygame井字棋游戏内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













