Python实现简单五子棋人机对战:类设计与算法解析
本文详细解析使用Python实现简单五子棋人机对战的完整过程。通过划分棋子类、棋盘类和策略类,展示面向对象在游戏中的应用。重点介绍了15x15棋盘的构建、坐标解析、随机落子策略以及基于行列和斜线的胜负判定算法,旨在为Python初学者提供清晰的代码结构与逻辑参考。
Python五子棋人机对战实现概述
本文记录使用Python实现简易五子棋人机对战模式的练习过程,供读者参考。
这是首次撰写技术博客,作者力求内容详实准确。
鉴于近期正在学习Python,本文旨在通过具体的五子棋游戏案例,梳理对面向对象编程及基础逻辑的理解。以下内容为在命令行环境(cmd)中运行的实现思路与步骤。
核心实现流程如下:
- 模块与类的架构划分 - 定义棋子类与棋盘类的方法 - 策略类功能细化,并调用棋子和棋盘类 - 实现胜负判断逻辑 - 通过main函数控制游戏整体流程
模块与类的架构划分
模块与类的架构划分
类的划分涉及面向对象编程的核心概念。根据五子棋规则,人与机器交替在棋盘上下棋,任意一方连成五子即获胜。因此,初步将系统划分为棋子类、棋盘类和策略类。每个类独立存放于单独模块,加上主程序模块,共计四个模块。
- 棋子类负责存储棋子的坐标位置及颜色(代表阵营),并提供相应的get和set访问方法。
- 棋盘类负责定义棋盘尺寸及当前状态,同样提供get和set访问方法。
- 棋盘类需具备以下功能:接收并放置棋子、清空棋盘状态、打印显示棋盘以及查询指定位置的状态。
- 策略类与棋盘类一一对应,在构造器中导入并持有棋盘类的实例。
- 策略类的主要功能包括:处理人类玩家落子、计算机自动落子以及判断当前棋局的胜负结果。
棋子类与棋盘类核心实现
棋子类与棋盘类的具体实现
棋子类实现较为简单,主要功能是接收并存储位置与颜色(阵营),并通过接口返回这些信息。其中,位置信息通过元组进行打包传递。
class Chessman(object):
#初始化
def __init__(self):
pass
def set_pos(self,pos):
self.pos = pos
def get_pos(self):
return self.pos
def set_color(self,color):
self.color = color
def get_color(self):
return self.color
棋盘类依赖于棋子类,在此之前需先完成棋盘的初始化设定。棋盘采用列表结构构建,分为两层以支持x和y坐标,棋盘尺寸定义为类属性。
#类属性
board_size =15
#初始化棋盘
def __init__(self):
self.__board = [[0 for i in range(0,Chessboard.board_size+1)] for j in range(0,Chessboard.board_size+1)]
清空棋盘的操作逻辑类似初始化过程。
#清空棋盘,‘+'为棋盘的样子
def init_board(self):
#忽略第0行
for i in range(1,Chessboard.board_size+1):
for j in range(1,Chessboard.board_size+1):
self.__board[i][j] = '+'
打印棋盘的功能也相对直观,需注意在坐标轴旁添加序列号标识:纵坐标范围为1-15,横坐标为a-o。
# 打印棋盘
def print_board(self):
#打印列号
print(' ', end='')
for i in range(1,Chessboard.board_size+1):
c = chr(ord('a') + i-1) # ord 字母转ASCLL码
print(c,end='')
print()
#棋盘
for i in range(1,Chessboard.board_size+1):
if 1<= i <=9:
print(' ', end='')
print(i, end='')
for j in range(1,Chessboard.board_size+1):
print(self.__board[i][j], end='')
print()
运行效果如下图所示。

