【问题标题】:How can I check an array with a list of array values?如何使用数组值列表检查数组?
【发布时间】:2015-05-26 03:36:47
【问题描述】:

我正在尝试解决基于石头剪刀布的编程挑战。我的目标是给出一个游戏动作列表,确定游戏在哪个动作中获胜。我的问题是检查游戏是否获胜。我有一个获胜组合列表,例如游戏网格是:

1, 2, 3,
4, 5, 6,
6, 7, 8,

那么获胜组合将是例如:4, 5, 6,因为它是连续 3 个。

我的问题是我不知道如何有效地检查所有这些获胜组合。我试图列出获胜组合的列表,然后通过它运行游戏板以检查获胜者,这太棒了,只是它不起作用,我不知道如何合理地接近它。

这是我的代码:

def is_winner(grid):
    player1_wins = ['X','X','X']
    player2_wins = ['O','O','O']
    player_win = [player1_wins, player2_wins]

    win1 = [0,3,6] #[1,4,7]
    win2 = [1,4,7] #[2,5,8]
    win3 = [2,5,8] #[3,6,9]
    win4 = [0,4,8] #[1,5,9]
    win5 = [6,7,8] #[7,8,9]
    win6 = [3,4,5] #[4,5,6]
    win7 = [0,1,2] #[1,2,3]
    win8 = [6,7,8] #[7,8,9]
    winning_grids = [win1, win2, win3, win4, win5, win6, win7, win8]

    if any(grid[winning_grids]) == any(player_win): # !!!! Broken code here !!!!
        return True # Game won
    else:
        return False

def tic_tac_toe(games):
    for game in range(games):
        grid = ['1','2','3',
                '4','5','6',
                '7','8','9']
        moves = [int(x) for x in raw_input().split()]

        turn = 1
        for move in moves:
            if turn % 2 != 0:
                grid[move-1] = 'X'
            elif turn % 2 == 0:
                grid[move-1] = 'O'
            if is_winner(grid):
                print("Game over on turn %d" % turn)

        print(grid)
tic_tac_toe(input())

示例输入如下所示:

3
7 5 4 1 9 2 8 3 6
5 1 3 7 6 4 2 9 8
5 1 2 8 6 4 7 3 9

如果是 3 场比赛,玩家 1 先上,玩家 2 是每个字符串中的下一个数字。

答案是:第 1 局 - 第 7 局。第 2 局 - 第 6 局,第 3 局 - 平局。 (尚未实施)

我可以做些什么来检查获胜的举动/有人对如何修复我的代码有任何建议吗?

