A few of you got far enough to work on some functions for Tic Tic Toe in the lab yesterday. I did, too. Let's play a game or two using my program...
Now that the program can manage a game between two human players, it would be neat to have the computer play against me. To do that, we will need a few more functions. Let's write one.
Write a Python function legal_moves() that takes a game board as input and returns a list of all moves that the next player can make. Represent each move as a (row, column) tuple.
>>> display( board_4 ) ['o', ' ', 'x'] ['x', 'x', 'x'] [' ', 'o', 'o'] >>> print( legal_moves(board_4) ) [(0, 1), (2, 0)] >>> display( board_1 ) [' ', ' ', 'x'] ['o', ' ', 'x'] [' ', ' ', 'o'] >>> print( legal_moves(board_1) ) [(0, 0), (0, 1), (1, 1), (2, 0), (2, 1)]
Remember that I have already written the function is_occupied(board, row, col), which returns true if there is a token at board[row][col] and false otherwise.
The running total pattern returns. (Has it ever left us?) Here is my version of this function.
With this in hand, how could we have the program play one side of the game? It could choose a move at random from the legal moves available.
>>> from random import randint >>> moves = legal_moves(board_1) >>> moves [(0, 0), (0, 1), (1, 1), (2, 0), (2, 1)] >>> len( legal_moves(board_1) ) 5 >>> pos = randint( 0, len(legal_moves(board_1))-1 ) >>> moves[pos] (0, 1) >>> row, col = moves[pos] >>> row 0 >>> col 1
Now, all we need to do is to wire similar code into the code that gets a player's next move. For now, let's keep things simple and hard-wire the computer in as player 'x', who goes first. The program is choosing randomly, so it needs the head start!
Here is a version of my get_move_for() function. We can switch the computer to play 'o' by changing one character. (We should probably make that a named constant at the top of the file.) It plays well enough to amuse, and could probably entertain a child for a while.
Not bad for half a lab's work...
I asked you to write several function for this program in the lab exercise. I chose ones that were of increasing complexity, so that you could warm up into the task. That's a common way for programmers to work: pick a small task or two that we can solve relatively easily at first, so that we can get our minds around the data that we are using and the way it will flow between functions.
How did I know that we would want those functions at all? I have written many games like this before, so I bring experience from previous programs. But I also planned ahead and so had a design in mind. Here's the design I created:
Of course, this evolved a bit in the course of writing my program. For instance, I forgot that I would need to create an empty game board for our players to play on! I added that function after I implemented play().
Designing programs, even large programs, isn't any harder than anything else programmers do, but it does benefit from experience. We get experience from practice. A good friend of mine likes to say:
Good design comes from experience.
Experience comes from bad design.
Like most everything, there are skills you can learn that will help you become a better design. In computer science, we try to codify these skills and practices in the ways that engineers codify their knowledge. Your reading assignment for next week is your first step.
... issue writing make_board():
def make_board(): board =  for i in range(3): row = [' ', ' ', ' '] board.append(row) return board
Why not this?
def make_board(): board =  row = [' ', ' ', ' '] for i in range(3): board.append(row) return board
Many of you encountered this issue when writing the driver code for the randomness test in Lab 12.
... look into this code. Computing max and min. Choices for initial values. Alternative? Make a list of lengths, and use Python's built-in functions!
... values. Simple types.
... names. Variables. Arguments and parameters.
... complex types. Values. Mutability.
... wonder why Python has tuples as separate from lists? Immutability makes these issues disappear (while making us write different kind of code as a result).
Immutability, multi-core, parallel processing, and programming languages. Big trends these days!
Task (a) ...