python3+tkinter实现的黑白棋,代码完整 100%能运行
今天分享给大家的是采用Python3+tkinter制作而成的小项目——黑白棋
tkinter是Python内置的图形化模块,简单易用,一般的小型UI程序可以快速用它实现,具体的tkinter相关知识王老师会在以后开辟专栏单独讲解
我们先来看看这个黑白棋项目吧
一、项目演示
二、代码
完整代码如下,用到的素材(图片等)下载地址为:https://www.itprojects.cn/web/material/details.html?id=15
1 from tkinter import * 2 from tkinter.messagebox import * 3 import random 4 5 root = Tk('黑白棋') 6 root.title("黑白棋(更多项目实例请访问www.itprojects.cn)") 7 # 加载图片 8 imgs = [PhotoImage(file='black.png'), PhotoImage(file='white.png'), PhotoImage(file='board.png'), PhotoImage(file='info2.png')] 9 10 11 def resetBoard(board): 12 """重置棋盘""" 13 for x in range(8): 14 for y in range(8): 15 board[x][y] = 'none' 16 # Starting pieces: 17 board[3][3] = 'black' 18 board[3][4] = 'white' 19 board[4][3] = 'white' 20 board[4][4] = 'black' 21 22 23 def getNewBoard(): 24 """开局时建立新棋盘""" 25 board = [] 26 for i in range(8): 27 board.append(['none'] * 8) 28 return board 29 30 31 def isValidMove(board, tile, xstart, ystart): 32 """是否是合法走法,如果合法返回需要翻转的棋子列表""" 33 # 如果该位置已经有棋子或者出界了,返回False 34 if not isOnBoard(xstart, ystart) or board[xstart][ystart] != 'none': 35 return False 36 # 临时将tile 放到指定的位置 37 board[xstart][ystart] = tile 38 if tile == 'black': 39 otherTile = 'white' 40 else: 41 otherTile = 'black' 42 # 要被翻转的棋子 43 tilesToFlip = [] 44 for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]: 45 x, y = xstart, ystart 46 x += xdirection 47 y += ydirection 48 if isOnBoard(x, y) and board[x][y] == otherTile: 49 x += xdirection 50 y += ydirection 51 if not isOnBoard(x, y): 52 continue 53 # 一直走到出界或不是对方棋子的位置 54 while board[x][y] == otherTile: 55 x += xdirection 56 y += ydirection 57 if not isOnBoard(x, y): 58 break 59 # 出界了,则没有棋子要翻转OXXXXX 60 if not isOnBoard(x, y): 61 continue 62 # 是自己的棋子OXXXXXXO 63 if board[x][y] == tile: 64 while True: 65 x -= xdirection 66 y -= ydirection 67 # 回到了起点则结束 68 if x == xstart and y == ystart: 69 break 70 # 需要翻转的棋子 71 tilesToFlip.append([x, y]) 72 # 将前面临时放上的棋子去掉,即还原棋盘 73 board[xstart][ystart] = 'none' # restore the empty space 74 # 没有要被翻转的棋子,则走法非法。翻转棋的规则。 75 if len(tilesToFlip) == 0: # If no tiles were flipped, this is not a valid move. 76 return False 77 return tilesToFlip 78 79 80 def isOnBoard(x, y): 81 """是否出界""" 82 return x >= 0 and x <= 7 and y >= 0 and y <= 7 83 84 85 def getValidMoves(board, tile): 86 """获取可落子的位置""" 87 validMoves = [] 88 for x in range(8): 89 for y in range(8): 90 if isValidMove(board, tile, x, y) != False: 91 validMoves.append([x, y]) 92 return validMoves 93 94 95 def getScoreOfBoard(board): 96 """获取棋盘上黑白双方的棋子数""" 97 xscore = 0 98 oscore = 0 99 for x in range(8): 100 for y in range(8): 101 if board[x][y] == 'black': 102 xscore += 1 103 if board[x][y] == 'white': 104 oscore += 1 105 return {'black': xscore, 'white': oscore} 106 107 108 def whoGoesFirst(): 109 """决定谁先走""" 110 if random.randint(0, 1) == 0: 111 return 'computer' 112 else: 113 return 'player' 114 115 116 def makeMove(board, tile, xstart, ystart): 117 """将一个tile棋子放到(xstart, ystart)""" 118 tilesToFlip = isValidMove(board, tile, xstart, ystart) 119 if tilesToFlip == False: 120 return False 121 board[xstart][ystart] = tile 122 for x, y in tilesToFlip: # tilesToFlip是需要翻转的棋子列表 123 board[x][y] = tile # 翻转棋子 124 return True 125 126 127 def getBoardCopy(board): 128 """复制棋盘""" 129 dupeBoard = getNewBoard() 130 for x in range(8): 131 for y in range(8): 132 dupeBoard[x][y] = board[x][y] 133 return dupeBoard 134 135 136 def isOnCorner(x, y): 137 """是否在角上""" 138 return (x == 0 and y == 0) or (x == 7 and y == 0) or (x == 0 and y == 7) or (x == 7 and y == 7) 139 140 141 def getComputerMove(board, computerTile): 142 """电脑走法,AI""" 143 # 获取所以合法走法 144 possibleMoves = getValidMoves(board, computerTile) 145 if not possibleMoves: # 如果没有合法走法 146 print("电脑没有合法走法") 147 return None 148 149 # 打乱所有合法走法 150 random.shuffle(possibleMoves) 151 # [x, y]在角上,则优先走,因为角上的不会被再次翻转 152 for x, y in possibleMoves: 153 if isOnCorner(x, y): 154 return [x, y] 155 bestScore = -1 156 for x, y in possibleMoves: 157 dupeBoard = getBoardCopy(board) 158 makeMove(dupeBoard, computerTile, x, y) 159 # 按照分数选择走法,优先选择翻转后分数最多的走法 160 score = getScoreOfBoard(dupeBoard)[computerTile] 161 if score > bestScore: 162 bestMove = [x, y] 163 bestScore = score 164 return bestMove 165 166 167 def isGameOver(board): 168 """是否游戏结束""" 169 for x in range(8): 170 for y in range(8): 171 if board[x][y] == 'none': 172 return False 173 return True 174 175 176 def drawQiPan(): 177 """画棋盘""" 178 img1 = imgs[2] 179 cv.create_image((360, 360), image=img1) 180 cv.pack() 181 182 183 def callback(event): 184 """走棋""" 185 global turn 186 # print ("clicked at", event.x, event.y,turn) 187 # x=(event.x)//40 #换算棋盘坐标 188 # y=(event.y)//40 189 if (gameOver == False and turn == 'computer'): # 没轮到玩家走棋 190 return 191 col = int((event.x - 40) / 80) # 换算棋盘坐标 192 row = int((event.y - 40) / 80) 193 if mainBoard[col][row] != "none": 194 showinfo(title="提示", message="已有棋子") 195 if makeMove(mainBoard, playerTile, col, row) == True: # 将一个玩家棋子放到(col, row) 196 if getValidMoves(mainBoard, computerTile) != []: 197 turn = 'computer' 198 # 电脑走棋 199 if getComputerMove(mainBoard, computerTile) == None: 200 turn = 'player' 201 showinfo(title="玩家继续", message="玩家继续") 202 else: 203 computerGo() 204 # 重画所有的棋子和棋盘 205 drawAll() 206 drawCanGo() 207 if isGameOver(mainBoard): # 游戏结束,显示双方棋子数量 208 scorePlayer = getScoreOfBoard(mainBoard)[playerTile] 209 scoreComputer = getScoreOfBoard(mainBoard)[computerTile] 210 outputStr = gameoverStr + "玩家:" + str(scorePlayer) + ":" + "电脑:" + str(scoreComputer) 211 showinfo(title="游戏结束提示", message=outputStr) 212 213 214 def computerGo(): 215 """电脑走棋""" 216 global turn 217 if (gameOver == False and turn == 'computer'): 218 x, y = getComputerMove(mainBoard, computerTile) # 电脑AI走法 219 makeMove(mainBoard, computerTile, x, y) 220 savex, savey = x, y 221 # 玩家没有可行的走法了,则电脑继续,否则切换到玩家走 222 if getValidMoves(mainBoard, playerTile) != []: 223 turn = 'player' 224 else: 225 if getValidMoves(mainBoard, computerTile) != []: 226 showinfo(title="电脑继续", message="电脑继续") 227 computerGo() 228 229 230 def drawAll(): 231 """重画所有的棋子和棋盘""" 232 drawQiPan() 233 for x in range(8): 234 for y in range(8): 235 if mainBoard[x][y] == 'black': 236 cv.create_image((x * 80 + 80, y * 80 + 80), image=imgs[0]) 237 cv.pack() 238 elif mainBoard[x][y] == 'white': 239 cv.create_image((x * 80 + 80, y * 80 + 80), image=imgs[1]) 240 cv.pack() 241 242 243 def drawCanGo(): 244 """画提示位置""" 245 list1 = getValidMoves(mainBoard, playerTile) 246 for m in list1: 247 x = m[0] 248 y = m[1] 249 cv.create_image((x * 80 + 80, y * 80 + 80), image=imgs[3]) 250 cv.pack() 251 252 253 if __name__ == '__main__': 254 # 初始化 255 gameOver = False 256 gameoverStr = 'Game Over Score ' 257 mainBoard = getNewBoard() 258 resetBoard(mainBoard) 259 turn = whoGoesFirst() 260 showinfo(title="游戏开始提示", message=turn + "先走!") 261 print(turn, "先走!") 262 if turn == 'player': 263 playerTile = 'black' 264 computerTile = 'white' 265 else: 266 playerTile = 'white' 267 computerTile = 'black' 268 computerGo() 269 270 # 设置窗口 271 cv = Canvas(root, bg='green', width=720, height=780) 272 # 重画所有的棋子和棋盘 273 drawAll() 274 drawCanGo() 275 cv.bind("<Button-1>", callback) 276 cv.pack() 277 root.mainloop()