基于Python的五子棋人机对战

这篇具有很好参考价值的文章主要介绍了基于Python的五子棋人机对战。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

人机对战

在之前的博文基于tkinter的五子棋游戏中使用tkinter做了一个简单的五子棋游戏,只能实现人人对战,后来想着加上人机对战的功能。
不过,最初想想还是挺麻烦的,计算机怎么评估当前的棋局,找到最佳或者较佳的落子点呢,脑子真是越来越不灵光了。站在巨人的肩膀上,科学技术才在这几百年发展的如此迅速,先看看别人怎么做的吧,果然别人实现起来也就那么几行代码,真是惭愧啊,也感谢这个开源的时代,让我们可以站得更高,看得更远。

计算机算法

计算机根据黑白双方现有落子情况进行棋局评估,给出各空白落子点处的分数。五子棋的几种基本棋形包括连五,活四,冲四,活三,眠三,活二,眠二等,不同的棋形打不同的分数。这个分数不但要考虑到了己方的棋子,还要考虑对方的局势,即要分别给双方打分,并求和,这样就兼具了攻击和防守的能力。不过,这里算法上与原算法相比略去一部分,这大概也导致了这个计算机有点傻😂
对于空位的遍历也是很费资源的,所以这里参考了引用博文中做法,仅遍历了已有棋子周边的空位。

源码

保留了原程序的架构,有些地方又偷懒,所以代码有点乱

from tkinter import *
import random

offset = [(1, 0), (0, 1), (1, 1), (1, -1)]


