python版本五子棋的实现代码


Posted in Python onDecember 11, 2018

正文之前

前阵子做了个《人工智能》 的课程作业,然后写了个人工智障。。。大概就是个可以跟你下五子棋的傻儿子。。。下面是代码和效果

正文

1、 摘要

机器博弈是人工智能领域的重要分支,它的研究对象多以复杂的棋牌类智力游戏为主,已经得到解决的棋类游戏,几乎全部都应归功于机器博弈近半个世纪的发展。计算机解决问题的优势在于能把不易解析的问题,借助于现代计算机的运算速度优势枚举出所有的合理情形而得解;然而,博弈问题的复杂程度决定了它不能过度依赖机器的计算能力。许多待解决的或已经解决的棋类,其状态空间复杂度或博弈树复杂度量级都太过庞大,所以我们需要添加约束,并且采用合理的算法进行优化。

五子棋问题是人工智能中的一个经典问题。当今世界,AlphaGo已经执围棋之牛耳,五子棋领域却鲜少有人问津。本文根据课堂所学知识结合文献、博客,基于两种开发语言实现了一个智能对战的AI五子棋游戏平台。

本文所做工作如下:

(1) 五子棋界面实现;

(2) 智能判定棋盘走势;

(3) 改进了棋盘扫描方式;

(4) 改良了系统评分表评估方式;

(5) 实现了基于点评分表估值找出最佳落子方式。

2、 问题描述、知识表达

2.1 问题描述

五子棋AI问题的最大问题是如何实现智能对弈,即当人落子之后,算法如何解读当前的棋盘并且对其进行分析解读,得到电脑方的最佳落子点。其次还有一个问题是如何判断胜利,这可以作为前面棋盘局势判定的一个子问题,也可以看做是一个单独的问题,不过这个问题总体来说较为简单,所以不做详细说明。

2.2 知识表达

五子棋的整体知识构建包含以下部分:

(1) 棋盘局面表示法

(2) 棋局胜利判定

(3) 棋型知识库

(4) 智能博弈流程

对于问题(1),采用数组表示法。棋盘中的各交叉点有三种状态,不妨令 0表示空(未放置棋子) ,-1 表示有黑子 ,1 表示有白子,数组表示法的基本思想是:以交叉点对应的数组索引值来表达物理位置 ,以交叉点对应的元素值表达状态(空、 黑子、 白子)。令 V = {0 ,1 ,-1} ,棋盘 的第 i 个交叉点的状态 Si ∈V ,任何棋局都可以表示成一个 n ×n 的二元组。

对于问题(2), 采用数组表示法时,想知道任意两个元素 Si 和Sj 是否共线,要通过 i 和 j 之间的数值规律来判断。从这方面看,数组表示法是一种原始、低效的表示方法,但是对于评分表算法来说其性能损失是可以接受的。要判断是否有一方已经胜利,只需要对整个棋盘判定当前落子点的纵、横、正斜、反斜四个方向的最长延伸出四个位置看是否能连成一条同色直线即可。具体的操作可以视为:从落子点出发,向两个方向延伸,如果遇到同色,那么计数器加一,遇到非同色(空白或者异色)则停止在该方向的延伸,一个计数器记下该方向上的两头的连续同色棋子数。等到四个方向都探索完毕,如果四个计数器中有一个计数器达到了5,那么即可判断出已经有五子连珠了,此局结束。

问题(3)棋型知识库主要包括各种既定的棋盘形式,有如下几种:

² 活四 :有两个连五点(即有两个点可以形成五),图中白点即为连五点。当活四出现的时候,整个局势已经无法阻止连五了,活四的归属方一定能取得胜利;

python版本五子棋的实现代码

² 冲四 :有一个连五点,如下面三图,均为冲四棋型。图中白点为连五点。 相对比活四来说,冲四的威胁性就小了很多,因为这个时候,只要跟着防守在那个唯一的连五点上,冲四就没法形成连五。

