井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋类似,由于棋盘一般不画边框,格线排成井字故得名。
游戏需要的工具仅为纸和笔,然后由分别代表O和X的两个游戏者轮流在格子里留下标记(一般来说先手者为X),任意三个标记形成一条直线,则为获胜。
不得不说,井字棋是我们上课时与同桌打发枯燥时光,必不可少的游戏。简单又有趣,但玩透了之后,基本是平局。
- 中心(4)
- 角(0、2、6、8)
- 边(1、3、5、7)
获胜规律:
先手下角,后手必中
先手下中,后手必角
否则,必有一个死棋
实现效果
这是一次我与AI对弈的过程:
请选择棋子X或者O(X先走,O后走):x
player先走!
0 | 1 | 2
_ | _ | _
3 | 4 | 5
_ | _ | _
6 | 7 | 8
请选择落子位置(0-8):3
0 | 1 | 2
_ | _ | _
X | 4 | 5
_ | _ | _
6 | 7 | 8
计算机人工智能AI落子位置: 4
0 | 1 | 2
_ | _ | _
X | O | 5
_ | _ | _
6 | 7 | 8
请选择落子位置(0-8):6
0 | 1 | 2
_ | _ | _
X | O | 5
_ | _ | _
X | 7 | 8
计算机人工智能AI落子位置: 0
O | 1 | 2
_ | _ | _
X | O | 5
_ | _ | _
X | 7 | 8
请选择落子位置(0-8):8
O | 1 | 2
_ | _ | _
X | O | 5
_ | _ | _
X | 7 | X
计算机人工智能AI落子位置: 7
O | 1 | 2
_ | _ | _
X | O | 5
_ | _ | _
X | O | X
请选择落子位置(0-8):1
O | X | 2
_ | _ | _
X | O | 5
_ | _ | _
X | O | X
计算机人工智能AI落子位置: 2
O | X | O
_ | _ | _
X | O | 5
_ | _ | _
X | O | X
请选择落子位置(0-8):5
O | X | O
_ | _ | _
X | O | X
_ | _ | _
X | O | X
平局!!!
井字棋的设计思路
棋盘采用包含9个元素的列表来实现
棋盘bord,
bord[0]到bord[8]存储代表棋子的字符串
字符串0到8代表未落子
字符串X
、O
表示两种棋子
程序的流程:
- 初始化棋盘
- 询问玩家选择棋子:棋子
X
先走,棋子O
后走 - 显示棋盘及落子布局
- 循环轮流落子
计算机人工智能(AI)落子算法如下:
- 如果某位置落子可以获胜,则选择该位置
- 否则,如果某个位置,玩家下一步落子可以获胜,则选择该位置
- 否则,按中心(4)、角(0、2、6、8)、边(1、3、5、7)顺序选择空的位置
就按照这个规律,我下不赢AI,把把都是平手…
判断输赢规则如下:
- 三条横线
0、1、2
3、4、5
6、7、8 - 三条竖线
0、3、6
1、4、7
2、5、8 - 两条对角线
0、4、8
2、4、6
以上八种情况的三个位置的棋子相同,则该棋子方赢棋。
如果全部位置落子,则平局
代码实现
def display_board(board):
"""显示棋盘"""
print("\t{0} | {1} | {2}".format(board[0], board[1], board[2]))
print("\t_ | _ | _")
print("\t{0} | {1} | {2}".format(board[3], board[4], board[5]))
print("\t_ | _ | _")
print("\t{0} | {1} | {2}".format(board[6], board[7], board[8]))
def legal_moves(board):
"""返回可落子的位置列表"""
moves = []#存放的是int类型
for i in range(9):
if board[i] in list("012345678"):
moves.append(i)
return moves
def getPlayerMove(board):
"""询问并确定玩家的选择落子位置,无效位置时重复询问"""
move = 9
while move not in legal_moves(board):
move = int(input("请选择落子位置(0-8):"))
return move
def getComputerMove(board, computerLetter, playerLetter):
"""核心算法:计算人工智能AI的落子位置"""
boardcopy = board.copy()
# 规则一:判断如果某位置落子可以获胜,则选择该位置
for move in legal_moves(boardcopy):
boardcopy[move] = computerLetter
if isWinner(boardcopy):
return move
boardcopy[move] = str(move)
# 规则二:某个位置玩家下一步落子可以获胜,则选择该位置
for move in legal_moves(boardcopy):
boardcopy[move] = playerLetter
if isWinner(boardcopy):
return move
boardcopy[move] = str(move)
# 规则三:按照中心、角、边的顺序选择空的位置
for move in (4,0,2,6,8,1,3,5,7):
if move in legal_moves(board):
return move
def isWinner(board):
"""判断所给的棋子是否获胜"""
WAYS_TO_WIN = {(0,1,2), (3,4,5), (6,7,8), (0,3,6), (1,4,7), (2,5,8), (0,4,8), (2,4,6)}
for r in WAYS_TO_WIN:
if board[r[0]] == board[r[1]] == board[r[2]]:
return True
return False
def isTie(board):
"""判断是否平局"""
for i in list("012345678"):
if i in board:
return False
return True
def tic_tac_toe():
"""井字棋"""
board = list("012345678")
playerLetter = input("请选择棋子X或者O(X先走,O后走):")
if playerLetter in ("X", "x"):
turn = "player"
playerLetter = "X"
computerLetter = "O"
else:
turn = "computer"
computerLetter = "X"
playerLetter = "O"
print("{}先走!".format(turn))
while True:
display_board(board)
if turn == 'player':
move = getPlayerMove(board)
board[move] = playerLetter
if isWinner(board):
display_board(board)
print("恭喜玩家获胜!")
break
else:
turn = "computer"
else:
move = getComputerMove(board, computerLetter, playerLetter)
print("计算机人工智能AI落子位置:", move)
board[move] = computerLetter
if isWinner(board):
display_board(board)
print("计算机人工智能AI获胜!")
break
else:
turn = "player"
if isTie(board):
display_board(board)
print('平局!!!')
break
if __name__ == '__main__':
tic_tac_toe()
参考资料: