Python写五⼦棋游戏(附完整源代码)
开端
开端
画棋盘
⾸先肯定是要画出棋盘来,⽤ pygame 画出⼀个 19 × 19 或 15 × 15 的棋盘并不是什么难事,这在之前的⽂章中已经多次⽤到,就不赘述了。
画棋⼦
cssci来源期刊扩展版是什么意思需要说⼀下的是画棋⼦,因为没到什么合适的棋⼦图⽚,所以只要⾃⼰来画棋⼦。
我们⽤ pygame.draw.circle 画出来的圆形是这样的:
很多⼈学习python,掌握了基本语法过后,不知道在哪⾥寻案例上⼿。
很多已经做案例的⼈,却不知道如何去学习更加⾼深的知识。
那么针对这三类⼈,我给⼤家提供⼀个好的学习平台,免费领取视频教程,电⼦书籍,以及课程的源代码!
QQ:701698587
锯齿状⼗分明显,pygame.draw 中有画抗锯齿直线的函数 aaline,但是并没有 aacircle 这样的函数来画⼀个抗锯齿的圆。
这⾥就需要⽤到 pygame.gfxdraw 啦。pygame.gfxdraw ⽬前还仅是实验版本,这意味着这个 API 可能会在以后的 pygame 版本中发⽣变化或消失。
要绘制抗锯齿和填充形状,请⾸先使⽤函数的aa *版本,然后使⽤填充版本。例如:
col = (255, 0, 0)
surf.fill((255, 255, 255))
pygame.gfxdraw.aacircle(surf, x, y, 30, col)
pygame.gfxdraw.filled_circle(surf, x, y, 30, col)
我们⽤这个⽅法在棋盘上画⼀个棋⼦试试看。
可以看到效果已明显改善。
落⼦
落⼦需要判断⿏标事件,当⿏标左键点击,获取⿏标点击的位置,然后根据棋盘的位置,计算出棋⼦落在棋盘的位置。
while True:c语言程序设计双版
for event in ():
pe == QUIT:
pe == MOUSEBUTTONDOWN:
pressed_array = _pressed()
if pressed_array[0]: # ⿏标左键点击
mouse_pos = _pos()winform progressbar
click_point = _get_clickpoint(mouse_pos)
胜利判定
当⼀⼦落下,如何判定是否胜利?
可以肯定的是,当某⼀⼦落下的时候,如果出现了 5 连,那么落下的这颗⼦必定在这条 5 连线上。那么这个问题就可以简化了,我们⽆需全盘扫描,只需要在落⼦位置上横竖撇捺扫描⼀下,判断是否出现 5 连即可。
我们定义⼀个棋盘类,类中实例化⼀个 19 × 19 的⼆维数组,初始值皆为 0,表⽰空,⽤ 1 表⽰⿊⼦,
2 表⽰⽩⼦。这个类对外提供⼀个落⼦⽅法 drop,接收参数落⼦⽅和落⼦坐标,如果落⼦后胜利,则返回胜利者,否则返回 None。
Chessman = namedtuple('Chessman', 'Name Value Color')
Point = namedtuple('Point', 'X Y')
BLACK_CHESSMAN = Chessman('⿊⼦', 1, (45, 45, 45))
WHITE_CHESSMAN = Chessman('⽩⼦', 2, (219, 219, 219))
offset = [(1, 0), (0, 1), (1, 1), (1, -1)]
class Checkerboard:
def __init__(self, line_points):
self._line_points = line_points
python教程电子版书籍self._checkerboard = [[0] * line_points for _ in range(line_points)]
def _get_checkerboard(self):
return self._checkerboard
checkerboard = property(_get_checkerboard)
# 判断是否可落⼦
def can_drop(self, point):
return self._checkerboard[point.Y][point.X] == 0
def drop(self, chessman, point):
"""
落⼦
:param chessman: ⿊⼦/⽩⼦
:param point:落⼦位置
:return:若该⼦落下之后即可获胜,则返回获胜⽅,否则返回 None
"""
print(f'{chessman.Name} ({point.X}, {point.Y})')
self._checkerboard[point.Y][point.X] = chessman.Value
if self._win(point):
print(f'{chessman.Name}获胜')
return chessman
# 判断是否赢了
def _win(self, point):
cur_value = self._checkerboard[point.Y][point.X]
for os in offset:
if self._get_count_on_direction(point, cur_value, os[0], os[1]):
return True
def _get_count_on_direction(self, point, value, x_offset, y_offset):
count = 1
for step in range(1, 5):
x = point.X + step * x_offset
y = point.Y + step * y_offset
if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: count += 1
else:
break
for step in range(1, 5):
x = point.X - step * x_offset
y = point.Y - step * y_offset
if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: count += 1
else:
break
return count >= 5
这⾥我定义了⼀个偏移量,我们⼀共要计算横竖撇捺 4 条线,任意⼀条线出现 5 连就算获胜。计算⽅法实际上是⼀样的,只是⽅向不同,所以定义⼀个偏移量数组,不同的偏移量表⽰不同的⽅向,这样就可以利⽤循环来实现了,节省了很多代码。
电脑落⼦
这就是全篇的重头戏了,要怎么教电脑下五⼦棋。
⾸先声明,我⽤的是相对传统的⽅式,不是深度学习。
五⼦棋就是要实现 5 连,所以,⼀开始,我的想法是:将所有连线保存在⼀个数组中,落⼦的时候选择最长的连线落⼦。但这样有个问题解决不掉,如何让电脑识别“三三”呢?
后来⽹上看到篇⽂章,使⽤的⽅法是:遍历棋盘上的空位,计算每⼀个位置其横竖撇捺 8 个⽅向上是否有⼰⽅的⼦,有⼀个就加 10 分,最后选得分最⾼的位置落⼦。
这样不太严谨,写出来的电脑估计⽔平很菜,但是这个思路却是对的,落⼦就是要到最值得的地⽅,那么我们⼲脆对每⼀个可落⼦的地⽅来做⼀个评估,选出最优解。
这⾥我们需要了解⼀下五⼦棋的⼏种基本棋形:连五,活四,冲四,活三,眠三,活⼆,眠⼆。
连五
顾名思义,五颗同⾊棋⼦连在⼀起,赢了
while和but的区别
活四
四颗同⾊棋⼦连在⼀起,并且左右两边都没有对⽅棋⼦阻挡,有两个连五点。
冲四
四颗同⾊棋⼦连在⼀起,并且⼀边有对⽅棋⼦阻挡,或者四颗棋⼦不是连的,当中有个空挡,这时只有⼀个连五点。
活三、跳活三
活⼆和眠⼆
活⼆,能够形成活三的⼆;眠⼆,能够形成眠三的⼆。这⾥就不放图了,参考活三眠三。
打分机制
理解了这些棋形,那么按我们之前的思路,就是如何打分了。
⾸先,连五肯定是不存在的,出现连五胜负已分,所以只要棋局还在进⾏中,就不会出现连五。那么,什么优先级最⾼?⾃然就是活四了。
其次是对⽅的“四”,对⽅活四,你防不防都⼀样输了,对⽅冲四,你就必须防守。
再次是我⽅的活三或冲四,活三跟冲四其实是⼀个级别的,对⽅必须防守。
再次是对⽅的活三或冲四。
以此类推下去。我们可以总结⼀点规律:
相同的棋形,我⽅优于对⽅。
冲四跟活三⼀个级别,眠三跟活⼆⼀个级别。
如果中间有空格的话,肯定是要⽐没空格的略微低级⼀点,但不⾄于降级。
基本逻辑就是这样,这⼀块的代码我写得也不好,整个判断写了100多⾏,就不贴代码了,⼤家可以直接下源码看。
信捷c语言五⼦棋执⿊是必赢的,代码中,玩家就是执⿊先⼿,电脑执⽩后⼿,所以,下的好是完全可以赢电脑的,不过⼀个⼩⼩失误也很可能被电脑翻盘。
全部源码:
ManAndMachine.py
"""五⼦棋之⼈机对战"""
import sys
import random
import pygame
from pygame.locals import *
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论