python版本五子棋的实现代码

² 活三 :可以形成活四的三,如下图,代表两种最基本的活三棋型。图中白点为活四点。活三棋型是进攻中最常见的一种,因为活三之后,如果对方不以理会,将可以下一手将活三变成活四,而活四是无法防守的。所以,面对活三的时候,需要非常谨慎对待。在没有更好的进攻手段的情况下,必须对其进行防守,以防止其形成可怕的活四棋型。

python版本五子棋的实现代码

² 眠三: 只能够形成冲四的三,如下各图,分别代表最基础的六种眠三形状。图中白点代表冲四点。眠三的棋型与活三的棋型相比,危险系数下降不少,因为眠三棋型即使不去防守,下一手它也只能形成冲四,而对于单纯的冲四棋型,是可以很简单的防守住的。

python版本五子棋的实现代码

² 活二 :能够形成活三的二,如下图,是三种基本的活二棋型。图中白点为活三点。

python版本五子棋的实现代码

² 眠二 :能够形成眠三的二。图中四个为最基本的眠二棋型,细心且喜欢思考的同学会根据眠三介绍中的图2-13找到与下列四个基本眠二棋型都不一样的眠二。图中白点为眠三点。

python版本五子棋的实现代码

对于上述的棋型,我们主要考虑的是活四、冲四、活三、眠三这几种主要的进攻棋型的防守与构成,整体棋型遵从以下原则:优先考虑数目,同等数目的情况下考虑是活是眠。评分表算法的设计整体偏向于防守。

对于问题(4),当下棋型的评估分析,算法严格遵从以下流程:

当人类方落下一子,算法启动,扫描全局,得到人类棋子的集合和电脑棋子的集合。全局扫描之后,对当前局势进行排序、计算。对每个集合的每个空白点位置打分,打分依据是根据这个点周围四个方向上的同色连续棋子的数量。按照这些最后得到的评分,得出最大值。得到人类方和电脑方的两个最大值之后,进行比较,如果人类方局势较好(分数较高),则算法将下一次落子位置设置为人类方得分最高的点,尽力降低人类方的下一步得分;如果电脑方的分数较高,那么则直接在使得分数最高的点落子即可。

3、 开发工具

本次课程设计,一共设计了两个版本,一个Java版本,为19X19的棋盘,配备简单的消息提示,基于AWT实现GUI,开发工具IntelliJ IDEA 2018.1

python版本五子棋的实现代码

另一个版本是使用Python设计,核心算法相同,但是受限于图片源文件,为15X15棋盘,基于pygame实现GUI,开发工具是:JetBrains PyCharm 2018.2.4 x64

python版本五子棋的实现代码 

4、 代码实现

from time import sleep
import pygame
from pygame.locals import *
from random import randint

