Python实现井字棋游戏

python案例 专栏收录该内容
14 篇文章 11 订阅

井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋类似,由于棋盘一般不画边框,格线排成井字故得名。

游戏需要的工具仅为纸和笔,然后由分别代表O和X的两个游戏者轮流在格子里留下标记(一般来说先手者为X),任意三个标记形成一条直线,则为获胜

不得不说,井字棋是我们上课时与同桌打发枯燥时光,必不可少的游戏。简单又有趣,但玩透了之后,基本是平局。

在这里插入图片描述

  • 中心(4)
  • 角(0、2、6、8)
  • 边(1、3、5、7)

获胜规律:
先手下角,后手必中
先手下中,后手必角
否则,必有一个死棋

井字棋的设计思路

棋盘采用包含9个元素的列表来实现

棋盘bord,

bord[0]到bord[8]存储代表棋子的字符串

在这里插入图片描述

字符串0到8代表未落子

字符串XO表示两种棋子

程序的流程:

  1. 初始化棋盘
board = list("012345678")
  1. 询问玩家选择棋子:棋子X先走,棋子O后走
  2. 显示棋盘及落子布局
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]))
  1. 循环轮流落子

计算机人工智能(AI)落子算法如下:

  • 如果某位置落子可以获胜,则选择该位置
  • 否则,如果某个位置,玩家下一步落子可以获胜,则选择该位置
  • 否则,按中心(4)、角(0、2、6、8)、边(1、3、5、7)顺序选择空的位置

就按照这个规律,我下不赢AI,把把都是平手…

AI需要先得到棋盘可落子位置(棋盘该位置若为‘O’、‘X’则表明已被落子)

def legal_moves(board):
    """返回可落子的位置列表"""
    moves = []#存放的是int类型
    for i in range(9):
        if board[i] in list("012345678"):
            moves.append(i)
    return moves

三个参数:棋盘(数据类型:列表)、AI棋子类型、玩家棋子类型
调用函数isWinner(),赢则返回True

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

判断输赢规则如下:

  1. 三条横线
    0、1、2;
    3、4、5;
    6、7、8
  2. 三条竖线
    0、3、6;
    1、4、7;
    2、5、8
  3. 两条对角线
    0、4、8;
    2、4、6

以上八种情况的三个位置的棋子相同,则该棋子方赢棋。

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

代码实现

tic-tac-toe.py

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

运行效果

这是一次我与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
平局!!!
评论 2 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值