井字棋(Tic-Tac-Toe)
2015-07-21 09:06 FARAMIR 阅读(1178) 评论(0) 收藏 举报井字棋介绍:https://en.wikipedia.org/wiki/Tic-tac-toe
井字棋简单,但是获胜策略却和直觉不同,四角比中间重要性要高,而且先手有很大的获胜概率获胜(先手胜:91, 后手胜:44,平局:3),所以当你陷入劣势时,怎么选择打平就是一个不那么简单的事情。不过无聊大抵孤单,没有人一起玩就只能和电脑PK,就写了个弱智AI,没事就偷着乐!
AI的获胜策略也很简单,先遍历检测棋盘副本的空格子看下一步能否获胜,如果有机会获胜,返回格子的下标,然后再棋盘上移动,其次,检测对手能否下一步获胜,提前封堵,如果前面两步都没返回的话,就说明双方都没有一步必胜的招式,这时候就得依次抢占四个角落,中间和剩余的位置。

1 import random 2 3 def draw_board(board): 4 """board is a 3X3 list containing the moves either ' ' representing 5 no moves there or 'x' or 'o' representing actual moves""" 6 for i in range(7): 7 if i%2 == 0: 8 print '+'.join(['---']*3) 9 else: 10 col = [] 11 for j in range(11): 12 if j%2 == 0: 13 col.append(' ') 14 elif j==3 or j==7: 15 col.append('|') 16 else: 17 col.append(board[i/2][j/4]) 18 print ''.join(col) 19 20 def who_goes_first(): 21 if random.randint(0, 1): 22 return 'AI' 23 else: 24 return 'P' 25 26 def play_again(): 27 print "Once Again?(y for Yes, n for No)" 28 return raw_input().lower().startswith('y') 29 30 def make_move(board, letter, move): 31 seq = move-1 32 board[2-seq/3][seq%3] = letter 33 34 def is_winner(bo, le): 35 # Given a board and a player’s letter, this function returns True if that player has won. 36 # We use bo instead of board and le instead of letter so we don’t have to type as much. 37 return ((bo[0][0] == le and bo[0][1] == le and bo[0][2] == le) or # across the top 38 (bo[1][0] == le and bo[1][1] == le and bo[1][2] == le) or # across the middle 39 (bo[2][0] == le and bo[2][1] == le and bo[2][2] == le) or # across the bottom 40 (bo[0][0] == le and bo[1][0] == le and bo[2][0] == le) or # down the left side 41 (bo[0][1] == le and bo[1][1] == le and bo[2][1] == le) or # down the middle 42 (bo[0][2] == le and bo[1][2] == le and bo[2][2] == le) or # down the right side 43 (bo[0][0] == le and bo[1][1] == le and bo[2][2] == le) or # diagonal 44 (bo[0][2] == le and bo[1][1] == le and bo[2][0] == le)) # diagonal 45 46 def get_board_copy(board): 47 dup = [[' ']*3 for i in range(3)] 48 for i in range(3): 49 for j in range(3): 50 dup[i][j] = board[i][j] 51 return dup 52 53 def is_move_avail(board, move): 54 seq = move-1 55 return board[2-seq/3][seq%3] == ' ' 56 57 def get_P_moves(board): 58 move = '' 59 while move not in [1, 2, 3, 4, 5, 6, 7, 8, 9] or not is_move_avail(board, move): 60 print "Please input your next move('1-9')" 61 move = input() 62 return move 63 64 def is_board_full(board): 65 for i in range(3): 66 for j in range(3): 67 if board[i][j] == ' ': 68 return False 69 return True 70 71 def choose_randomly(board, avail): 72 possible_moves = [] 73 for i in avail: 74 if is_move_avail(board, i): 75 possible_moves.append(i) 76 if len(possible_moves) != 0: 77 return random.choice(possible_moves) 78 else: 79 return None 80 81 def get_AI_moves(board, AI, P): 82 #check if AI can win in the next move 83 for i in range(1, 10): 84 copy = get_board_copy(board) 85 if is_move_avail(board, i): 86 make_move(copy, AI, i) 87 if is_winner(copy, AI): 88 return i 89 90 #else check if P can win in the next move and block the first found move 91 for i in range(1, 10): 92 copy = get_board_copy(board) 93 if is_move_avail(board, i): 94 make_move(copy, P, i) 95 if is_winner(copy, P): 96 return i 97 98 #The key to win is to occupy the corners, so move there if available 99 move = choose_randomly(board, [1, 3, 7, 9]) 100 print move 101 if move != None: 102 return move 103 104 #of second priority is the center element 105 if is_move_avail(board, 5): 106 return 5 107 108 #Then the rest 109 return choose_randomly(board, [2, 4, 6, 8]) 110 111 if __name__ == '__main__': 112 113 while True: 114 Board = [[' ']*3 for i in range(3)] 115 P, AI = 'x', 'o' 116 turn = who_goes_first() 117 print "{0} will go first".format(turn) 118 GameOn = True 119 120 while GameOn: 121 if turn == 'P': 122 move = get_P_moves(Board) 123 make_move(Board, P, move) 124 draw_board(Board) 125 126 if is_winner(Board, P): 127 draw_board(Board) 128 print "GameOver You've Won!" 129 GameOn = False 130 else: 131 if is_board_full(Board): 132 draw_board(Board) 133 print "Tie" 134 break 135 else: 136 turn = 'AI' 137 138 else: 139 move = get_AI_moves(Board, AI, P) 140 make_move(Board, AI, move) 141 draw_board(Board) 142 143 if is_winner(Board, AI): 144 draw_board(Board) 145 print "GameOver AI has Won!" 146 GameOn = False 147 else: 148 if is_board_full(Board): 149 draw_board(Board) 150 print "Tie" 151 break 152 else: 153 turn = 'P' 154 155 if not play_again(): 156 break 157 158 ##---+---+--- 159 ## x | o | x 160 ##---+---+--- 161 ## o | x | o 162 ##---+---+--- 163 ## x | o | 164 ##---+---+---
注:
- python 2.7中input和raw_input的区别,python3中合并了
- 数据结构很简单,3X3的list of lists来表示棋盘。井字棋位置和小键盘一致。
- 参考文献: http://www.guokr.com/article/4754/
浙公网安备 33010602011771号