Python实现黑白棋游戏策略与胜负判定详解:电脑落子与游戏结束条件分析

Python 实现黑白棋

Python实现黑白棋游戏策略与胜负判定详解:电脑落子与游戏结束条件分析

该问题需要计算机策略

对于每个可能的放置位置,尝试计算该位置的“分数”(可以翻转的对手棋子的数量)。分数越高,将该棋子放置在该位置越有利。计算每个可能位置的分数并选择得分最高的位置。可能有 2 个或更多方格得分相同。在这种情况下,选择行字母最小的棋盘。如果两个棋子得分相同并且位于同一行,则选择列字母较小的棋子。

游戏结束条件

1)整个棋盘已满;

2)一方的棋子已被另一方吃掉;

3) 双方棋手都没有可以放置棋子的棋盘方格;

4)一方处于非法职务。

前三种情况按棋子数量计算胜负,棋子多的一方获胜;第四种情况,判定对方获胜。

解决问题思路的关键逻辑

1)无论是电脑下棋还是人下棋,首先要判断是否有可以掉的字。

2)人类在下棋之前,必须确定这一步棋是否合法。

3)判断走棋是否合法时,要注意棋盘的边界

因为python列表的下标为-1,所以必须注意下标的下界。另一方面,因为黑白棋需要考虑最后的棋子是否同色,所以必须注意当前搜索的棋子和下一个方向相同的棋子。该棋子(可能具有相同颜色)是否出界。

例如:4*4的棋盘上的“黑与白”,如果不考虑下一个棋子的出界情况,就会出现从黑开始,回去找黑的错误,从而翻转三个白色棋子。

4)其实翻转、检查走法是否合法、计算走法分数都用的是同一套循环逻辑,所以写一个就行了,基本是复制粘贴。

5)使用多重排序来比较不同权重

6)比赛结束时的几种情况要具体情况具体讨论。

关键函数Init_board:

读入棋盘大小n(n为偶数,且4≤n≤26),并按要求初始化棋盘。程序使用以下字符来表示每个棋盘的状态:

。 – 未被占据 X – 被黑色占据 O – 被白色占据

def Init_board():
   global board
   board = [[0] * l for row in range(l)]  #用列表生成式生成棋盘
   board[int(l / 2 - 1)][int(l / 2 - 1)] = -1
   board[int(l / 2 - 1)][int(l / 2)] = 1
   board[int(l / 2)][int(l / 2 - 1)] = 1
   board[int(l / 2)][int(l / 2)] = -1    #四个初始棋子的摆放
   return board
    #在这个处理中我们用0代表未落子,1代表黑棋,-1代表白棋

打印板:

输出棋盘。例如:4×4棋盘的初始状态如下:

abcd

一个。 。 。 。

盒子。

c.XO。

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()

计算机_移动:

计算机下棋。棋子的位置以“行行字母”的格式表示。例如:“ba”表示棋子落在b行a列。

def computer_move(row, col, color):             #电脑行棋和棋子翻转
    global board
    if (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                  

人类移动:

用户下棋

def human_move(row, col, color):                #人类行棋和棋子翻转,与电脑行棋类似
    global board
    if (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
            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
                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

检查板:

检查游戏是否结束

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 = 0
            elif (board[i][j] == 1):              #如果存在黑棋
                a21 = 0
            else:                                 #如果存在白棋
                a22 = 0
    if not (check):                               # check为0则不存在翻转,落子合法
        a4 = 1
    if (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')

检查合法移动:

检查有颜色的棋子落在棋盘上是否合法(行,列)

 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 = 0
    for i in range(8):                                    #思路与落子的思路类似,但不同的是这里当搜索到最后的同色棋子时,进行加和操作而非翻面操作 
        zscore = 1
        while (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 += zscore
                break
            zscore += 1
    return score

游戏结束:

游戏结束,统计分数,输出结果。

def gameover(s):                                          #游戏结束判定
   global s1
   global condition
   global black
   global white
   condition = 0                                         #将游戏标记置为 0,游戏停止
   if s == 'score':                                      #如果是分数过程,则计算黑白棋的个数
       print('Game Over!')
       black = 0
       white = 0
       for i in range(l):
           for j in range(l):
               if board[i][j] == 1:
                   black += 1
               if board[i][j] == -1:
                   white += 1
       if (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 s1
   if 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

保存信息:

将每个人机游戏的信息一行写入文件 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 + ',' + s1
 f.write(s)                                             #向文件中输入
 f.write('\n')
 f.close()

主要的

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 = -1
 Xplayer = '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 = 1
         check = 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')
                 break
             row = ord(inter[0]) - 97          #把输入的字母通过ASCII码变成输出
             col = ord(inter[1]) - 97
             color = -1
             if (row>=l) or (col>=l) or (row<0) or (col <0):          #如果输入超过边界,则为非法输入
                 gameover('illegal')
                 break
             
             check = check_legal_move(row, col, color)    #检测落子是否存在翻转
             xp = 1
             op = 1
             human_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 = 1
 Oplayer = 'computer'
 Xplayer = 'human'
 condition = 1
 printBoard()
 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')
             break
         row = ord(inter[0]) - 97
         col = ord(inter[1]) - 97
         color = 1
         if (row>=l) or (col>=l) or (row<0) or (col <0):
             gameover('illegal')
             break
         check = check_legal_move(row, col, color)
         xp = 1
         op = 1
         human_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.")
     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 = 1
             op = 1
             row = legal[0][0]
             col = legal[0][1]
             color = -1
             check = check_legal_move(row, col, color)
             computer_move(row, col, -1)
         else:
             xp = 0
             print("X player has no vaild move.")
         check_board()
         printBoard()
         print('Computer places O at', chr(ord('a') + row), chr(ord('a') + col), '.')
 saveinfo()

postscript程序可能的优化方向

可能是程序错误!有一种情况,一方原本无棋可下,但对方下了棋后,突然有棋可下!因此,我们需要重新设置“是否有棋可以下”的条件码。我们将等到重大任务到期后再进行任何更改。

1)单独讨论计算机是黑是白太麻烦(相当于代码量*2)。可以用函数解决吗?

2)实际上,判断走棋的位置、得分以及是否合法都是用同一套函数。你可以使用函数来复用代码,所以不需要写那么多。

3)因为我们后面基本都是用pycharm进行一步步调试,所以有些判断和列表语句可能写得不是那么漂亮。

4)程序的稳定性有待测试(我实在是懒得用电脑玩那么多游戏了)

5)GameOver的多次进入功能可以优化吗?

你可能想看:
« 上一篇
下一篇 »

相关推荐

python爬虫教程PDF,Python爬虫书PDF

2026年09月02日

34阅读

外国教程python,python编程教学视频

2026年09月02日

28阅读

python简明教程沈洁元,python详细基础教程

2026年09月02日

22阅读

python库包教程,python 包

2026年09月02日

27阅读

python教程大全集,python教程600集

2026年09月02日

28阅读

python入门教程完整版,python零基础入门全套教程视频

2026年09月02日

23阅读