class GoBang():
    def __int__(self):
        self.window = Tk()
        self.window.title("五子棋")
        self.window.iconbitmap('./gobang.ico')
        self.window.geometry("500x560")
        self.window.canvas = Canvas(self.window, width=480, height=480, bg='peachpuff')
        self.window.canvas.pack()
        for num in range(1, 16):
            if num == 1 or num == 15:
                self.window.canvas.create_line(num * 30, 30,
                                               num * 30, 450,
                                               width=2)
            else:
                self.window.canvas.create_line(num * 30, 30,
                                               num * 30, 450,
                                               width=1)
        for num in range(1, 16):
            if num == 1 or num == 15:
                self.window.canvas.create_line(30, num * 30,
                                               450, num * 30,
                                               width=2)
            else:
                self.window.canvas.create_line(30, num * 30,
                                               450, num * 30,
                                               width=1)

        self.window.canvas.create_oval(8 * 30 - 2, 8 * 30 - 2, 8 * 30 + 2,
                                       8 * 30 + 2, fill='black')
        self.window.canvas.create_oval(5 * 30 - 2, 5 * 30 - 2, 5 * 30 + 2,
                                       5 * 30 + 2, fill='black')
        self.window.canvas.create_oval(5 * 30 - 2, 11 * 30 - 2, 5 * 30 + 2,
                                       11 * 30 + 2, fill='black')
        self.window.canvas.create_oval(11 * 30 - 2, 5 * 30 - 2, 11 * 30 + 2,
                                       5 * 30 + 2, fill='black')
        self.window.canvas.create_oval(11 * 30 - 2, 11 * 30 - 2, 11 * 30 + 2,
                                       11 * 30 + 2, fill='black')
        self.startBtn = Button(self.window, text='Start', bg="DeepSkyBlue", width=8, height=1, command=self.chessGo)
        self.quitBtn = Button(self.window, text='Quit', bg="OrangeRed", width=8, height=1, command=self.window.quit)
        self.withDrawBtn = Button(self.window, text='Withdraw', bg="cyan", width=8, height=1, command=self.withDraw)
        self.startBtn.place(relx=0.2, rely=0.89)
        self.quitBtn.place(relx=0.6, rely=0.89)
        self.withDrawBtn.place(relx=0.4, rely=0.89)

        self.game_print = StringVar()
        self.labelInfo = Label(self.window, width=12, textvariable=self.game_print, font=("Arial", 10, "bold"),
                               justify="center")
        self.labelInfo.place(relx=0.36, rely=0.95)
        self.window.canvas.bind("<Button-1>", self.place)
        self.game_print.set("请开始新局")
        self.chess = [([0] * 15) for i in range(15)]
        # 悔棋用的顺序列表
        self.order = []

        # 棋子颜色
        self.color_count = 0
        self.color = 'black'

        self.flag_win = 0
        self.flag_go = 0

        self.window.mainloop()

    def chessGo(self):
        if self.startBtn['text'] == "Start":
            #
            self.flag_go = 1
            self.startBtn['text'] = "Going"
            self.game_print.set('请black落子')
            self.labelInfo['fg'] = 'black'

        elif self.startBtn['text'] == "New":
            self.startBtn['text'] = "Start"
            self.newGame()

    def newGame(self):
        self.window.canvas.delete("chessman")
        self.chess = [([0] * 15) for i in range(15)]
        self.order = []
        self.color_count = 0
        self.color = 'black'
        self.flag_win = 0
        self.flag_go = 0
        self.game_print.set('请开始新局')
        self.labelInfo['fg'] = 'black'

    def withDraw(self):
        if len(self.order) == 0 or self.flag_win == 1:
            self.game_print.set("Can't Withdraw")
            self.labelInfo['fg'] = 'sandybrown'
            return
        else:
            self.window.canvas.delete("chessman")
            # add for machine
            xylist = self.order.pop()
            self.chess[xylist[0]][xylist[1]] = 0
            #####
            xylist = self.order.pop()
            self.chess[xylist[0]][xylist[1]] = 0
            self.color_count = 0
            for xylist in self.order:
                y = xylist[0]
                x = xylist[1]
                if self.color_count == 0:
                    self.chess[y][x] = 1
                    self.color = 'black'

                elif self.color_count == 1:
                    self.chess[y][x] = 2
                    self.color = 'white'
                self.color_count = 1 - self.color_count
                self.window.canvas.create_oval((x + 1) * 30 - 12, (y + 1) * 30 - 12, (x + 1) * 30 + 12,
                                               (y + 1) * 30 + 12, fill=self.color,
                                               tags="chessman")
            if self.color_count:
                self.color = 'white'
            else:
                self.color = 'black'
            self.game_print.set("请" + self.color + "落子")
            self.labelInfo['fg'] = 'black'

    def place(self, event):
        if (self.flag_win == 0 and self.flag_go == 1):
            print("enter place")
            x, y = event.x, event.y
            x = round(x / 30 - 1)
            y = round(y / 30 - 1)
            if x < 0 or x > 14 or y < 0 or y > 14:
                #            tkinter.messagebox.INFO('提示', '请在棋盘上落子!')
                self.game_print.set('越界落子!')
                self.labelInfo['fg'] = "darkorange"
                return
            # add for machine 221109
            self.color_count = 0
            if self.chess[y][x] == 0:
                print("enter paint oval")
                if self.color_count == 0:
                    self.chess[y][x] = 1
                    self.color = 'black'

                elif self.color_count == 1:
                    self.chess[y][x] = 2
                    self.color = 'white'
                self.color_count = 1 - self.color_count
                self.window.canvas.create_oval((x + 1) * 30 - 12, (y + 1) * 30 - 12, (x + 1) * 30 + 12,
                                               (y + 1) * 30 + 12, fill=self.color,
                                               tags="chessman")
                self.order.append([y, x])
            else:
                #            tkinter.messagebox.INFO('提示', '此处已有棋子!')
                self.game_print.set('请别处落子!')
                self.labelInfo['fg'] = "darkorange"
                return

            if self.win(x, y):
                self.flag_win = 1
                self.startBtn['text'] = "New"
                if self.color_count == 1:
                    self.color = 'black'

                else:
                    self.color = 'white'
                    # self.messagebox.INFO('提示', '白棋胜!')
                self.game_print.set(self.color + "胜!")
                self.labelInfo['fg'] = "red"

            else:
                if self.color_count:
                    self.color = 'white'
                else:
                    self.color = 'black'

                self.game_print.set("请" + self.color + "落子")
                self.labelInfo['fg'] = "black"
                point = self.machine_drop()

                y = point[0]
                x = point[1]
                self.chess[y][x] = 2
                self.color = 'white'
                self.color_count = 0

                self.window.canvas.create_oval((x + 1) * 30 - 12, (y + 1) * 30 - 12, (x + 1) * 30 + 12,
                                               (y + 1) * 30 + 12, fill=self.color,
                                               tags="chessman")
                self.order.append([y, x])

                if self.win(x, y):
                    self.flag_win = 1
                    self.startBtn['text'] = "New"
                    if self.color_count == 1:
                        self.color = 'black'

                    else:
                        self.color = 'white'
                        # self.messagebox.INFO('提示', '白棋胜!')
                    self.game_print.set(self.color + "胜!")
                    self.labelInfo['fg'] = "red"
                else:
                    if self.color_count:
                        self.color = 'white'
                    else:
                        self.color = 'black'

                    self.game_print.set("请" + self.color + "落子")
                    self.labelInfo['fg'] = "black"
    def machine_drop(self):

        _score = 0
        point = [-1,-1]
        for i in range(0,15):
            for j in range(0,15):
                if self.can_drop(i,j):
                    score = self.get_point_score(i,j)
                    print(i,j,score)
                    if score > _score:
                        point[0] = i
                        point[1] = j
                        _score = score
                    elif score == _score:
                        r = random.randint(0, 100)
                        if r % 2 == 0:
                            point[0] = i
                            point[1] = j
        print(point)
        return point

    def can_drop(self, y, x):
        if self.chess[y][x] != 0:
            return False
        else:
            for i in (-1, 0, 1):
                for j in (-1, 0, 1):
                    if y + i >= 0 and y + i <= 14 and x + j >= 0 and x + j <= 14:
                        if self.chess[y + i][x + j] != 0:
                            return True
        return False

    def get_point_score(self, y, x):
        score = 0
        for os in offset:
            score += self.get_direction_score(y, x, os[0], os[1])
        return score

    def get_direction_score(self, y, x, y_offset, x_offset):
        count = 0  # 落子处我方连续子数
        _count = 0  # 落子处对方连续子数
        space = None  # 我方连续子中有无空格
        _space = None  # 对方连续子中有无空格
        both = 0  # 我方连续子两端有无阻挡
        _both = 0  # 对方连续子两端有无阻挡

        tmp_x = x
        tmp_y = y
        # 如果是 2 表示是边上是我方子,1 表示敌方子
        if 0 <= y+y_offset <=14 and 0 <= x + x_offset <=14:
            flag = self.chess[y + y_offset][x + x_offset]
            if flag != 0:
                for step in range(1, 6):
                    x += x_offset
                    y += y_offset
                    if 0 <= x < 15 and 0 <= y < 15:
                        if flag == 2:
                            if self.chess[y][x] == 2:
                                count += 1
                                if space is False:
                                    space = True
                            elif self.chess[y][x] == 1:
                                _both += 1
                                break
                            else:
                                if space is None:
                                    space = False
                                else:
                                    break  # 遇到第二个空格退出
                        elif flag == 1:
                            if self.chess[y][x] == 2:
                                _both += 1
                                break
                            elif self.chess[y][x] == 1:
                                _count += 1
                                if _space is False:
                                    _space = True
                            else:
                                if _space is None:
                                    _space = False
                                else:
                                    break
                    else:
                        # 遇到边也就是阻挡
                        if flag == 2:
                            both += 1
                        elif flag == 1:
                            _both += 1

            if space is False:
                space = None
            if _space is False:
                _space = None

        x = tmp_x
        y = tmp_y
        if 0 <= y - y_offset <= 14 and 0 <= x - x_offset <= 14:
            _flag = self.chess[y - y_offset][x - x_offset]
            if _flag != 0:
                for step in range(1, 6):
                    x -= x_offset
                    y -= y_offset
                    if 0 <= x < 15 and 0 <= y < 15:
                        if _flag == 2:
                            if self.chess[y][x] == 2:
                                count += 1
                                if space is False:
                                    space = True
                            elif self.chess[y][x] == 1:
                                _both += 1
                                break
                            else:
                                if space is None:
                                    space = False
                                else:
                                    break  # 遇到第二个空格退出
                        elif _flag == 1:
                            if self.chess[y][x] == 2:
                                _both += 1
                                break
                            elif self.chess[y][x] == 1:
                                _count += 1
                                if _space is False:
                                    _space = True
                            else:
                                if _space is None:
                                    _space = False
                                else:
                                    break
                    else:
                        # 遇到边也就是阻挡
                        if _flag == 1:
                            both += 1
                        elif _flag == 2:
                            _both += 1

        score = 0
        if count == 4:
            score = 10000
        elif _count == 4:
            score = 9000
        elif count == 3:
            if both == 0:
                score = 1000
            elif both == 1:
                score = 100
            else:
                score = 0
        elif _count == 3:
            if _both == 0:
                score = 900
            elif _both == 1:
                score = 90
            else:
                score = 0
        elif count == 2:
            if both == 0:
                score = 100
            elif both == 1:
                score = 10
            else:
                score = 0
        elif _count == 2:
            if _both == 0:
                score = 90
            elif _both == 1:
                score = 9
            else:
                score = 0
        elif count == 1:
            score = 10
        elif _count == 1:
            score = 9
        else:
            score = 0

        if space or _space:
            score /= 2

        return score

    def win(self, x, y):
        count = 1
        # -计算
        for i in range(-1, -5, -1):
            if x + i < 0:
                break
            else:
                if self.chess[y][x + i] == self.chess[y][x]:
                    count += 1
                else:
                    break
        for i in range(1, 5, 1):
            if x + i > 14:
                break
            else:
                if self.chess[y][x + i] == self.chess[y][x]:
                    count += 1
                else:
                    break
        if count >= 5:
            return True
        # |计算
        count = 1
        for i in range(-1, -5, -1):
            if y + i < 0:
                break
            else:
                if self.chess[y + i][x] == self.chess[y][x]:
                    count += 1
                else:
                    break
        for i in range(1, 5, 1):
            if y + i > 14:
                break
            else:
                if self.chess[y + i][x] == self.chess[y][x]:
                    count += 1
                else:
                    break
        if count >= 5:
            return True
        # /计算
        count = 1
        for i in range(-1, -5, -1):
            if y + i < 0 or x + i < 0:
                break
            else:
                if self.chess[y + i][x + i] == self.chess[y][x]:
                    count += 1
                else:
                    break
        for i in range(1, 5, 1):
            if y + i > 14 or x + i > 14:
                break
            else:
                if self.chess[y + i][x + i] == self.chess[y][x]:
                    count += 1
                else:
                    break
        if count >= 5:
            return True
        # \计算
        count = 1
        for i in range(-1, -5, -1):
            if y + i < 0 or x - i > 14:
                break
            else:
                if self.chess[y + i][x - i] == self.chess[y][x]:
                    count += 1
                else:
                    break
        for i in range(1, 5, 1):
            if y + i > 14 or x - i < 0:
                break
            else:
                if self.chess[y + i][x - i] == self.chess[y][x]:
                    count += 1
                else:
                    break
        if count >= 5:
            return True