level = 15
grade = 10
MAX = 1008611
def Scan(chesspad, color):
 shape = [[[0 for high in range(5)] for col in range(15)] for row in range(15)]
 # 扫描每一个点,然后在空白的点每一个方向上做出价值评估!!
 for i in range(15):
 for j in range(15):

  # 如果此处为空 那么就可以开始扫描周边
  if chesspad[i][j] == 0:
  m = i
  n = j
  # 如果上方跟当前传入的颜色参数一致,那么加分到0位!
  while n - 1 >= 0 and chesspad[m][n - 1] == color:
   n -= 1
   shape[i][j][0] += grade
  if n-1>=0 and chesspad[m][n - 1] == 0:
   shape[i][j][0] += 1
  if n-1 >= 0 and chesspad[m][n - 1] == -color:
   shape[i][j][0] -= 2
  m = i
  n = j
  # 如果下方跟当前传入的颜色参数一致,那么加分到0位!
  while (n + 1 < level and chesspad[m][n + 1] == color):
   n += 1
   shape[i][j][0] += grade
  if n + 1 < level and chesspad[m][n + 1] == 0:
   shape[i][j][0] += 1
  if n + 1 < level and chesspad[m][n + 1] == -color:
   shape[i][j][0] -= 2
  m = i
  n = j
  # 如果左边跟当前传入的颜色参数一致,那么加分到1位!
  while (m - 1 >= 0 and chesspad[m - 1][n] == color):
   m -= 1
   shape[i][j][1] += grade
  if m - 1 >= 0 and chesspad[m - 1][n] == 0:
   shape[i][j][1] += 1
  if m - 1 >= 0 and chesspad[m - 1][n] == -color:
   shape[i][j][1] -= 2
  m = i
  n = j
  # 如果右边跟当前传入的颜色参数一致,那么加分到1位!
  while (m + 1 < level and chesspad[m + 1][n] == color):
   m += 1
   shape[i][j][1] += grade
  if m + 1 < level and chesspad[m + 1][n] == 0:
   shape[i][j][1] += 1
  if m + 1 < level and chesspad[m + 1][n] == -color:
   shape[i][j][1] -= 2
  m = i
  n = j
  # 如果左下方跟当前传入的颜色参数一致,那么加分到2位!
  while (m - 1 >= 0 and n + 1 < level and chesspad[m - 1][n + 1] == color):
   m -= 1
   n += 1
   shape[i][j][2] += grade
  if m - 1 >= 0 and n + 1 < level and chesspad[m - 1][n + 1] == 0:
   shape[i][j][2] += 1
  if m - 1 >= 0 and n + 1 < level and chesspad[m - 1][n + 1] == -color:
   shape[i][j][2] -= 2
  m = i
  n = j
  # 如果右上方跟当前传入的颜色参数一致,那么加分到2位!
  while (m + 1 < level and n - 1 >= 0 and chesspad[m + 1][n - 1] == color):
   m += 1
   n -= 1
   shape[i][j][2] += grade
  if m + 1 < level and n - 1 >= 0 and chesspad[m + 1][n - 1] == 0:
   shape[i][j][2] += 1
  if m + 1 < level and n - 1 >= 0 and chesspad[m + 1][n - 1] == -color:
   shape[i][j][2] -= 2
  m = i
  n = j
  # 如果左上方跟当前传入的颜色参数一致,那么加分到3位!
  while (m - 1 >= 0 and n - 1 >= 0 and chesspad[m - 1][n - 1] == color):
   m -= 1
   n -= 1 
   shape[i][j][3] += grade
  if m - 1 >= 0 and n - 1 >= 0 and chesspad[m - 1][n - 1] == 0:
   shape[i][j][3] += 1
  if m - 1 >= 0 and n - 1 >= 0 and chesspad[m - 1][n - 1] == -color:
   shape[i][j][3] -= 2
  m = i
  n = j
  # 如果右下方跟当前传入的颜色参数一致,那么加分到3位!
  while m + 1 < level and n + 1 < level and chesspad[m + 1][n + 1] == color:
   m += 1
   n += 1
   shape[i][j][3] += grade
  if m + 1 < level and n + 1 < level and chesspad[m + 1][n + 1] == 0:
   shape[i][j][3] += 1
  if m + 1 < level and n + 1 < level and chesspad[m + 1][n + 1] == -color:
   shape[i][j][3] -= 2
 return shape


def Sort(shape):
 for i in shape:
 for j in i:
  for x in range(5):
  for w in range(3, x - 1, -1):
   if j[w - 1] < j[w]:
   temp = j[w]
   j[w - 1] = j[w]
   j[w] = temp
 print("This Time Sort Done !")
 return shape


def Evaluate(shape):
 for i in range(level):
 for j in range(level):

  if shape[i][j][0] == 4:
  return i, j, MAX
  shape[i][j][4] = shape[i][j][0]*1000 + shape[i][j][1]*100 + shape[i][j][2]*10 + shape[i][j][3]
 max_x = 0
 max_y = 0
 max = 0
 for i in range(15):
 for j in range(15):
  if max < shape[i][j][4]:
  max = shape[i][j][4]
  max_x = i
  max_y = j
 print("the max is "+ str(max) + " at ( "+ str(max_x)+" , "+str(max_y)+" )")
 return max_x, max_y, max


