参考学习:Python实现井字棋游戏

闲扯

井字棋(Tic-Tac-Toe),初高中进行打发时间的一种画x画o的游戏,3*3的格子组成,一方把行列斜行连成相同的就算获胜。

那么怎么利用进行人机对弈这种简单的小游戏那。我们先不急于写代码,先进行思考,程序的实现是进行方便人们的,我们设计井字棋,肯定想让程序智能化,能够最大程度的模拟人,所以我们设计一个无敌的“人”,最后的结果只能是玩家输或者平局,机器必不可能输。

顺着这个思想想,怎么让机器无敌,这个时候就要考虑这个游戏本身了,因为游戏简单,我们很轻松就可以推到想赢所对应的步骤,把这种思想步骤灌输给计算机,让他学习到,想输都难,大概这就是人工智能(AI)吧,不过我们的这个游戏简单,简易的不能准确的称为标准的人工智能,做不到AlphaGo那样可以对战世界冠军,但是总体AlphaGo也是通过不断学习不断增强的。

言归正传,说我们的井字棋。井字棋我们分为0-8,横着排就是这样。

想要获胜就要:

(第一个下角,后面的下中)(第一个下中,后面的下角)(不然的必定有一个死棋)

设计

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

棋盘为board

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

字符串0到8代表未落子

字符串XO表示两种棋子,也就是玩家和机器进行下的棋子

程序

1.先有一个棋盘

        棋盘的设计不唯一,可以设计多种样式的棋盘,有兴趣的话可以进行自行探索。

board = list("012345678")
def dis_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]))

2.进行询问:是x先走还是o先走

3.人机进行交互落子

AI寻求落子算法

