[人工智能]实现自我学习,五子棋

初学机器学习,从分类到聚类,从朴素贝叶斯到SVM,从神经网络到深度学习,各种神秘的项目,但是感觉干的各种事情离我们生活还是太远了。最近AlphaGo Zero的发布,深度学习又火了一把,小伙伴们按捺不住内心的躁动,要搞一个游戏AI,好吧,那就从规则简单、老少皆宜的五子棋开始学起。工欲善其事必先利其器,要实现五子棋的AI,连棋都没有,AI个锤子!

  • 简介五子棋

五子棋分为有禁手和无禁手,我们先实现一个普通版本的无禁手版本作为例子,因为这个不影响我们实现一个AI。补充说明一下,无禁手黑棋必胜,经过比赛和各种研究,人们逐渐知道了这个事实就开始想办法来限制黑棋先手优势。于是出现了有禁手规则,规定黑棋不能下三三,四四和长连。但随着比赛的结果的研究的继续进行,发现其实即使是对黑棋有禁手限制,还是不能阻止黑棋开局必胜的事实,像直指开局中花月,山月,云月,溪月,寒星等,斜指开局中的名月,浦月,恒星,峡月,岚月都是黑棋必胜。于是日本人继续提出了交换和换打的思想,到了后来发展成了国际比赛中三手交换和五手二打规则,防止执黑者下出必胜开局或者在第五手下出必胜打。所以结论是,在不正规的比赛规则或者无禁手情况下,黑棋必胜是存在的。

  • 实现五子棋

这里用Python来实现,因为之后的机器学习库也是Python的,方便一点。界面和逻辑要分开,解耦合,这个是毋庸置疑的,并且之后还要训练AI,分离这是必须的。所以我们先来实现一个五子棋的逻辑。我们先来考虑五子棋是一个15*15的棋盘,棋盘上的每一个交叉点(或格子)上一共会有3种状态:空白、黑棋、白棋,所以先建个文件 consts.py
做如下定义:

from enum import Enum
N = 15
class ChessboardState(Enum):EMPTY = 0BLACK = 1WHITE = 2

棋盘的状态,我们先用一个15*15的二维数组chessMap来表示,建一个类 gobang.py文件,currentI、currentJ、currentState 分别表示当前这步着棋的坐标和颜色,再定义一个get和set函数,最基本的框架就出来了,代码如下:

from enum import Enum
from consts import *
class GoBang(object):def __init__(self):self.__chessMap = [[ChessboardState.EMPTY for j in range(N)] for i in range(N)]self.__currentI = -1self.__currentJ = -1self.__currentState = ChessboardState.EMPTYdef get_chessMap(self):return self.__chessMapdef get_chessboard_state(self, i, j):return self.__chessMap[i][j]def set_chessboard_state(self, i, j, state):self.__chessMap[i][j] = stateself.__currentI = iself.__currentJ = jself.__currentState = state

这样界面端可以调用get函数来获取各个格子的状态来决定是否绘制棋子,以及绘制什么样的棋子;每次下棋的时候呢,在对应的格子上,通过坐标来设置棋盘Map的状态。
所以最基本的展示和下棋,上面的逻辑就够了,接下来干什么呢,得考虑每次下棋之后,set了对应格子的状态,是不是需要判断当前有没有获胜。所以还需要再加两个函数来干这个事情,思路就是从当前位置从东、南、西、北、东南、西南、西北、东北8个方向,4根轴,看是否有连续的大于5颗相同颜色的棋子出现。假设我们目前落子在棋盘正中,需要判断的位置如下图所示的米字形。

那代码怎么写呢,最最笨的办法,按照字面意思来翻译咯,比如横轴,先看当前位置左边有多少颗连续同色的,再看右边有多少颗连续同色的,左边加右边,就是当前横轴上的连续数,如果大于5,则胜利。

def have_five(self, current_i, current_j):#四个方向计数 竖 横 左斜 右斜hcount = 1temp = ChessboardState.EMPTY#H-左for j in range(current_j - 1, -1, -1):  #横向往左 from (current_j - 1) to 0temp = self.__chessMap[current_i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakhcount = hcount + 1#H-右for j in range(current_j + 1, N):  #横向往右 from (current_j + 1) to Ntemp = self.__chessMap[current_i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakhcount = hcount + 1#H-结果if hcount >= 5:return True

