Make Three in a Row, Part 3
Another post about making a game as I’m learning Python. Now with a more top down approach. I iterated over these steps back and forth, but here’s the resulting write-up before coding.
Describe the problem (thoroughly!)
This game is played on a 3x3 board, with 9 squares that are empty at the start. Two players take turns to make marks. Traditionally played with pen and paper, but I’m writing a script to play in the terminal. The first player uses X and the second is 0. If a player gets three of their marks to form a row — either horizontal, vertical or diagonal — they win the game. If all 9 squares are filled without either X or O creating three in a row, the outcome is a draw.
Research (more than I initially think I need to)
Read a bit on both Tic-tac-toe and m,n,k-game. Oh yeah, and Three Men's Morris is the name of the game where you can move the pieces. I remember we had a small magnetic board like this to play in the car when I was a kid. But in Norwegian, we just called this game also “three in a row”.
Tic-tac-toe is a futile game, it will always end in a draw if played optimally. It is also definitely a solved game. I used to play a lot of Othello back in the day, and was surprised to see it is considered only partially solved, in the same category as chess.
Analysts have estimated the number of legal positions in Othello is at most 10^28, and it has a game-tree complexity of approximately 10^58. Mathematically, Othello still remains unsolved. Experts have not absolutely resolved what the outcome of a game will be where both sides use perfect play. However, analysis of thousands of high quality games (most of them computer-generated) appears to lead to a reliable conclusion (pending actual proof if true) that, on the standard 8×8 board, perfect play on both sides results in a draw.
Thankfully, tic-tac-toe is simpler… here we are dealing with:
- 765 essentially different positions
- 138 terminal board positions
🤔 I’m not sure what the difference between those two are. But I’m going to leave game theory for now, and get back to making my simple version for two humans to make the decisions.
There are 9 squares to fill, so the player who starts can get 5 and the other only 4. But the game could end before all squares are occupied. That didn’t initially occur to me, that this is actually how the game needs to work, in case one player is not quite following. 😜
I can name the positions like this:
1 2 3
4 5 6
7 8 9
Would be sweet if I figure out how to output something like this as the game progresses:
- - - - - - - 0 - - 0 - 0 0 -
- X - - X - - X - - X X - X X
0 - - 0 X - 0 X - 0 X - 0 X -
Find the key concepts
- board / grid
- squares / space
- empty
- marked / taken
- squares / space
- players
- playerX
- player0
- play
- start
- move
- three-in-a-row
- horizontal
- vertical
- diagonal
- result
- winner X
- winner 0
- draw
I think now… 🤔 that I should try to not get too caught up in doing this exactly like the class heavy object-oriented LPTHW exercise 43 approach. Because what I’m making here is not that advanced, and making it work any way I can will be fine.
Pseudooooooooo 👻
Shitty first draft!
dictonary to collect all the moves of a game
list to store just moves by player X
list to store just moves by player 0
list with the 8 possible winning combos
loop (for 9? counting items in dict or list?)
ask player for their move
if square is empty
update dict with move
elif square is occupied
try again
else
result
if winning_combo
elif all squares occupied
draw
else
play again
That won’t work. Some iterations later…
list for info about empty squares
list to collect moves by player X
list to collect moves by player 0
winning combos (8 possible three-in-a-row)
loop
if empty squares
ask player for input
remove number from one list
add number to the other list
elif winning combo for X
declare X winner
elif winning combo for 0
declare 0 winner
elif no empty squares and no winning combo
declare draw
else
I need to differentiate between the players. So keep track of turns?
list for info about empty squares
list to collect moves by player X
list to collect moves by player 0
something to track who’s turn it is next
winning combos (8 possible three-in-a-row)
if empty squares AND next turn for X
input from player X
remove number from empty squares
add number to moves by player X
elif empty squares AND next turn for 0
input from player 0
remove number from empty squares
add number to moves by player 0
elif winning combo for X
declare X winner
elif winning combo for 0
declare 0 winner
elif no empty squares AND no winning combo
declare draw
else
loop back and continue
Probably don’t have everything I need here yet, but I think I’m getting close enough to start coding. This looks waaaaay more like a plan than previous early stabs. So let’s go! 🚀