接下来介绍棋子的放置逻辑:
该功能可分为两个方法实现:一是根据传入的位置和颜色直接放置棋子;二是接收一个棋子类实例,获取其位置和颜色,调用第一个方法并传入相应数值。需注意在传参时进行类型验证。
#写入对应位置的颜色
def set_chess(self,pos, color):
if not isinstance(pos,tuple):
raise RuntimeError('第一个参数必须为元组')
if pos[0] <= 0 or pos[0] > Chessboard.board_size:
raise RuntimeError('行下标越界')
if pos[1] <=0 or pos[1] > Chessboard.board_size:
raise RuntimeError('纵下标越界')
self.__board[pos[0]][pos[1]] = color
#把棋子对象摆放到棋盘上
def set_chessman(self,chessman):
if not isinstance(chessman, Chessman):
raise RuntimeError('类型不对,第一个参数应为ChessMan对象')
pos = chessman.get_pos()
color = chessman.get_color()
self.set_chess(pos,color)
后续根据棋盘位置获取棋子颜色的方法,主要为策略类中的胜负判定提供数据支持。
#根据棋盘位置获取棋子的颜色
def get_chess(self,pos):
if pos[0] <= 0 or pos[0] > Chessboard.board_size:
raise RuntimeError('行下标越界')
if pos[1] <=0 or pos[1] > Chessboard.board_size:
raise RuntimeError('纵下标越界')
return self.__board[pos[0]][pos[1]]
策略类与胜负判定算法
策略类的实现
策略类需调用前两类,涉及更多名称的方法或属性,因此需仔细区分各部分功能。首先,构造器中传入棋盘实例对象。
#初始化要把棋盘对象传入
def __init__(self,chessboard):
self.__chessboard = chessboard
人类玩家下棋时,策略类负责将用户输入的字符串转换为x,y坐标,并生成棋子对象。
def parse_user_input(self,input,chessman):
if not isinstance(chessman,Chessman):
raise RuntimeError('类型不对,第一个参数必须为Chessman对象')
ret = input.split(',')
value1 = ret[0]
value2 = ret[1]
#转换成坐标
pos_x = int(value1)
pos_y = ord(value2) - ord('a') +1
chessman.set_pos((pos_x, pos_y))
#print(ret)
计算机下棋策略:此处暂时使用随机数生成位置(后续可优化,此处略过)。
#电脑下棋的策略
def computer_go(self, chessman):
if not isinstance(chessman,Chessman):
raise RuntimeError('类型不对,第一个参数必须为Chessman对象')
while True:
# pos_x和pos_y在1~15之间随机生成一个数
pos_x = math.ceil(random.random()*Chessboard.board_size)
pos_y = random.randint(1,15)
#判断是否为空,否则重新生成坐标
if self.__chessboard.get_chess((pos_x,pos_y)) == '+':
print('电脑下棋的位置:%d,%d'%(pos_x,pos_y))
chessman.set_pos((pos_x,pos_y))
break
判断当前棋局胜负:每落一子均需判断一次。根据当前落子点的范围,检查其上下左右及两条斜线上是否有连续五子,若有则判定胜利。
斜线方向的坐标范围确定较为复杂,其他方向逻辑类似。以下是经过测试可用的判定方法(特别是斜线部分),目前验证无误,或许存在更优解法:
#判断胜负
#当摆放一个棋子,判断是否赢
def is_won(self,pos,color):
#垂直方向的范围
start_x = 1
end_x = 15
if pos[0] -4 >=1:
start_x =pos[0] - 4
if pos[0] +4 <=15:
end_x = pos[0]+4
#垂直方向的判断
count = 0
for pos_x in range(start_x, end_x+1):
if self.__chessboard.get_chess((pos_x, pos[1])) == color:
count +=1
if count >=5:
return True
else:
# 一旦断开 统计数清0
count = 0
#水平方向的范围
start_y = 1
end_y = 15
if pos[1] -4 >=1:
start_y =pos[1] - 4
if pos[1] +4 <=15:
end_y = pos[1]+4
#水平方向的判断
count = 0
for pos_y in range(start_y, end_y+1):
if self.__chessboard.get_chess((pos[0], pos_y)) == color:
count +=1
if count >=5:
return True
else:
# 一旦断开 统计数清0
count = 0
#左上右下方向判断
count = 0
s=pos[0] - pos[1]
start=start_x
end=end_y+s
if pos[0]>pos[1]:
start=start_y+s
end=end_x
for index in range(start, end+1):
if self.__chessboard.get_chess((index, index-s)) == color:
count +=1
if count >=5:
return True
else:
# 一旦断开 统计数清0
count = 0
#左下右上方向判断
count = 0
s=pos[0] + pos[1]
if pos[0]+pos[1]<=16:
start=start_x
end=s-start_y
if pos[0]+pos[1]>16:
start=s-start_y
end=start_x
if s>=6 and s<=12:
for index in range(start, end+1):
if self.__chessboard.get_chess((index, s-index)) == color:
count +=1
if count >=5:
return True
else:
# 一旦断开 统计数清0
count = 0
return False
随后,通过一个判断胜利方的方法调用上述胜负判定逻辑。
#判断对象放置后,胜负是否已分
def is_wonman(self,chessman):
if not isinstance(chessman,Chessman):
raise RuntimeError('类型不对,第一个参数必须为Chessman对象')
pos = chessman.get_pos()
color = chessman.get_color()
#调用is_won()获取它的返回值
return self.is_won(pos,color)
主程序流程控制
主模块(main模块)的实现
main模块负责控制整个游戏的运行逻辑。main函数实现单局流程,通过循环实现简单的人机轮流下棋。由于增加了用户选择先后手的选项,代码略显繁琐(可进一步精简),此处展示当前版本:
def main():
chessboard =Chessboard()
chessboard.init_board()
chessboard.print_board()
engine = Engine(chessboard)
count=0
select = int(input('用户选择先后:(先:1,后:2)'))
#先
while True:
chessman = Chessman()
chessman.set_color('x')
if select==1:
i = input('人下棋,请输入下棋坐标(格式:x,y):')
engine.parse_user_input(i, chessman)#转换成坐标
else:
#电脑下棋
print('电脑下棋:')
engine.computer_go(chessman)
# 把该棋子对象放到棋盘上
chessboard.set_chessman(chessman)
count +=1
#打印棋盘
chessboard.print_board()
if engine.is_wonman(chessman):
if select==1:
print('人赢了!')
else:
print('电脑赢了!')
break
if count == 225:
print('平局!')
break
#后
chessman = Chessman()
chessman.set_color('o')
if k==1:
#电脑下棋
print('电脑下棋:')
#电脑给棋子生成策略(位置)
engine.computer_go(chessman)
else:
i = input('人下棋,请输入下棋坐标(格式:x,y):')
engine.parse_user_input(i, chessman)#转换成坐标
#下棋
chessboard.set_chessman(chessman)
count +=1
chessboard.print_board()
if engine.is_wonman(chessman):
if k==1:
print('电脑赢了!')
else:
print('人赢了!')
break
if count == 225:
print('平局!')
break
主线程作为程序入口,控制每一局的游戏流程:
if __name__ == '__main__':
while True:
print('开始一局!')
#调用main方法
main()
s=int(input('是否再来一局:(是:1,否:0)'))
if s!=1:
break
print('游戏结束!')
五子棋的简单人机模式即上述内容。需注意,当前代码中输入部分未添加严格校验,因此坐标输入必须严格遵循“数字+逗号+字母”的格式,建议后续可加入正则表达式进行判断。运行效果图如下:



以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









