2015-05-26 46 views
1

我正試圖解決基於岩石剪刀的編程挑戰。我的目標是給出一個遊戲移動列表,確定遊戲贏得了什麼舉動。我的問題是檢查遊戲是否獲勝。我有獲勝組合的列表,比方說遊戲電網:如何用數組值列表檢查數組?

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場 - 領帶。 (尚未實施)

我能做些什麼來檢查獲勝的舉動/有沒有人對如何解決我的代碼有任何建議?

回答

3

我認爲你需要的是使用一個類。我本可以試着修復你的代碼,但我認爲你需要重新考慮它。從邏輯上講,你可以把它分解成一個遊戲對象,跟蹤單個遊戲的動作。你可以簡單地做出一個動作,然後在每一步之後檢查是否贏得了比賽。

我不確定你是否熟悉類,但我認爲一個對象可以更好地實現一個tic tac toe遊戲。您還可以在其他許多場景中重新使用遊戲類。不僅僅是爲了確定每場比賽的勝利。在一個複雜的程序中,您甚至可以將遊戲對象傳遞給其他對象,以便它們可以以自己的方式與它進行交互。這超出了這個答案的範圍,但希望你明白我的觀點。

請嘗試下面的代碼,我特意對它進行了評論,並使它(希望)易於理解。這很長,但是它將每項任務分解開來,以便很容易地跟蹤正在發生的事情。 (至少對我而言)

您可以使用此代碼中的概念來修復您的實現。無論是使用我的代碼片段來修復你的或只是使用我的版本,如果你喜歡。

通過此代碼,遊戲對象可以追蹤它的轉向,每個玩家的動作,遊戲是否獲勝,遊戲是否結束,獲勝者是誰,以及玩過的動作數量。

另外,我有目的地編寫了代碼,以便它可以在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

該代碼可以同時蟒蛇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.