首要目的是要确保AI的每一步都不能出错,一出错可能就满盘皆输

  •  AI判定某个位置可以赢那么就选择这个位置落子
  •  否则,AI进行判定如果玩家下一步落某个位置赢,那么AI不让他赢,就落子落在这个位   置
  •  否则,按照中心,角,边的位置进行落子
  • 这样就可以让AI立于不败之地了。

    AI先找到可以落子的位置

    def _moves(board):
        #寻求可落子的位置
        moves = []
        for i in range(9):
            if board[i] in list("012345678"):    #遍历了棋盘的位置如果位置为0-8那么这个位置可以落子
                moves.append(i)
        return moves

    询问玩家落子位置,无效落子重复询问

    def playermove(board):
        #询问并确定玩家的选择落子位置,无效落子重复询问
        move = 9
        while move not in _moves(board):
            move = int(input("请选择落子位置(0-8):"))
        return move

    参数:棋盘,AI棋子,玩家棋子

    并且运用winner函数,赢就返回True 

    def computermove(board,computerletter,playerletter):
        #核心算法:计算AI的落子位置
        boardcopy = board.copy()
    
        #规则一:判断如果某位置落子可以获胜,则选择这个位置
        for move in _moves(boardcopy):
            boardcopy[move] = computerletter
            if winner(boardcopy):
                return move
            boardcopy[move] = str(move)
    
        #规则二:某个位置玩家下一步落子就可以获胜,则选择该位置
        for move in _moves(boardcopy):
            boardcopy[move] = playerletter
            if winner(boardcopy):
                return move
            boardcopy[move] = str(move)
    
        #规则三:按照中心、角、边的选择空的位置
        for move in(4,0,2,6,8,1,3,5,7):
            if move in _moves(board):
                return move
    

    winner函数:判断怎样是获胜

    分为八种情况,三种横线,三种竖线,两种对角线

    def winner(board):
        #判断所给棋子是否获胜
        _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 _to_win:
            if board[r[0]] == board[r[1]] == board[r[2]]:
                return True
        return False

    Tie函数:还有判定平局的情况 

    def Tie(board):
        #判断是否平局
        for i in list("012345678"):
            if i in board:
                return False
        return True
    

    完整代码实现

    # python菜鸟
    # 2022.01.10
    def dis_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 _moves(board):
        #寻求可落子的位置
        moves = []
        for i in range(9):
            if board[i] in list("012345678"):       #遍历了棋盘的位置如果位置为0-8那么这个位置可以落子
                moves.append(i)
        return moves
    
    def playermove(board):
        #询问并确定玩家的选择落子位置,无效落子重复询问
        move = 9
        while move not in _moves(board):
            move = int(input("请选择落子位置(0-8):"))
        return move
    
    def computermove(board,computerletter,playerletter):
        #核心算法:计算AI的落子位置
        boardcopy = board.copy()
    
        #规则一:判断如果某位置落子可以获胜,则选择这个位置
        for move in _moves(boardcopy):
            boardcopy[move] = computerletter
            if winner(boardcopy):
                return move
            boardcopy[move] = str(move)
    
        #规则二:某个位置玩家下一步落子就可以获胜,则选择该位置
        for move in _moves(boardcopy):
            boardcopy[move] = playerletter
            if winner(boardcopy):
                return move
            boardcopy[move] = str(move)
    
        #规则三:按照中心、角、边的选择空的位置
        for move in(4,0,2,6,8,1,3,5,7):
            if move in _moves(board):
                return move
    
    def winner(board):
        #判断所给棋子是否获胜
        _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 _to_win:
            if board[r[0]] == board[r[1]] == board[r[2]]:
                return True
        return False
    
    def Tie(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(AI)——(x先走,o后走):")
        if playerletter in("X","x"):
            turn = "player"
            playerletter = "x"
            computerletter = "o"
        else:
            turn = "AI"
            computerletter = "x"
            playerletter = "o"
        print("{}先走!".format(turn))
    
        while True:
            dis_board(board)
            if turn == 'player':
                move = playermove(board)
                board[move] = playerletter
                if winner(board):
                    dis_board(board)
                    print("恭喜玩家获胜!")
                    break
                else:
                    turn = "AI"
            else:
                move = computermove(board, computerletter, playerletter)
                print("人工智能AI落子位置:",move)
                board[move] = computerletter
                if winner(board):
                    dis_board(board)
                    print("人工智能AI获胜!")
                    break
                else:
                    turn = "player"
            if Tie(board):
                dis_board(board)
                print('平局!')
                break
    
    
    if __name__=='__main__':
            tic_tac_toe()
    
    
    

    其中一个实现效果 

    请选择棋子x(玩家)或者o(AI)——(x先走,o后走):x
    player先走!
    	0 | 1 | 2
    	_ | _ | _
    	3 | 4 | 5
    	_ | _ | _
    	6 | 7 | 8
    请选择落子位置(0-8):8
    	0 | 1 | 2
    	_ | _ | _
    	3 | 4 | 5
    	_ | _ | _
    	6 | 7 | x
    人工智能AI落子位置: 4
    	0 | 1 | 2
    	_ | _ | _
    	3 | o | 5
    	_ | _ | _
    	6 | 7 | x
    请选择落子位置(0-8):2
    	0 | 1 | x
    	_ | _ | _
    	3 | o | 5
    	_ | _ | _
    	6 | 7 | x
    人工智能AI落子位置: 5
    	0 | 1 | x
    	_ | _ | _
    	3 | o | o
    	_ | _ | _
    	6 | 7 | x
    请选择落子位置(0-8):3
    	0 | 1 | x
    	_ | _ | _
    	x | o | o
    	_ | _ | _
    	6 | 7 | x
    人工智能AI落子位置: 0
    	o | 1 | x
    	_ | _ | _
    	x | o | o
    	_ | _ | _
    	6 | 7 | x
    请选择落子位置(0-8):7
    	o | 1 | x
    	_ | _ | _
    	x | o | o
    	_ | _ | _
    	6 | x | x
    人工智能AI落子位置: 6
    	o | 1 | x
    	_ | _ | _
    	x | o | o
    	_ | _ | _
    	o | x | x
    请选择落子位置(0-8):1
    	o | x | x
    	_ | _ | _
    	x | o | o
    	_ | _ | _
    	o | x | x
    平局!
    
    进程已结束,退出代码0
    

    遇到的一些问题

  • 缩进问题:python中是有着严格的缩进的,一旦缩进不规整,就会出现逻辑上的错误
  •  其他都是码代码的小问题,符号的错误,语言的错误,等等,需要后期认真纠正
  • 物联沃分享整理
    物联沃-IOTWORD物联网 » python实现井字棋

    发表评论