class chess(object):
 def __init__(self):
 self.a = [[0 for high in range(15)] for col in range(15)] 

 def fall(self, x, y, color):
 if (x < 0 or x > level - 1 or y < 0 or y > level - 1):
  return
 self.a[x][y] = color
 if Judge(x, y, color, self.a, 4):
  if color < 0:
  print("The Winner is White!!")
  else:
  print("The Winner is Black!!")

 def isEmpty(self, m, n):
 if self.a[m][n] != 0:
  return False
 else:
  return True


def Judge(x, y, color, CHESSLOCATION, length):
 count1, count2, count3, count4 = 0, 0, 0, 0
 # 横向判断
 i = x - 1
 while (i >= 0):
 if color == CHESSLOCATION[i][y]:
  count1 += 1
  i -= 1
 else:
  break
 i = x + 1
 while i < level:
 if CHESSLOCATION[i][y] == color:
  count1 += 1
  i += 1
 else:
  break

 # 纵向判断
 j = y - 1
 while (j >= 0):
 if CHESSLOCATION[x][j] == color:
  count2 += 1
  j -= 1
 else:
  break
 j = y + 1
 while j < level:
 if CHESSLOCATION[x][j] == color:
  count2 += 1
  j += 1
 else:
  break

 # 正对角线判断
 i, j = x - 1, y - 1
 while (i >= 0 and j >= 0):
 if CHESSLOCATION[i][j] == color:
  count3 += 1
  i -= 1
  j -= 1
 else:
  break
 i, j = x + 1, y + 1
 while (i < level and j < level):
 if CHESSLOCATION[i][j] == color:
  count3 += 1
  i += 1
  j += 1
 else:
  break
 # 反对角线判断
 i, j = x + 1, y - 1
 while (i < level and j >= 0):
 if CHESSLOCATION[i][j] == color:
  count4 += 1
  i += 1
  j -= 1
 else:
  break
 i, j = x - 1, y + 1
 while (i > 0 and j < level):
 if CHESSLOCATION[i][j] == color:
  count4 += 1
  i -= 1
  j += 1
 else:
  break

 if count1 >= length or count2 >= length or count3 >= length or count4 >= length:
 return True
 else:
 return False


def Autoplay(ch, m, n):
 a1 = [1,-1,1,-1,1,-1,0,0]
 b1 = [1,-1,-1,1,0,0,1,-1]
 rand = randint(0,7)
 while m+a1[rand]>=0 and m+a1[rand]<level and n+b1[rand]>=0 and n+b1[rand]<level and ch[m+a1[rand]][n+b1[rand]]!=0 :
 rand = randint(0,7)
 return m + a1[rand], n+b1[rand]

def BetaGo(ch, m, n, color, times):
 if times < 2:
 return Autoplay(ch, m, n)
 else:
 shape_P = Scan(ch, -color)
 shape_C = Scan(ch,color)
 shape_P = Sort(shape_P)
 shape_C = Sort(shape_C)
 max_x_P, max_y_P, max_P = Evaluate(shape_P)
 max_x_C, max_y_C, max_C = Evaluate(shape_C)
 if max_P>max_C and max_C<MAX:
  return max_x_P,max_y_P
 else:
  return max_x_C,max_y_C