以此类推,再看竖轴、再看左斜、再看又斜,于是,have_five函数变成这样了:

def have_five(self, current_i, current_j):#四个方向计数 竖 横 左斜 右斜hcount = 1vcount = 1lbhcount = 1rbhcount = 1temp = ChessboardState.EMPTY#H-左for j in range(current_j - 1, -1, -1):  #横向往左 from (current_j - 1) to 0temp = self.__chessMap[current_i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakhcount = hcount + 1#H-右for j in range(current_j + 1, N):  #横向往右 from (current_j + 1) to Ntemp = self.__chessMap[current_i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakhcount = hcount + 1#H-结果if hcount >= 5:return True#V-上for i in range(current_i - 1, -1, -1):  # from (current_i - 1) to 0temp = self.__chessMap[i][current_j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakvcount = vcount + 1#V-下for i in range(current_i + 1, N):  # from (current_i + 1) to Ntemp = self.__chessMap[i][current_j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakvcount = vcount + 1#V-结果if vcount >= 5:return True#LB-上for i, j in zip(range(current_i - 1, -1, -1), range(current_j - 1, -1, -1)):  temp = self.__chessMap[i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breaklbhcount = lbhcount + 1#LB-下for i, j in zip(range(current_i + 1, N), range(current_j + 1, N)):  temp = self.__chessMap[i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breaklbhcount = lbhcount + 1#LB-结果if lbhcount >= 5:return True#RB-上for i, j in zip(range(current_i - 1, -1, -1), range(current_j + 1, N)):  temp = self.__chessMap[i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakrbhcount = rbhcount + 1#RB-下for i, j in zip(range(current_i + 1, N), range(current_j - 1, -1, -1)):  temp = self.__chessMap[i][j]if temp == ChessboardState.EMPTY or temp != self.__currentState:breakrbhcount = rbhcount + 1#LB-结果if rbhcount >= 5:return True

这样是不是就写完了,五子棋的逻辑全部实现~

  • 重构五子棋

NO,别高兴得太早,我想说,我好恶心,上面那个代码,简直丑爆了,再看一眼,重复的写了这么多for,这么多if,这么多重复的代码块,让我先去吐会儿……
好了,想想办法怎么改,至少分了4根轴,是重复的对不对,然后每根轴分别从正负两个方向去统计,最后加起来,两个方向,也是重复的对不对。于是我们能不能只写一个方向的代码,分别调2次,然后4根轴,分别再调4次,2*4=8,一共8行代码搞定试试。因为有45°和135°这两根斜轴的存在,所以方向上应该分别从x和y两个轴来控制正负,于是可以这样,先写一个函数,按照方向来统计:
xdirection=0,ydirection=1 表示从y轴正向数;
xdirection=0,ydirection=-1 表示从y轴负向数;
xdirection=1,ydirection=1 表示从45°斜轴正向数;
……
不一一列举了,再加上边界条件的判断,于是有了以下函数:

def count_on_direction(self, i, j, xdirection, ydirection, color):count = 0for step in range(1, 5): #除当前位置外,朝对应方向再看4步if xdirection != 0 and (j + xdirection * step < 0 or j + xdirection * step >= N):breakif ydirection != 0 and (i + ydirection * step < 0 or i + ydirection * step >= N):breakif self.__chessMap[i + ydirection * step][j + xdirection * step] == color:count += 1else:breakreturn count

于是乎,前面的have_five稍微长的好看了一点,可以变成这样:

def have_five(self, i, j, color):#四个方向计数 竖 横 左斜 右斜hcount = 1vcount = 1lbhcount = 1rbhcount = 1hcount += self.count_on_direction(i, j, -1, 0, color)hcount += self.count_on_direction(i, j, 1, 0, color)if hcount >= 5:return Truevcount += self.count_on_direction(i, j, 0, -1, color)vcount += self.count_on_direction(i, j, 0, 1, color)if vcount >= 5:return Truelbhcount += self.count_on_direction(i, j, -1, 1, color)lbhcount += self.count_on_direction(i, j, 1, -1, color)if lbhcount >= 5:return Truerbhcount += self.count_on_direction(i, j, -1, -1, color)rbhcount += self.count_on_direction(i, j, 1, 1, color)if rbhcount >= 5:return True

