Опубликован: 12.07.2013 | Доступ: свободный | Студентов: 735 / 20 | Длительность: 37:41:00
Лекция 15:


< Лекция 14 || Лекция 15: 12345 || Лекция 16 >

Printing the Scores to the Screen

239.   def showPoints(playerTile, computerTile):
240.             # Prints out the current score.
241.             scores = getScoreOfBoard(mainBoard)
242.             print('You have %s points. The computer has %s points.' % (scores[playerTile], scores[computerTile]))

showPoints() simply calls the getScoreOfBoard() function and then prints out the player's score and the computer's score. Remember that getScoreOfBoard() returns a dictionary with the keys 'X' and 'O' and values of the scores for the X and O players.

That's all the functions we define for our Reversi game. The code starting on line 246 will implement the actual game and make calls to these functions when they are needed.

The Start of the Game

246. print('Welcome to Reversi!') 
248. while True:
249.     # Reset the board and game.
250.     mainBoard = getNewBoard()
251.     resetBoard(mainBoard)
252.     playerTile, computerTile = enterPlayerTile()
253.      showHints = False
254.     turn = whoGoesFirst()
255.     print('The ' + turn + ' will go first.')

The while loop on line 248 is the main game loop. The program will loop back to line 248 each time we want to start a new game. First we get a new game board data structure by calling getNewBoard() and set the starting tiles by calling resetBoard(). mainBoard is the main game board data structure we will use for this program. The call to enterPlayerTile() will let the player type in whether they want to be 'X' or 'O', which is then stored in playerTile and computerTile.

showHints is a Boolean value that determines if hints mode is on or off. We originally set it to off by setting showHints to False.

The turn variable is a string will either have the string value 'player' or 'computer', and will keep track of whose turn it is. We set turn to the return value of whoGoesFirst(), which randomly chooses who will go first. We then print out who goes first to the player on line 255.

Running the Player's Turn

257.     while True:
258.          if turn == 'player':
259.             # Player's turn.
260.              if showHints:
261.                 validMovesBoard = getBoardWithValidMoves (mainBoard, playerTile)
262.                 drawBoard(validMovesBoard)
263.             else:
264.                 drawBoard(mainBoard)
265.              showPoints(playerTile, computerTile)

The while loop that starts on line 257 will keep looping each time the player or computer takes a turn. We will break out of this loop when the current game is over.

Line 258 has an if statement whose body has the code that runs if it is the player's turn. (The else-block that starts on line 282 has the code for the computer's turn.) The first thing we want to do is display the board to the player. If hints mode is on (which it is if showHints is True), then we want to get a board data structure that has '.' period characters on every space the player could go.

Our getBoardWithValidMoves() function does that, all we have to do is pass the game board data structure and it will return a copy that also contains '.' period characters. We then pass this board to the drawBoard() function.

If hints mode is off, then we just pass mainBoard to drawBoard().

After printing out the game board to the player, we also want to print out the current score by calling showPoints().

266.             move = getPlayerMove(mainBoard, playerTile)

Next we let the player type in their move. getPlayerMove() handles this, and its return value is a two-item list of the X and Y coordinate of the player's move. getPlayerMove() makes sure that the move the player typed in is a valid move, so we don't have to worry about it here.

Handling the Quit or Hints Commands

267.              if move == 'quit':
268.                 print('Thanks for playing!')
269.                  sys.exit() # terminate the program
270.             elif move == 'hints':
271.                  showHints = not showHints
272.                 continue
273.             else:
274.                 makeMove(mainBoard, playerTile, move[0], move [ 1])

If the player typed in the string 'quit' for their move, then getPlayerMove() would have returned the string 'quit'. In that case, we should call the sys.exit() to terminate the program.