def satrtGUI(ch):
 pygame.init()
 bg = 'bg.png'
 white_image = 'white.png'
 black_image = 'black.png'

 screen = pygame.display.set_mode((750, 750), 0, 32)
 background = pygame.image.load(bg).convert()
 white = pygame.image.load(white_image).convert_alpha()
 black = pygame.image.load(black_image).convert_alpha()
 white = pygame.transform.smoothscale(white, (int(white.get_width() * 1.5), int(white.get_height() * 1.5)))
 black = pygame.transform.smoothscale(black, (int(black.get_width() * 1.5), int(black.get_height() * 1.5)))

 screen.blit(background, (0, 0))
 font = pygame.font.SysFont("黑体", 40)

 pygame.event.set_blocked([1, 4, KEYUP, JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN, JOYBUTTONUP, JOYHATMOTION])
 pygame.event.set_allowed([MOUSEBUTTONDOWN, MOUSEBUTTONUP, 12, KEYDOWN])

 dot_list = [(25 + i * 50 - white.get_width() / 2, 25 + j * 50 - white.get_height() / 2) for i in range(level) for
  j in range(level)]
 color = -1
 times = 0
 flag = False
 while not flag:
 for event in pygame.event.get():
  if event.type == QUIT:
  exit()
  elif event.type == MOUSEBUTTONDOWN:
  x, y = pygame.mouse.get_pos()
  if 25 <= x <= 725 and 25 <= y <= 725 and ((x - 25) % 50 <= level or (x - 25) % 50 >= 0) and (
   (y - 25) % 50 <= level or (y - 25) % 50 >= 0):
   color = -1 * color
   m = int(round((x - 25) / 50))
   n = int(round((y - 25) / 50))
   if not ch.isEmpty(m, n):
   print("Black OverWrite~~")
   continue
   ch.fall(m, n, color)
   screen.blit(black, dot_list[level * m + n])
   if Judge(m, n, color, ch.a, 4):
   screen.blit(font.render('GAME OVER,Black is win!', True, (110, 210, 30)), (80, 650))
   break

   color = -1 * color
   sleep(0.1)
   x, y = BetaGo(ch.a, m, n, color, times)
   times += 1
   print("Predict:" + str(x) + " and " + str(y))
   ch.fall(x, y, color)
   screen.blit(white, dot_list[level * x + y])
   if Judge(x, y, color, ch.a, 4):
   screen.blit(font.render('GAME OVER,White is win!', True, (217, 20, 30)), (80, 650))
   break
 pygame.display.update()
 if flag:
  sleep(5)

now = chess()
satrtGUI(now)

python版本五子棋的实现代码

bg.png

python版本五子棋的实现代码

black.png

python版本五子棋的实现代码

white.png

5、 小结及展望

5.1 小结

因为近期时间较为紧迫,所以《人工智能》这门课我选择了较为简单的五子棋问题进行课程设计。在本次课程设计中,我的编码能力、调试能力、算法解读实现能力、函数优化能力等各方面有了长足的进步。在本次的设计过程中也出现了几个问题,下面对这些问题进行一个简单的描述:

(1) 对棋盘局势的判断力不够,因为只是简单的对当前的棋盘局势进行判断,基本等同于一个粗通规则而且天赋不高的五子棋选手。如果对手很细心,而且熟练经营各种布局策略,那么基本这个算法就会被钻研出习惯,从而被轻易针对,而且针对方案百试不爽;

(2) 判断棋局形式的时候对边界的评分算法跟中心区域的评分算法一致,无法有效提前识别边界,降低边界空白点的权重;

(3) 用户图形界面需要改进,另外可以增设PK模式以及选色、选择棋盘大小功能等;

5.2 展望

后续可以尝试用博弈树算法尝试与当前算法进行比较。评分表算法牺牲了更高的精度,以求迅速的得出最佳落子点;而博弈树可以通过提前落子进行全局预判进行更全方位的对人类方的围追堵截。

另外,可以通过在课堂上学到的知识,比如BFS、DFS、A*算法、决策树算法 等应用于五子棋的智能决策中。

《人工智能》这门课让我对于图、知识表示、智能决策等各个方面有了更好地认识与体验,课堂设计内容充实有趣,让我受益匪浅,希望今后可以更加深入这个方面,并且将课堂上学到的知识应用于实践之中。

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