【问题讨论】:

    标签: python arrays python-2.7 tic-tac-toe


    【解决方案1】:

    我认为你需要的是使用一个类。我本可以尝试修复您的代码,但我认为您需要彻底重新考虑它。

    从逻辑上讲,您可以将其分解为一个游戏对象,以跟踪单个游戏的动作。您可以简单地进行一次移动,然后在每次移动后检查游戏是否已获胜。

    我不确定您是否熟悉类,但我认为井字游戏最好实现为对象。您还可以在许多其他场景中重用游戏类。不仅仅是为了确定每场比赛的获胜方式。在复杂的程序中,您甚至可以将游戏对象传递给其他对象,以便它们以自己的方式与之交互。这超出了这个答案的范围,但希望你明白我的意思。

    试试下面的代码,我特意对它进行了大量注释,并使其(希望)易于理解。它很长,但它分解了每项任务,以便轻松了解正在发生的事情。 (至少对我来说是)

    您可以使用此代码中的概念来修复您的实现。要么使用我的代码片段来修复你的代码,要么如果你喜欢就使用我的版本。

    使用此代码,游戏对象会跟踪轮到谁、每个玩家的移动、游戏是否已获胜、游戏是否结束、获胜的玩家是谁以及移动的次数。

    另外,我特意编写了代码,以便它可以在 Python 2.7 和 3.4 上运行。通常,我尝试只为 Python 3x 编写代码,但这是我的偏好。

    class TicTacToeGame:
        """
        A class that implements a tic tac toe game
        """
    
        # This is a class variable that contains
        # a list of all the winning combos
        winningCombos = [
            [1, 2, 3],
            [4, 5, 6],
            [7, 8, 9],
            [1, 4, 7],
            [2, 5, 8],
            [3, 6, 9],
            [1, 5, 9],
            [3, 5, 7]
        ]
    
        def __init__(self):
            """
            Init method. This gets called when you create a new game object
            We simply use this method to initialize all our instance variables
            """
    
            # The current player. Either X or O
            self.currentPlayer = 'X'
    
            # List of player x moves
            self.playerXMoves = []
    
            # List of player o moves
            self.playerOMoves = []
    
            # Whether or not the game has been won
            self.isWon = False
    
            # Whether or not the game is over
            self.isOver = False
    
            # The winning player
            self.winningPlayer = None
    
            # The number of moves played
            self.numberOfMovesPlayed = 0
    
        def doMakeAMoveAtPos(self, pos):
            """
            Makes a move in the game at the specified position
            1 is the first position, 5 is the center position, etc
    
            @param pos: The position (1 through 9)
            @type pos: int
            @rtype: None
            """
    
            # If the game has already been won
            if self.isWon:
                raise ValueError('The game has been won')
    
            # If the game is over, nobody won
            if self.isOver:
                raise ValueError('The game is a tie')
    
            # Make sure that the position is within range
            if pos < 1 or pos > 9:
                raise ValueError('Invalid position. Should be between 1 and 9')
    
            # Make sure the position isn't already taken
            if pos in self.playerXMoves or pos in self.playerOMoves:
                raise ValueError('The position: ' + str(pos) + ' is already taken')
    
            # Get the current player
            currentPlayer = self.currentPlayer
    
            # If the current player is X
            if currentPlayer == 'X':
    
                # Add the move and switch to player O
                currentPlayerMoves = self.playerXMoves
                currentPlayerMoves.append(pos)
                self.currentPlayer = 'O'
    
            # Otherwise, the current player is O
            else:
    
                # Add the move and switch to player X
                currentPlayerMoves = self.playerOMoves
                currentPlayerMoves.append(pos)
                self.currentPlayer = 'X'
    
            # Increment the number of plays.. You could just check the length of
            # playerXMoves and playerOMoves to get the total number of moves, but
            # we are going to keep track to avoid more code later
            self.numberOfMovesPlayed += 1
    
            # If the number of plays is 9, the game is over
            if self.numberOfMovesPlayed == 9:
                self.isOver = True
    
            # See if the game has been won
    
            # If there hasn't been enough moves to win yet, no winner
            if len(currentPlayerMoves) < 3:
                return
    
            # Iterate through each winning combo
            for winningCombo in self.winningCombos:
    
                # If each number is in the player's moves, the game has been won
                if set(winningCombo) <= set(currentPlayerMoves):
    
                    self.isWon = True
                    self.winningPlayer = currentPlayer
                    return
    
    
    
    # OK... Our Class has been defined.
    # Now it's time to play tic tac toe.
    
    # Define an input string. How you get this is up to you
    # Change this to different numbers to see what you get.
    inputString = '3 7 5 4 1 9 2 8 3 6 5 1 3 7 6 4 2 9 8 5 1 2 8 6 4 7 3 9'
    
    # Parse the input string into a list of integers
    moves = [int(move) for move in inputString.split()]
    
    # Create the initial game
    game = TicTacToeGame()
    
    # Set the number of games to 1 (This is the first game after all)
    numberOfGames = 1
    
    # Go through all the moves 1 by 1
    for pos in moves:
    
        # Try to make a move in the current game
        try:
            game.doMakeAMoveAtPos(pos)
    
        # But, since the input is unpredictable, we need to catch errors
        # What's to stop the input from being '1 1 1 1 1 1 1 1 1', etc
        # You can't keep playing position number 1 over and over
        except ValueError as exc:
    
            # Do what you want with the exception.
            # For this example, I'm just gonna print it
            # and move on the the next move
            print(exc)
            continue
    
        # If the game has been won
        if game.isWon:
            print('Game ' + str(numberOfGames) + ' Won On Move: ' + str(game.numberOfMovesPlayed) + ' Winning Player: ' + str(game.winningPlayer))
    
            # Since the game was won, create a new game
            game = TicTacToeGame()
    
            # And increment the game number
            numberOfGames += 1
    
        # If the game is a tie
        elif game.isOver:
            print('Game ' + str(numberOfGames) + ' Tie')
    
            # Since the game was a tie, create a new game
            game = TicTacToeGame()
    
            # And increment the game number
            numberOfGames += 1
    
    # If there is an unfinished game, we can report this as well
    if game.numberOfMovesPlayed > 0:
        print('Game ' + str(numberOfGames) + ' was not finished')
    

    有很多可以改进的地方,但你明白了(我希望)当我运行这段代码时,我得到以下输出:

    Game 1 Won On Move: 7 Winning Player: X
    The position: 3 is already taken
    Game 2 Won On Move: 6 Winning Player: O
    The position: 2 is already taken
    The position: 8 is already taken
    The position: 6 is already taken
    The position: 4 is already taken
    Game 3 Won On Move: 9 Winning Player: X
    Game 4 was not finished
    

    【讨论】:

      【解决方案2】:

      @RayPerea 做了一个很好的回答。但是如果您不能按照您的要求使用类或者只是不想使用,我将采用不同的方法。

      这篇文章背后的想法是展示 python 的功能方面。 “函数式”编程的主要概念之一是您无法访问函数的外部范围。我通过将player_oneplayer_two 添加到全局命名空间来作弊。但它很容易转化为 100% 的功能代码。这是good tutorial

      此代码可以在 python 2 和 3 上运行。

      唯一要做的就是将保存的输入更改为实际输入。

      player_one = 'X'
      player_two = 'O'
      
      # You can add "HAZ THE MOVEZ" joke here:
      def has_the_moves(player, moves):
          if len(moves) <= 2:
              return None
      
          win1 = (0,3,6) #[1,4,7]
          win2 = (1,4,7) #[2,5,8]
          win3 = (2,5,8) #[3,6,9]
          win4 = (0,4,8) #[1,5,9]
          win5 = (6,7,8) #[7,8,9]
          win6 = (3,4,5) #[4,5,6]
          win7 = (0,1,2) #[1,2,3]
          win8 = (6,7,8) #[7,8,9]
          winning_grids = [win1, win2, win3, win4, win5, win6, win7, win8]
      
          # We will return a player name (not bool) if he is a winner.
          # This name will be used later.
          tried = [set(posibility) <= set(moves) for posibility in winning_grids]
          return player if any(tried) else None
      
      def is_winner(grid):
      
          player_one_moves = [i for i, x in enumerate(grid) if x == player_one]
          player_two_moves = [i for i, x in enumerate(grid) if x == player_two]
      
          player_one_won = has_the_moves(player_one, player_one_moves)
          player_two_won = has_the_moves(player_two, player_two_moves)
      
          # If we a have a winner:
          if player_one_won or player_two_won:
              return player_one_won if player_one_won else player_two_won
      
          return None
      
      def end_game(winner=None, last_turn=False):
          """ This function can be used when you find a winner,
          or when the end of the game is reached. 
          """
          if last_turn:
              print('Game ended in a draw.')
          if winner:
              print('Player {} won.'.format(winner))
      
      def tic_tac_toe(games):
      
          # For testing purposes let's save user's input:
          saved_moves = ['7 5 4 1 9 2 8 3 6', '5 1 3 7 6 4 2 9 8', '5 1 2 8 6 4 7 3 9']
      
          for game in range(games):
              grid = [str(x) for x in range(1, 10)] # one-liner
              moves = [int(x) for x in saved_moves[game].split()] # TODO: make sure to change saved_moves[game]
      
              for turn, move in enumerate(moves):
                  grid[move - 1] = player_one if turn % 2 == 0 else player_two
      
                  # Stop the game?
                  winner = is_winner(grid)
                  if winner:
                      print('Game over on turn {}.'.format(turn + 1))
                      end_game(winner=winner)
                      break; # no more iterations required.
                  if turn == len(moves) - 1:
                      end_game(last_turn=True)
      
      if __name__ == '__main__':
          # We running 3 games:
          saved_games_number = 3
          tic_tac_toe(saved_games_number)
      

      结果是:

      Game over on turn 7.
      Player X won.
      Game over on turn 6.
      Player O won.
      Game ended in a draw.
      

      【讨论】:

        猜你喜欢
        • 2017-03-12
        • 2021-12-10
        • 2018-10-06
        • 1970-01-01
        • 2013-04-20
        • 1970-01-01
        • 1970-01-01
        • 2013-10-23
        • 1970-01-01
        相关资源
        最近更新 更多