Python实现简单五子棋人机对战:类设计与算法解析

洛溪
洛溪
发布时间:2026-10-13 | 4人浏览过
原创

本文详细解析使用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('游戏结束!') 

五子棋的简单人机模式即上述内容。需注意,当前代码中输入部分未添加严格校验,因此坐标输入必须严格遵循“数字+逗号+字母”的格式,建议后续可加入正则表达式进行判断。运行效果图如下:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表