Python 相关文章推荐
Python pickle模块用法实例
Apr 14 Python
python多线程方式执行多个bat代码
Jun 07 Python
Python实现按中文排序的方法示例
Apr 25 Python
python使用pdfminer解析pdf文件的方法示例
Dec 20 Python
python中logging模块的一些简单用法的使用
Feb 22 Python
Pytorch卷积层手动初始化权值的实例
Aug 17 Python
python读取ini配置文件过程示范
Dec 23 Python
在tensorflow中设置保存checkpoint的最大数量实例
Jan 21 Python
Python while循环使用else语句代码实例
Feb 07 Python
Jupyter Notebook 文件默认目录的查看以及更改步骤
Apr 14 Python
Django怎么在admin后台注册数据库表
Nov 14 Python
Python中文纠错的简单实现
Jul 07 Python
python提取具有某种特定字符串的行数据方法
Dec 11 #Python
Python面向对象基础入门之编码细节与注意事项
Dec 11 #Python
Python面向对象基础入门之设置对象属性
Dec 11 #Python
python提取包含关键字的整行数据方法
Dec 11 #Python
django开发post接口简单案例,获取参数值的方法
Dec 11 #Python
python面向对象入门教程之从代码复用开始(一)
Dec 11 #Python
python 运用Django 开发后台接口的实例
Dec 11 #Python
You might like
2020年4月新番动漫目录 官方宣布4月播出的作品一览
2020/03/08 日漫
PHP学习之PHP表达式
2006/10/09 PHP
PHP面向接口编程 耦合设计模式 简单范例
2011/03/23 PHP
PHP __autoload函数(自动载入类文件)的使用方法
2012/02/04 PHP
php中数组首字符过滤功能代码
2012/07/31 PHP
解析获取优酷视频真实下载地址的PHP源代码
2013/06/26 PHP
php+mysqli实现批量执行插入、更新及删除数据的方法
2015/01/29 PHP
php实现的一个简单json rpc框架实例
2015/03/30 PHP
PHP设计模式之装饰者模式代码实例
2015/05/11 PHP
Laravel中间件实现原理详解
2016/10/09 PHP
PHP获取星期几的常用方法小结
2018/12/18 PHP
JavaScript 无符号右移运算符
2009/04/17 Javascript
JavaScript中出现乱码的处理心得
2009/12/24 Javascript
Javascript堆排序算法详解
2014/12/03 Javascript
实例详解JSON数据格式及json格式数据域字符串相互转换
2016/01/07 Javascript
javascript实现随机生成DIV背景色
2016/06/20 Javascript
html+js实现简单的计算器代码(加减乘除)
2016/07/12 Javascript
JavaScript中三个等号和两个等号的区别(== 和 ===)浅析
2016/09/22 Javascript
javascript canvas检测小球碰撞
2020/04/17 Javascript
javascript-hashchange事件和历史状态管理实例分析
2020/04/18 Javascript
python模拟鼠标拖动操作的方法
2015/03/11 Python
ubuntu系统下使用pm2设置nodejs开机自启动的方法
2018/05/12 NodeJs
使用pandas的DataFrame的plot方法绘制图像的实例
2018/05/24 Python
解决pycharm工程启动卡住没反应的问题
2019/01/19 Python
使用python执行shell脚本 并动态传参 及subprocess的使用详解
2020/03/06 Python
用python对oracle进行简单性能测试
2020/12/05 Python
德国帽子专家:Hutshopping
2019/11/03 全球购物
潘多拉珠宝美国官方网站:Pandora US
2020/06/18 全球购物
String和StringBuffer的区别
2015/08/13 面试题
linux面试题参考答案(8)
2015/08/11 面试题
学校安全工作制度
2014/01/19 职场文书
《罗布泊,消逝的仙湖》教学反思
2014/03/01 职场文书
学生会个人总结范文
2015/02/15 职场文书
工作迟到检讨书范文
2015/05/06 职场文书
我的兄弟姐妹观后感
2015/06/15 职场文书
麦田里的守望者读书笔记
2015/06/30 职场文书