今天分享給大家的是採用Python3+tkinter製作而成的小專案——黑白棋
tkinter是Python內建的圖形化模組,簡單易用,一般的小型UI程式可以快速用它實現,具體的tkinter相關知識王老師會在以後開闢專欄單獨講解
我們先來看看這個黑白棋專案吧
一、專案演示
二、程式碼
完整程式碼如下,用到的素材(圖片等)下載地址為:https://www.itprojects.cn/detail.html?example_id=f00fd7f9722b363f9dc15cf08d80e212
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()