还是一大排重复的代码呀,我还是觉得它丑啊,我真的不是处女座,但是这个函数是真丑啊,能不能让它再帅一点,当然可以,4个重复块再收成一个函数,循环调4次,是不是可以,好,就这么干,于是have_five就又漂亮了一点点:

def have_five(self, i, j, color):#四个方向计数 竖 横 左斜 右斜directions = [[(-1, 0), (1, 0)], \[(0, -1), (0, 1)], \[(-1, 1), (1, -1)], \[(-1, -1), (1, 1)]]for axis in directions:axis_count = 1for (xdirection, ydirection) in axis:axis_count += self.count_on_direction(i, j, xdirection, ydirection, color)if axis_count >= 5:return Truereturn False

这下判断是否有5颗相同颜色棋子的逻辑也有了,再加一个函数来给界面层返回结果,逻辑部分的代码就差不多了:

 def get_chess_result(self):if self.have_five(self.__currentI, self.__currentJ, self.__currentState):return self.__currentStateelse:return ChessboardState.EMPTY
  • 完整代码gobang.py如下:
#coding:utf-8from enum import Enum
from consts import *class GoBang(object):def __init__(self):self.__chessMap = [[ChessboardState.EMPTY for j in range(N)] for i in range(N)]self.__currentI = -1self.__currentJ = -1self.__currentState = ChessboardState.EMPTYdef get_chessMap(self):return self.__chessMapdef get_chessboard_state(self, i, j):return self.__chessMap[i][j]def set_chessboard_state(self, i, j, state):self.__chessMap[i][j] = stateself.__currentI = iself.__currentJ = jself.__currentState = statedef get_chess_result(self):if self.have_five(self.__currentI, self.__currentJ, self.__currentState):return self.__currentStateelse:return ChessboardState.EMPTYdef count_on_direction(self, i, j, xdirection, ydirection, color):count = 0for step in range(1, 5): #除当前位置外,朝对应方向再看4步if xdirection != 0 and (j + xdirection * step < 0 or j + xdirection * step >= N):breakif ydirection != 0 and (i + ydirection * step < 0 or i + ydirection * step >= N):breakif self.__chessMap[i + ydirection * step][j + xdirection * step] == color:count += 1else:breakreturn countdef have_five(self, i, j, color):#四个方向计数 竖 横 左斜 右斜directions = [[(-1, 0), (1, 0)], \[(0, -1), (0, 1)], \[(-1, 1), (1, -1)], \[(-1, -1), (1, 1)]]for axis in directions:axis_count = 1for (xdirection, ydirection) in axis:axis_count += self.count_on_direction(i, j, xdirection, ydirection, color)if axis_count >= 5:return Truereturn False

