Python实现简单五子棋人机对战:面向对象设计与核心逻辑解析

阿澈
阿澈
发布时间:2026-10-15| 4人浏览过
原创

本文详细解析使用Python实现简单五子棋人机对战的完整过程。文章基于面向对象思想,将系统划分为棋子类、棋盘类和策略类三个核心模块。重点介绍了15x15棋盘的数据结构构建、坐标解析逻辑以及通过遍历判断五子连珠的胜负算法。代码在CMD环境中运行,展示了从初始化、用户交互到游戏循环控制的完整实现,适合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

判断当前棋局的胜负:每一方落子后均需进行一次判断,因此可根据当前落子点的范围,判断其上下左右及两条斜线上是否有连续五子。若有,则判定胜利。斜线方向的x,y判断范围较为复杂,其他方向逻辑类似。以下是经过详细推导得出的判断方法(特别是斜线部分),目前测试无误,或许存在更优方案:

#判断胜负
    #当摆放一个棋子,判断是否赢
    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 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。