If the player typed in the string 'hints' for their move, then getPlayerMove() would have returned the string 'hints'. In that case, we want to turn hints mode on (if i was off) or off (if it was on). The showHints = not showHints assignment statement handles both of these cases, because not False evaluates to True and not True evaluates to False. Then we run the continue statement to loop back (turn ha not changed, so it will still be the player's turn after we loop).

Make the Player's Move

Otherwise, if the player did not quit or toggle hints mode, then we will call makeMove () to make the player's move on the board.

276.              if getValidMoves(mainBoard, computerTile) == [] :
277.                 break
278.             else:
279.                 turn = 'computer'

After making the player's move, we call False to see if the computer could possibly make any moves. If False returns a blank list, then there are no more moves left that the computer could make (most likely because the board is full). In that case, we break out of the while loop and end the current game.

Otherwise, we set turn to 'computer'. The flow of execution skips the else-block and reaches the end of the while-block, so execution jumps back to the while statement on line 257. This time, however, it will be the computer's turn.

Running the Computer's Turn

281.         else:
282.             # Computer's turn.
283.             drawBoard(mainBoard)
284.              showPoints(playerTile, computerTile)
285.              input('Press Enter to see the computer\'s move.')
286.             x, y = getComputerMove(mainBoard, computerTile)
287.             makeMove(mainBoard, computerTile, x, y)

The first thing we do when it is the computer's turn is call drawBoard() to print out the board to the player. Why do we do this now? Because either the computer was selected to make the first move of the game, in which case we should display the original starting picture of the board to the player before the computer makes its move. Or the player has gone first, and we want to show what the board looks like after the player has moved but before the computer has gone.

After printing out the board with drawBoard(), we also want to print out the current score with a call to showPoints().

Next we have a call to input() to pause the script while the player can look at the board. This is much like how we use input() to pause the program in our Jokes chapter. Instead of using a print() call to print a string before a call to input(), you can pass the string as a parameter to input(). input() has an optional string parameter. The string we pass in this call is 'Press Enter to see the computer\'s move.'.

After the player has looked at the board and pressed Enter (any text the player typed is ignored since we do not assign the return value of input() to anything), we call getComputerMove() to get the X and Y coordinates of the computer's next move. We store these coordinates in variables x and y, respectively.

Finally, we pass x and y, along with the game board data structure and the computer's tile to the makeMove() function to change the game board to reflect the computer's move. Our call to getComputerMove() got the computer's move, and the call to makeMove () makes the move on the board.

289.              if getValidMoves(mainBoard, playerTile) == [] :
290.                 break
291.             else:
292.                 turn = 'player'

Lines 289 to 292 are very similar to lines 276 to 279. After the computer has made its move, we check if there exist any possible moves the human player can make. If getValidMoves() returns an empty list, then there are no possible moves. That means the game is over, and we should break out of the while loop that we are in.

Otherwise, there is at least one possible move the player should make, so we should set turn to 'player'. There is no more code in the while-block after line 292, so execution loops back to the while statement on line 257.

Drawing Everything on the Screen

294.               # Display the final score.
295.               drawBoard(mainBoard)
296.               scores = getScoreOfBoard(mainBoard)
297.              print('X scored %s points. O scored %s points.' % (scores['X'], scores['O']))
298.               if scores[playerTile] > scores[computerTile]:
299.                         print('You beat the computer by %s points! Congratulations!' % (scores[playerTile] - scores
300.               elif scores[playerTile] < scores[computerTile]:
301.                       print('You lost. The computer beat you by %s
points.' % (scores[computerTile] - scores[playerTile])) 
302.    else: 
303.                       print('The game was a tie!')

Line 294 is the first line beyond the while-block that started on line 257. This code is executed when we have broken out of that while loop, either on line 290 or 277. (The while statement's condition on line 257 is simply the value True, so we can only exit the loop through break statements.)

At this point, the game is over. We should print out the board and scores, and determine who won the game. getScoreOfBoard() will return a dictionary with keys 'X' and 'O' and values of both players' scores. By checking if the player's score is greater than, less than, or equal to the computer's score, we can know if the player won, if the player lost, or if the player and computer tied.

Subtracting one score from the other is an easy way to see by how much one player won over the other. Our print() calls on lines 299 and 301 use string interpolation to put the result of this subtraction into the string that is printed.

Ask the Player to Play Again

305.     if not playAgain() : 
306.                       break

The game is now over and the winner has been declared. We should call our playAgain() function, which returns True if the player typed in that they want to play another game. If playAgain() returns False (which makes the if statement's condition True), we break out of the while loop (the one that started on line 248), and since there are no more lines of code after this while-block, the program terminates.

Otherwise, playAgain() has returned True (which makes the if statement's condition False), and so execution loops back to the while statement on line 248 and a new game board is created.

Summary: Reviewing the Reversi Game

The AI may seem almost unbeatable, but this isn't because the computer is very smart. The strategy it follows is very simple: move on the corner if you can, otherwise make the move that will flip over the most tiles. We could do that, but it would take us a long time to figure out how many tiles would be flipped for every possible valid move we could make. But calculating this for the computer is very simple. The computer isn't smarter than us, it's just much faster!

This game is very similar to Sonar because it makes use of a grid for a board. It is also like the Tic Tac Toe game because there is an AI that plans out the best move for it to take. This chapter only introduced one new concept: using the bool() function and the fact that empty lists, blank strings, and the integer 0 all evaluate to False in the context of a condition.

Other than that, this game used programming concepts that you already knew! You don't have to know very much about programming in order to create interesting games. However, this game is stretching how far you can get with ASCII art. The board took up almost the entire screen to draw, and the game didn't have any color.

Later in this book, we will learn how to create games with graphics and animation, not just text. We will do this using a module called Pygame, which adds new functions and features to Python so that we can break away from using just text and keyboard input.

< Лекция 14 || Лекция 15: 12345 || Лекция 16 >