if __name__ == "__main__":
    myBang = GoBang()
    myBang.__int__()

运行结果

人机对战取代了人人对战,不是可选模式,人执黑先手,计算机执白后手,可以悔棋。
基于Python的五子棋人机对战

引用

看了不少博文,有些算法应该出自一处,谢谢!
1.Python五子棋人机对战
2.python五子棋之人机对战
3.基于java的人机五子棋文章来源地址https://www.toymoban.com/news/detail-443554.html

到了这里,关于基于Python的五子棋人机对战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 实现对战AI五子棋

     个人主页: 日刷百题 系列专栏 : 〖C/C++小游戏〗 〖Linux〗 〖数据结构〗   〖 C语言 〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ ​      为了能够快速上手一门语言,我们往往在学习了基本语法后,采用写一个小项目的方式来加深理解语言的语法及运用,本文采

    2024年02月03日
    浏览(55)
  • 【项目设计】网络对战五子棋(上)

    想回家过年… 1.1 http1.0/1.1和websocket协议 1. a. http协议在Linux的学习部分我们就已经学习过了,当时http和https是一块学的,我们当时其实已经了解了http的大部分知识内容,比如http请求和响应的格式,各自的报头字段都有哪些,cookie和session机制,http1.1的长连接策略keep-alive,还有

    2024年02月07日
    浏览(50)
  • C++项目:网络版本在线五子棋对战

    目录 1.项目介绍 2.开发环境 3.核心技术 4. 环境搭建 5.websocketpp 5.1原理解析 5.2报文格式  5.3websocketpp常用接口介绍 5.4websocket服务器 6.JsonCpp使用 6.1Json数据格式 6.2JsonCpp介绍 7.MySQL API 7.1MySQL API介绍 7.2MySQL API使用 7.3实现增删改查操作 8.项目结构设计 8.1项目模块划分说明 8.2业务处

    2024年02月10日
    浏览(51)
  • Linux项目实战——五子棋(单机人人对战版)

    Linux操作系统项目实战——五子棋 GIF: 目录            Linux操作系统项目——五子棋 一、问题导引: 二、实现要求: 三、五子棋原理: 1.落子数据信息保存载体: 2.落子思路: 3.判断“五子连珠” 四、项目实现步骤: Ⅰ.创建目录及文件: 1.在Linux环境下创建名为Gobang的文

    2024年02月03日
    浏览(53)
  • C++项目:在线五子棋对战网页版--匹配对战模块开发

    玩家匹配是根据自己的天梯分数进行匹配的,而服务器中将玩家天梯分数分为三个档次: 1. 普通:天梯分数小于2000分 2. 高手:天梯分数介于2000~3000分之间 3. 大神:天梯分数大于3000分 当玩家进行对战匹配时,服务器会根据档次,将玩家送到不同档次的匹配队列当中。共有

    2024年02月13日
    浏览(37)
  • C++在线五子棋对战(网页版)项目:websocket协议

    目标:认识理解websocket协议、websocket切换过程和websocket协议格式。认识和学会使用websocketpp库常用接口。了解websocketpp库搭建服务器流程,认识和学会使用websocketpp库bin接口,最后使用websocketpp库搭建服务器。 平时我们在逛某宝,点击商品查看商品信息,从HTTP角度来看,就是客

    2024年02月13日
    浏览(53)
  • C++项目:在线五子棋对战网页版--数据模块开发

    数据管理模块,基于mysql数据库进行数据管理以及封装数据管理模块实现数据库访问。因此,在数据库中,我需要为每一张表创建出对应类,通过类实例化的对象来访问这张数据库表中的数 据,这样的话当我们要访问哪张表的时候,使⽤哪个类实例化的对象即可。 那么在五子

    2024年02月13日
    浏览(35)
  • JAVA五子棋手机网络对战游戏的设计与实现(源代码+论文)

    在现代社会中,手机及其它无线设备越来越多的走进普通老百姓的工作和生活。 随着3G技术的普及与应用,基于Java开发的软件在手机上的使用非常的广泛,手机增值服务的内容也是越来越多,对丰富人们的生活内容、提供快捷的资讯起着不可忽视的作用。 本文基于J2ME技术,以

    2024年02月09日
    浏览(46)
  • 网页版Java(Spring/Spring Boot/Spring MVC)五子棋项目(四)对战模块

    匹配成功返回数据 1. message消息类别 2. ok 3. reson 4. 房间id 5. 双方id 6.白色玩家 一个类记录房间中的信息(房间id,两个用户id,是否为白棋) 信息提示框 处理匹配API 初始化游戏(棋盘,下一个棋子,接受棋子处理响应,判断是否结束) 1. 客户端连接到游戏房间后, 服务器返回

    2024年02月13日
    浏览(52)
  • 2.6.C++项目:网络版五子棋对战之数据管理模块-游戏房间管理模块的设计

    对匹配成功的玩家创建房间,建立起一个小范围的玩家之间的关联关系! 房间里一个玩家产生的动作将会广播给房间里的其他用户。 将这些房间管理起来,以便于进行房间生命周期的控制! 游戏房间类: // 实现两个部分: // 1. 房间的设计 // 2. 房间管理的设置 // 游戏房间的

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包