Programming lesson
Mastering 2D Arrays with Find Four: A Step-by-Step Python Lab Tutorial
Learn how to implement the classic Find Four (Connect Four) game in Python while mastering 2D arrays, input validation, and game logic. Perfect for COP3504c students.
Introduction to 2D Arrays with Find Four
In this tutorial, we'll break down the COP3504c Lab 02: Find Four Game, a classic programming assignment that teaches you how to work with 2D arrays in Python. By recreating the popular Connect Four game, you'll learn essential skills like array indexing, input validation, and game state management. This lab is a rite of passage for many CS students, and understanding it will prepare you for more complex projects like AI-powered game bots or even data structures for apps.
Understanding the Game Board as a 2D Array
The Find Four board is essentially a 2D list (list of lists) where each cell holds a character: '.' for empty, 'x' for Player 1, and 'o' for Player 2. The board is stored in row-major order, but note that row 0 is the bottom of the board. This reversed indexing mimics how chips fall to the lowest available row.
Think of it like a social media feed where new posts appear at the top, but the oldest stay at the bottom. In Find Four, the newest chip sits at the top, but the board is stored bottom-first. This is a common trick in game programming to simplify dropping logic.
Creating the Initial Board
The function get_initial_board(rows, columns) returns a 2D list filled with '.'. For a 4x5 board, it looks like:
board = [
['.', '.', '.', '.', '.'], # row 0 (bottom)
['.', '.', '.', '.', '.'], # row 1
['.', '.', '.', '.', '.'], # row 2
['.', '.', '.', '.', '.'] # row 3 (top)
]Notice that the first list in the outer list represents the bottom row. This is crucial for the insert_chip function.
Printing the Board
The print_board function must display the board from top to bottom. Since row 0 is bottom, you need to iterate from the last row to the first. A simple loop with reversed() works:
def print_board(board):
for row in reversed(board):
print('|' + ' '.join(row) + '|')This prints each row with spaces between chips and vertical bars on the sides. The top border is a line of underscores, and the bottom border is a line of dashes. Pay close attention to the exact formatting in the assignment output.
Dropping a Chip: The insert_chip Function
When a player selects a column, the chip must fall to the lowest empty row in that column. This is like dropping a coin into a vending machine – it falls until it hits another coin or the bottom. In code, you loop from row 0 upward until you find an empty cell ('.'). The function returns the row where the chip lands.
def insert_chip(board, column, chip):
for row in range(len(board)):
if board[row][column] == '.':
board[row][column] = chip
return row
return -1 # column fullThis function assumes the column is valid and not full – but those checks happen elsewhere. The assignment requires that error handling (like column full) is done during input, not inside insert_chip.
Checking for a Win
The is_win_state(chip, board, row, column) function checks if the last placed chip (at row, column) creates a line of four. You only need to check horizontal and vertical lines (not diagonal, per the lab spec). This is a huge time-saver compared to full Connect Four.
Horizontal Check
Count consecutive chips of the same type to the left and right of the placed chip. If the total count (including the chip itself) is 4 or more, it's a win.
def is_win_state(chip, board, row, column):
# Horizontal
count = 0
for c in range(column - 3, column + 4):
if 0 <= c < len(board[0]) and board[row][c] == chip:
count += 1
if count >= 4:
return True
else:
count = 0
# Vertical
count = 0
for r in range(row - 3, row + 4):
if 0 <= r < len(board) and board[r][column] == chip:
count += 1
if count >= 4:
return True
else:
count = 0
return FalseThis approach uses a sliding window of size 7 centered on the placed chip. It's efficient and avoids double counting.
Checking for a Draw
The is_board_full function simply checks if any cell contains '.'. If none, the board is full and the game ends in a draw.
def is_board_full(board):
for row in board:
if '.' in row:
return False
return TrueInput Validation and Error Handling
The lab emphasizes robust error handling. You must validate:
- Board dimensions: must be integers between 4 and 25 inclusive.
- Column selection: must be an integer within the valid column range, and the column must not be full.
- Non-numeric inputs: catch
ValueErrorwhen converting input to int.
Use loops to keep asking until valid input is provided. This is a common pattern in real-world applications like form validation in web apps or input sanitization in AI chatbots.
Putting It All Together: Game Loop
The main game loop alternates between players, displays the board, gets input, places chips, and checks for win/draw. Here's a skeleton:
def play_game():
rows = get_dimension('height')
cols = get_dimension('width')
board = get_initial_board(rows, cols)
print_board(board)
current_player = 1
while True:
chip = 'x' if current_player == 1 else 'o'
col = get_column(board, cols)
row = insert_chip(board, col, chip)
print_board(board)
if is_win_state(chip, board, row, col):
print(f'Player {current_player} won the game!')
break
if is_board_full(board):
print('Draw game! Players tied.')
break
current_player = 2 if current_player == 1 else 1Testing and Debugging Tips
Test with small boards (4x4) and trace through the win logic manually. Use print statements to check board state. The ZyLabs unit tests expect exact output, so match the formatting including spaces and newlines.
This lab is like building a mini-game for a gaming platform – you learn how data structures drive gameplay. Mastering 2D arrays here will help you later with image processing (pixel grids), spreadsheets, or even neural network weight matrices.
Conclusion
By completing this lab, you'll have a solid grasp of 2D arrays, input validation, and game logic in Python. These skills are foundational for more advanced topics like AI for games, data analysis, and backend development. Keep practicing, and soon you'll be able to build your own games or contribute to open-source projects.