Writing A Connect Four Game Reader In Python
6 min readA recent assignment handed out in the boot camp I’m a part of, PDX Code Guild, was to design a program that could read a file full of moves for populating a Connect Four game board. The following post is a walk through of how I solved this problem.
Reading the file
First we need to read the file that contains the moves our players are making. The file consists of single lines of numbers ranging from 1-7 alternating between players. So our connect-four-moves.txt
would look something like the following:
# 4 <-- player one's selection
# 3 <-- player two's selection
# 5
# 6
# 4
def open_file(filename, encoding='utf-8'):
"""
Returns a list of the lines of text.
"""
with open(filename, encoding=encoding) as f:
return f.readlines()
text = open_file('connect-four-moves.txt')
print(text) # ['4\n', '3\n', '5\n', '6\n', '4\n']
Grouping the players moves
Now we can read the data from the text file and group the moves together for each player. We will also remove that pesky newline character we are seeing returned from our open_file
function using rstrip()
. We will add the moves to two different lists depending on whether or not i
is even or odd and then return those two lists in a tuple for later unpacking.
def read_plays(moves):
player_one = []
player_two = []
for i in range(len(moves)):
if i % 2 == 0:
player_two.append(moves[i].rstrip())
else:
player_one.append(moves[i].rstrip())
return (player_one, player_two) # (['4', '5', '4'], ['3', '6'])
Building & Printing the Board
Our board is just a list of lists so we will loop over the height of the board and append our rows of lists and then loop over our width and append an empty string for each space. Our print_board
function is pretty self-explanatory 😉
BOARD_HEIGHT = 6
BOARD_WIDTH = 7
def build_board():
board = []
for y in range(BOARD_HEIGHT):
board.append([])
for x in range(BOARD_WIDTH):
board[y].append(' ')
return board
def print_board(board):
for row in board:
print(row)
What our board now looks like in the terminal:
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
Making a Move on the Board
We will create another function that accepts three arguments: the current player, the selection made by the player, and the board. Using a nifty little trick we will loop through the board counting down instead of counting up the indices using reversed()
By doing this now we will place the player’s mark at the bottom of our board instead of at the top just like if you were dropping your piece into position on a real Connect Four board. We will look to see if the space selected on the board is taken or not, and if it is not taken we will replace the blank space with our player’s icon and reassign the value to that location on the board. We will then break from the loop and return the board as to not populate all the blank spaces in that column with the player’s icon.
def make_move(player, column, board):
# reversed() will cause 'i' to start at 6 instead of 1
for i in reversed(range(BOARD_HEIGHT)):
if board[i][column - 1] == ' ':
board[i][column - 1] = board[i][column - 1].replace(' ', player)
break
return board
Playing out the Game
To play out our player’s moves on the board we will pass the moves we are returning from read_plays
and the game board to a new function play_game
. By setting a variable called current_player
we can toggle who is up to make a move on the board later on with our if statements. We will start off by unpacking our tuple to get the player’s moves and setup a while loop that will terminate when both lists are empty.
When we get to making our moves we will want to access the first index of the list so instead of just calling the pop
method, who’s default behavior is to return the last index of a list, we will pass an argument to pop
of which index we want it to return. For those keeping score at home move
is actually of type string so we need to cast it to an integer or trying to index in the make_move
function will blow up. Lastly we will return the board and print it for every player’s move.
PLAYER_ONE_ICON = 'X'
PLAYER_TWO_ICON = 'O'
def play_game(moves, board):
current_player = 1
p1_moves, p2_moves = moves
while p1_moves or p2_moves:
if current_player == 1:
move = p1_moves.pop(0)
current_player += 1
board = make_move(PLAYER_ONE_ICON, int(move), board)
print_board(board)
elif current_player == 2:
move = p2_moves.pop(0)
current_player -= 1
board = make_move(PLAYER_TWO_ICON, int(move), board)
print_board(board)
Ready to Go!
And we are set to run the game!
text = open_file('connect-four-moves.txt')
moves = read_plays(text)
board = build_board()
play_game(moves, board)
What our game board looks like now:
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', 'X', ' ', ' ', ' ']
[' ', ' ', 'X', 'O', 'O', 'X', ' ']
Bonus: Clean up
To clean up the output in the terminal we can use the os
module and create a function to insert before printing our board out. This function is basically Python telling the OS to run the command to clear the terminal for either Windows or macOS/Linux. Now our terminal will only show one board instead of a bunch.
from os import name, system
def cls():
system('cls' if name == 'nt' else 'clear')
def print_board(board):
cls()
for row in board:
print(row)
Wrap Up
It was an interesting task and if you think this was an easy assignment I did get stuck a few times and did some real pondering. If you’ve got questions feel free to contact me and I’ll help you understand the code. You can see the full code on my GitHub.
Related Articles
Python Scripting In iTerm2
How to use the Python Scripting API in iTerm2 to open several tabs and execute commands in those tabs.
Recursion & Memoization In Python
Working through Fibonacci using recursion and memoization in Python.
Getting Started With Python3
Installation and setup of Python3 on macOS & development with Visual Studio Code.
Building A Black Jack Advice Generator With Python
How to build a simple black jack advice generator using Python.
Cody is a Christian, USN Veteran, Jayhawk, and an American expat living outside of Bogotá, Colombia. He is currently looking for new opportunities in the tech industry.