可以自我学习的AI五子棋相关推荐

  1. 能自我学习的AI 能辨识20种乐器声音

    MIT发表称为PixelPlayer的人工智能系统,以影片的视觉元素代替人为卷标,让系统达到自我监督学习的目的,自动辨识声音与乐器间的关联,不只可用于音乐的编辑与后制,还能用于机器人研究领域,帮助其理 ...

  2. qpython3h教程_Python3实现AI五子棋【初版】|python3教程|python入门|python教程

    https://www.xin3721.com/eschool/pythonxin3721/ 本文转载至知乎ID:Charles(白露未晞)知乎个人专栏 下载W3Cschool手机App,0基础随时随 ...

  3. 【人工智能】基于蒙特卡洛树搜索和策略价值网络的AI五子棋算法设计

    基于蒙特卡洛树搜索和策略价值网络的AI五子棋算法设计 摘要 蒙特卡洛树搜索算法 五子棋博弈的状态价值函数 附1:详细论文说明下载: 附2:实现代码下载(2022.10更新后代码): 摘要 随着人工智能 ...

  4. 甲小姐对话稚晖君:深度学习并非AI的终点

    "人类不应该只存在在地球上,对于这么浩瀚的宇宙来说太浪费了." 作者 | 甲小姐 助理 | 沁云 近日,华为"天才少年".B站UP主稚晖君的新作自动驾驶自行车在 ...

  5. python五子棋ai_零基础学Python之—AI五子棋(1)

    今天是小编学习Python的第二天,有点小激动,因为我 昨天试了下水,做了一个Python的小弹球游戏,代码copy一路畅通,效果也还不错,而且,我居然还得了60个赞,很高兴,因为这是我第一次写技术博 ...

  6. 产品经理—开发转产品,浅谈自我学习与探索

    编辑导语:如今有越来越多人正想着入职产品岗位,产品经理不论出生,人人都是产品经理,然而想做好产品经理也绝非易事.本文讲述了作者从开发转向产品岗位的背景.想法.学习和探索过程的些许经验,亦或是对自己转行 ...

  7. 五子棋输赢算法php,js实现AI五子棋人机大战

    本文实例为大家分享了js实现AI五子棋人机大战的具体代码,供大家参考,具体内容如下 实现原理就是计算五子棋所有赢的种类,利用canvas实现五子棋排版落子. 五子棋 #canvas{ display: ...

  8. 程序员的下一个风口——永远是不断自我学习,自我思考提升!

    面对近一年的裁员潮,以及 GPT 出现带来的 AI 颠覆潮流,各种话题出现:「前端已死」.「后端已死」.「Copy/Paste 程序员将被 AI 取代」. 文章目录 程序员行业是否还有发展空间? 除技 ...

  9. 深度学习、AI构图、智能裁图、显著性检测、美感质量评价

    深度学习.AI构图.智能裁图.显著性检测.美感质量评价 基于美感数据集和改进的Alexnet-SPP的AI构图智能裁图 基于美感数据集和改进的Alexnet-SPP的显著性检测 部分代码下载地址:下载 ...

  10. 联邦学习:AI大规模落地又一革命性突破

    联邦学习:AI大规模落地又一革命性突破 一方面,AI在安防行业的探索才刚刚开始:另一方面,做好AI所必须的数据养料有限且质量较差,不同数据源之间存在难以打破的壁垒. 除了少数几家拥有海量用户.具备产品 ...

最新文章

  1. 【项目实战】:Python 商铺地址分布数据分析
  2. php 调用扫描仪,如何从浏览器中触发扫描仪?
  3. mysql id会用完吗_数据库自增ID用完了会怎样?
  4. ubuntu16.04 安装python3.6
  5. 2015软件测试面试题第三篇
  6. 计算机专业抑郁症多,社工专业毕业的我得了抑郁症,我的痛苦别人难以理解?...
  7. YUV和RGB格式分析
  8. 【14NOIP普及组】珠心算测验
  9. ubuntu安装百度输入法
  10. js-拖拽-div跟随鼠标的拖拽而移动
  11. php无法导出excel,PHPExcel导出Excel文件时出现错误的解决办法
  12. 微信电话显示对方忙是为什么 微信电话显示对方忙是什么意思
  13. 《Sequence Models》课堂笔记
  14. 【web前端特效源码】使用HTML5+CSS3+JavaScript制作一个可拖动的拼图游戏动画效果~适合初学者~超简单~ |it前端开发
  15. ArcGIS教程:什么是格网和经纬网?
  16. En-Tan-Mo(ETM)项目周报(7.5-7.11)
  17. 成也留存率败也留存率,5大要点助产品人提高留存率
  18. 七年级计算机上教学计划,七年级美术教学计划(精选5篇)
  19. go语言弹出html,golang 定时弹出对话框
  20. 德国研究生分数计算机,德国各专业毕业分数比例的差别,心疼理工科的同学们...

热门文章

  1. JavaWeb从入门到精通 二
  2. 局域网服务器时间自动校准,实现局域网内服务器时间同步的方法
  3. 移动应用开发 jQuery Mobile
  4. cpld的入门交流之三:JED to ABL 反编译方法
  5. lzg_ad:XPE中EWF组件
  6. 推荐10个最好用的数据采集工具
  7. 代码行数统计工具 cloc
  8. 使用wsdl2java编写webservice客户端
  9. 读掘金小册组件精讲总结2
  10. Windows内核编程(五)-驱动的调试