Python 实现黑白棋
Python实现黑白棋
- 题目要求
- 电脑的策略
- 游戏结束的条件
- 解题思路
- 关键逻辑
- 关键函数
- Init_board:
- printBoard:
- computer_move:
- human_move:
- check_board:
- check_legal_move:
- gameover:
- saveinfo:
- main
- 后记
- 程序可能的优化方向
题目要求
电脑的策略
对每个可能的落子位置,都进行尝试,计算该位置的“分值” (可以翻转的对手棋子数量),分值越高则在该位置落子越有利。计算每个可能位置的分值,选择最大值位置落子。可能有2个或多个棋盘格有相同的分值。这种情况下,选择行字母最小的棋盘格。如果两个棋盘格分值相同且在同一行,则选择列字母较小的棋盘格
游戏结束的条件
1)整个棋盘满了;
2)一方的棋子已经被对方吃光;
3)两名玩家都 没有可以落子的棋盘格;
4)一方落子在非法位置。
前 3 种情况以棋子数目来计算胜负,棋子多的一方获 胜;第 4 种情况判定对方获胜。
解题思路
关键逻辑
1)不论是电脑下棋还是人类下棋,都需要先判断是否有字可落
2)人类下棋之前,要判断落子是否合法
3)在判断落子是否合法的时候,要注意棋盘的边界
因为python的列表存在下标为-1的情况,故要注意下标的下界,另一方面,因为黑白棋要考虑尽头那个棋子是否为同色的情况,所以要注意当前搜索棋子和同方向的下一个棋子(潜在的同色可能性)是否越界。
举例:4*4棋盘的“黑 白 白 白” ,如果不考虑下一个棋子的越界情况的话,会出现从黑开始绕一个圈回来又查找到黑从而把三个白棋翻转的错误情况
4)其实翻转、检测落子是否合法,计算落子的分值用的都是同一套循环逻辑,所以只写一个然后基本复制黏贴就好了
5)用多次sort进行不同权重的比较
6)游戏结束的几种情况要分情况讨论
关键函数
Init_board:
读入棋盘大小 n(n 为偶数,且 4≤n≤26),按照要求初始化棋盘。程序使用如下字 符表示每个棋盘格的状态:
. – 未被占用 X – 被黑棋占用 O – 被白棋占用
def Init_board():global boardboard = [[0] * l for row in range(l)] #用列表生成式生成棋盘board[int(l / 2 - 1)][int(l / 2 - 1)] = -1board[int(l / 2 - 1)][int(l / 2)] = 1board[int(l / 2)][int(l / 2 - 1)] = 1board[int(l / 2)][int(l / 2)] = -1 #四个初始棋子的摆放return board#在这个处理中我们用0代表未落子,1代表黑棋,-1代表白棋
printBoard:
输出棋盘。例如:4×4 棋盘的初始状态如下:
a b c d
a . . . .
b . O X .
c . X O .
d . . . .
def printBoard():l = len(board)print(' ', end = ' ')for i in range(l):print(chr(ord('a') + i), end = ' ')print()for i in range(l):print(chr(ord('a') + i), end = ' ')for j in range(l):if (board[i][j] == 0):print('.', end = ' ')elif (board[i][j] == 1):print('X', end = ' ')else:print('O', end = ' ')print()
computer_move:
计算机下棋。落子位置表示为“行列字母”的格式,如:“ba”代表棋子 落在行 b 列 a。
def computer_move(row, col, color): #电脑行棋和棋子翻转global boardif (check != 0): #check中存储的是该棋子的价值(翻转的棋子数),不为0则合法board[row][col] = color #向规定地点放上棋子direction = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1))for i in range(8):z = 1 #对8个方向进行搜索while (0<= row + (z+1) * direction[i][0] < l) and (0<= col + (z+1) * direction[i][1] < l) and (board[row + z * direction[i][0]][col + z * direction[i][1]] == -color):#搜索进行的条件,搜索的下一个位置没有超过系统边界(因为尽头是一个相同的棋子所以要多查找一步),当前位置的棋子是一个异色的棋子。z += 1 #这里涉及到一个问题就是python列表值是存在-1值的,所以要规定列表搜索的下界只能到0,不然本质上会查找到列表最后一个(下标为-1)的值if board[row + z * direction[i][0]][col + z * direction[i][1]] == color: #如果查找到了尽头的那个同色棋子for j in range(z):board[row + j * direction[i][0]][col + j * direction[i][1]] = color #那就把中间的棋子全部置为同色并退出这次搜索break
human_move:
用户下棋
def human_move(row, col, color): #人类行棋和棋子翻转,与电脑行棋类似global boardif (check != 0):board[row][col] = colordirection = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1))for i in range(8):z = 1while (0<=row + (z+1) * direction[i][0] < l) and (0 <= col + (z+1) * direction[i][1] < l) and (board[row + z * direction[i][0]][col + z * direction[i][1]] == -color):z += 1if board[row + z * direction[i][0]][col + z * direction[i][1]] == color:for j in range(z):board[row + j * direction[i][0]][col + j * direction[i][1]] = colorbreak
check_board:
检测游戏是否结束
def check_board(): #检测本局游戏是否结束a1 = 1 #用来标记棋盘是否下满a21 = 1 #检测棋盘中是否还有黑棋a22 = 1 #检测棋盘中是否还有白棋a4 = 0 #检测当前落子位置是否合法for i in range(l):for j in range(l): #遍历整个棋盘if (board[i][j] == 0): #如果存在空位a1 = 0elif (board[i][j] == 1): #如果存在黑棋a21 = 0else: #如果存在白棋a22 = 0if not (check): # check为0则不存在翻转,落子合法a4 = 1if (a1 or (a21 and a22) or (not (xp or op)) or a4):if (a1 or (a21 and a22) or (not (xp or op))): # xp和op代表了双方是否存在落子位置if (not (xp or op)): #如双双置0,则证明双方都无落子位置print("Both player have no vaild move!")gameover('score') #这些都是积分计算胜负关系else: #如果a4出现了,则落子非法,计算胜负关系gameover('illegal')
check_legal_move:
检测颜色为 color 的棋子落在棋盘格(row, col) 上是否合法
def check_legal_move(row, col, color): #检测落子位置是否合法direction = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1))score = 0for i in range(8): #思路与落子的思路类似,但不同的是这里当搜索到最后的同色棋子时,进行加和操作而非翻面操作 zscore = 1while (0 <= (row + (zscore+1) * direction[i][0]) < l) and (0 <= (col + (zscore+1) * direction[i][1]) < l) and ((board[row + zscore * direction[i][0]][col + zscore * direction[i][1]]) == -color):if (board[row + (zscore + 1) * direction[i][0]][col + (zscore + 1) * direction[i][1]] == color):score += zscorebreakzscore += 1return score
gameover:
游戏结束,统计得分,输出结果
def gameover(s): #游戏结束判定global s1global conditionglobal blackglobal whitecondition = 0 #将游戏标记置为 0,游戏停止if s == 'score': #如果是分数过程,则计算黑白棋的个数print('Game Over!')black = 0white = 0for i in range(l):for j in range(l):if board[i][j] == 1:black += 1if board[i][j] == -1:white += 1if (black > white):print('X : O =', black, ':', white)print('X player wins!')elif (black < white):print('O player wins!')print('X : O =', black, ':', white)else:print('Draw!')s1 = str(black) + 'to' + str(white) # s1 中存储的是要输进文件去的文本return s1if s == 'illegal':print('Invaild move!')s1 = 'Invaild move!'if s == 'gg':print('Human gave up!')s1 = 'Human gave up!'print('Game Over!')if (color == 1): #这里是非法输入和gg投子的输出设置,color在主程序中更改print('O player wins.')else:print('X player wins.')return s1
saveinfo:
把每次人机对弈的信息作为一行写入文件reversi.csv中,这些信息包括:游戏 开始的时间、单次游戏使用的时间、棋盘大小、黑棋玩家、白棋玩家、游戏比分,信息之间使用逗号字 符分隔。
def saveinfo(): #文件存储time3 = time.time() #游戏结束时间long = time3-time2 #游戏持续时长f = open('Reversi.csv', 'a+')s = str(time1) + ',' + str(long) + ',' + str(l) + '*' + str(l) + ',' + Xplayer + ',' + Oplayer + ',' + s1f.write(s) #向文件中输入f.write('\n')f.close()
main
import datetime
import time
time1 = datetime.datetime.now().strftime('%Y-%m-%d %T') #保存游戏时间
time2 = time.time() #游戏开始时间
l = int(input('Enter the board dimension:')) # l 中保存了棋盘的长度
board = Init_board() #初始化棋盘
x1 = input('Computer plays (X/O):') # x1中保存电脑的棋子颜色
if (x1 == 'X'): # 电脑执黑 hcolor = -1Xplayer = 'computer'Oplayer = 'human' #这个是要输进文件里的东西condition = 1 #游戏标记置1,游戏进行printBoard() #打印 、while condition: #如果游戏标志为1(没进gameover),则可以继续运行legal = []for i in range(l):for j in range(l):if (board[i][j] == 0):if (check_legal_move(i, j, 1) != 0):legal.append([i, j, check_legal_move(i, j, 1)]) #将所有可下位置存进legal列表中legal.sort(key=lambda x: x[1], reverse=False)legal.sort(key=lambda x: x[0], reverse=False)legal.sort(key=lambda x: x[2], reverse=True) #对列表进行先值,再行,再列的排序if (legal != []): #如果存在合法输入row = legal[0][0]col = legal[0][1]color = 1check = check_legal_move(row, col, color)xp = 1 #证明X仍可下op = 1 #证明O仍可下computer_move(row, col, 1) #将分值存进check里,进行落子print('Computer places X at', chr(ord('a') + row), chr(ord('a') + col), '.')else:xp = 0 #如果不存在落子位置print('X player has no vaild move.') #不进行落子printBoard() #进行棋盘打印check_board() #进行检测棋局是否结束if (condition != 0): #如果棋局没有结束的话进行人类行棋legal = [] for i in range(l):for j in range(l):if board[i][j] == 0:if (check_legal_move(i, j, -1) != 0) and (board[i][j] == 0):legal.append([i, j, check_legal_move(i, j, -1)]) #检测是否有行棋位置if (legal != []):inter = input('Enter move for O (Rowcol):')if inter == 'gg': #贴心的投降设置gameover('gg')breakrow = ord(inter[0]) - 97 #把输入的字母通过ASCII码变成输出col = ord(inter[1]) - 97color = -1if (row>=l) or (col>=l) or (row<0) or (col <0): #如果输入超过边界,则为非法输入gameover('illegal')breakcheck = check_legal_move(row, col, color) #检测落子是否存在翻转xp = 1op = 1human_move(ord(inter[0]) - 97, ord(inter[1]) - 97, -1) #人类落子check_board() #检测当前棋盘是否满足结束条件if check:printBoard() #如果通过,则进行打印else:op = 0 #白棋无棋可下 print("O player has no vaild move.")saveinfo() #游戏结束之后进行游戏记录的保存else: #之后为电脑执白棋的情况,与上文黑棋的情况类似hcolor = 1Oplayer = 'computer'Xplayer = 'human'condition = 1printBoard()while condition:legal = []for i in range(l):for j in range(l):if (board[i][j] == 0):if (check_legal_move(i, j, 1) != 0):legal.append([i, j, check_legal_move(i, j, 1)])if (legal != []):inter = input('Enter move for X (Rowcol):')if inter == 'gg':gameover('gg')breakrow = ord(inter[0]) - 97col = ord(inter[1]) - 97color = 1if (row>=l) or (col>=l) or (row<0) or (col <0):gameover('illegal')breakcheck = check_legal_move(row, col, color)xp = 1op = 1human_move(ord(inter[0]) - 97, ord(inter[1]) - 97, 1)check_board()if check:printBoard()else:op = 0print("O player has no vaild move.")if condition:legal = []for i in range(l):for j in range(l):if (board[i][j] == 0):if (check_legal_move(i, j, -1) != 0):legal.append([i, j, check_legal_move(i, j, -1)])legal.sort(key=lambda x: x[1], reverse=False) legal.sort(key=lambda x: x[0], reverse=False)legal.sort(key=lambda x: x[2], reverse=True)if (legal != []):xp = 1op = 1row = legal[0][0]col = legal[0][1]color = -1check = check_legal_move(row, col, color)computer_move(row, col, -1)else:xp = 0print("X player has no vaild move.")check_board()printBoard()print('Computer places O at', chr(ord('a') + row), chr(ord('a') + col), '.')saveinfo()
后记
程序可能的优化方向
程序可能出现的错误!存在一种情况就是一方本来无棋可下,另一方行棋之后突然有棋可下了!所以需要重置“是否有棋可下”的条件码,这里等到大作业截止之后再做修改
1)将电脑执黑或执白的情况分开来讨论太麻烦了(相当于代码量*2),能用一个函数解决它吗?
2)其实判断落子位置,分值和是否合法用的也是同一套函数,可以使用函数进行代码的复用,就不用写那么多了。
3)因为后面基本就是用pycharm来做逐步debug了,所以一些判断和list语句可能写的没那么好看
4)程序的稳定性有待检验(实在是懒得跟电脑下那么多盘棋)
5)gameover的函数多入口情况是否可以优化?
Python 实现黑白棋相关推荐
- Python实现黑白棋人机对弈
Python实现黑白棋人机对弈 简书:Python实现黑白棋人机对弈https://www.jianshu.com/p/37191dffbe07 规则 黑白棋的每颗棋子由黑白两色组成,一面白,一面黑. ...
- python+pyGame 黑白棋游戏
注:以下程序为根据相应的字符界面程序改编而来,写的不好,若有好的建议,望留言告知.而若能帮助一二访客,幸甚! 继续学习python. 为了学习起来更有趣,继续以游戏的方式来学习. 注:前几天学习了In ...
- 黑白棋python代码框架_Python实现黑白棋人机对弈
Python实现黑白棋人机对弈 规则 黑白棋的每颗棋子由黑白两色组成,一面白,一面黑.每次落子,把本方颜色的棋子放在棋盘的空格上,若在横.竖.斜八个方向的任一方向上有本方棋子,则被夹在中间的对手棋子全 ...
- python大作业黑白棋记分_Python实现黑白棋人机对弈
Python实现黑白棋人机对弈 规则 黑白棋的每颗棋子由黑白两色组成,一面白,一面黑.每次落子,把本方颜色的棋子放在棋盘的空格上,若在横.竖.斜八个方向的任一方向上有本方棋子,则被夹在中间的对手棋子全 ...
- Windows游戏设计(三)- 黑白棋游戏 - 使用Win32 SDK
注:以下程序为本人原创,写的不好,若有好的建议,望留言告知.而若能帮助一二访客,幸甚! 上回用Python 写黑白棋,后来想添加个最小最大规则搜索博弈树的算法,没能实现,于是想先用Win32 写一个, ...
- 人工智能导论实验二 食人族传教士过河+黑白棋 prolog+Python
实验目的及要求: 本项目要求能够理解人工智能的基本原理,理解状态空间的概念.原理和方法,掌握用状态空间表示问题的步骤,掌握搜索方法的基本原理,并能够实际问题给出具体的实现. 实验内容: 状态.状态空间 ...
- python 黑白棋_python-黑白棋游戏需要说明
黑白棋是一款优雅简单的游戏.我将使用伪C#/ Java语言来解释一些概念,但是您可以将它们转换为Python. 要将其分解为最简单的组件,您有两个基本要求: 代表游戏板的二维数组: gameBoard ...
- [Python] 黑白棋(翻转棋)小游戏
[Python] 黑白棋(翻转棋)小游戏 游戏介绍 黑白棋(Reversi or Othello)在西方和日本很流行.游戏通过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负. 规则 黑白棋的每颗 ...
- 【Python案例】基于Pygame黑白棋游戏(附源码)
有没有小火伴是特别喜欢玩五子棋的,我记得我初中是特别喜欢的.于是,我今天就用Python给大家写了一个黑白棋游戏.代码放在下面了. 01.绘制棋盘 Python学习交流Q群:906715085### ...
最新文章
- iOS开发几年了,你清楚OC中的这些东西么!!!?
- slam开发|adb的用法一些总结
- python怎么安装matplotlib-python 安装matplotlib
- cmake / add_compile_options、CMAKE_CXX_FLAGS 和 add_definitions 区别
- 在springboot中使用springsecurity实现安全控制
- jdbc-------JDBCUtil类 工具类
- CSS清除默认样式,看完这篇彻底明白了
- IIS AppCreate子目录的错误(0x80020006)
- OpenShift应用镜像构建(4) - fabric8-maven-plugin
- 大一java题库及答案_2016最新java考试题库及答案
- 中国建设银行-跨境易支付
- C语言--《C专家编程》C语言申明的优先级规则
- 关于约束多目标MOEA/D-DAE
- 《人类简史》二、认知革命——上帝之手的秘密
- Linux常用命令 shell脚本for QA-数据脱敏版2
- 计算机中1kb等于多少字节,在计算机中1kb等于多少字节
- latex插图编号_LaTex技巧[26]:Latex重新为图片编号
- 快速复制文件,提高复制文件的速度
- 递归回溯法求数独全部解
- 【聚类算法】MiniBatchKMeans算法