【问题标题】:Generate all possible board positions of tic tac toe生成所有可能的井字棋棋盘位置
【发布时间】:2020-04-29 17:53:33
【问题描述】:

这有点类似于这个问题:Python generate all possible configurations of numbers on a "board",但我正在尝试在 Python 中实现,并且我想包含生成的仅部分完成的板。

井字游戏中有 3^9 (19683) 个棋盘位置。

这是我生成每个板子的代码,其中板子数组的每个元素都是一个板子:

boards = []
temp_boards = []

for i in range(0 , 19683) : 
    c = i
    temp_boards = []
    for ii in range(0 , 9) : 
        temp_boards.append(c % 3)
        c = c // 3
    boards.append(temp_boards)
  • 0对应O
  • 1对应X
  • 2 对应于“尚未填补的职位”

我会错过任何职位吗?

【问题讨论】:

  • 9 X 的板子可以接受吗?
  • @ScottHunter 不,就在三个 X 或 O 对齐的位置,以及 X 或 O 的混合,或者在剩余位置没有任何内容。
  • 然后这段代码会生成 LOT 的不可接受的板。
  • 因此,不能接受带有“尚未填补的职位”的董事会?
  • 大声笑,所以基本上你是说 O 先行。在这种情况下,O 有 9 个选择,还是只有 3 个?请edit澄清问题。

标签: python algorithm


【解决方案1】:

如果您认为玩家轮流进行,当有人获胜时游戏停止,则可能的棋盘数将少于 X、O 和空白单元格的最大组合所建议的数量。您也不能计算填充了所有 X 或所有 Os 或任何 X 和 Os 数量之差大于 1 的组合的板。

您可以通过递归模拟从 X 开始到 O 开始的移动来获得该数字:

axes = [(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 isWin(board):
    return any("".join(board[p] for p in axis) in ["XXX","OOO"] for axis in axes)

def validBoards(board="."*9,player=None):
    if player == None:
        yield board  # count the empty board
        for b in validBoards(board,player="X"): yield b # X goes 1st
        for b in validBoards(board,player="O"): yield b # O goes 1st
        return
    opponent = "XO"[player=="X"]
    for pos,cell in enumerate(board):
        if cell != ".": continue
        played = board[:pos]+player+board[pos+1:] # simulate move
        yield played                              # return the new state
        if isWin(played): continue                # stop game upon winning
        for nextBoard in validBoards(played,opponent):
            yield nextBoard # return boards for subsequent moves        

输出:

distinctBoards = set(validBoards())  # only look at distinct board states

allStates = len(distinctBoards)
print(allStates)  # 8533 counting all intermediate states

winningStates = sum(isWin(b) for b in  distinctBoards)
print(winningStates) # 1884  (so 942 for a specific starting player)

filledStates  = sum(("." not in b) for b in distinctBoards)        
print(filledStates) #  156 states where all cells are filled 

finalStates  = sum(isWin(b) or ("." not in b) for b in distinctBoards)        
print(finalStates) #  1916 end of game states (win or draw) 

earlyWins = sum(isWin(b) and ("." in b) for b in distinctBoards)
print(earlyWins) # 1760 wins before filling the board

draws  = finalStates - winningStates        
print(draws) #  32 ways to end up in a draw 

lastWins = filledStates-draws
print(lastWins) # 124 wins on the 9th move (i.e filling the board)

fastWins = sum( isWin(b) and b.count(".") == 4 for b in distinctBoards)
print(fastWins) # 240 fastest wins by 1st player (in 3 moves)

fastCounters = sum( isWin(b) and b.count(".") == 3 for b in distinctBoards)
print(fastCounters) # 296 fastest wins by 2nd player (in 3 moves)

如果您需要更快的实现,这里有一个优化版本的函数,它只返回不同的状态并利用它来跳过移动序列树的整个分支:

def validBoards(board="."*9,player=None,states=None):
    if player == None:
        result  = {board}  # count the empty board
        result |= validBoards(board,player="X",states=set()) # X goes 1st
        result |= validBoards(board,player="O",states=set()) # O goes 1st
        return result
    opponent = "XO"[player=="X"]
    for pos,cell in enumerate(board):
        if cell != ".": continue
        played = board[:pos]+player+board[pos+1:] # simulate move
        if played in states : continue            # skip duplicate states
        states.add(played)                        # return the new state
        if isWin(played): continue                # stop game upon winning 
        validBoards(played,opponent,states)       # add subsequent moves 
    return states

【讨论】:

  • validBoards返回的值有多少重复?
  • validBoards() 返回所有移动序列的棋盘状态(包括 1 移动、2 移动之后的状态等),因此其中有很多重复的状态(1,099,891 中的 1,091,358)。
  • 所以 99% 都是重复的?!?
  • 99% 的移动序列是的,但只有 56% 的可能组合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多