For this project, I used GitHub Copilot to assist with generating the inital project structure. I leveraged GitHub Copilot and Gemini to help with some of the boilerplate and common functions.
Building a classic game like Sudoku is an excellent way to sharpen your programming skills. It's a project that might seem simple on the surface, but it quickly introduces you to essential concepts like data structures, algorithms, and robust user input handling. In this post, I'll walk you through some of the core components of my terminal-based Sudoku game built in Python.
An Object-Oriented Approach
Instead of a single script, I've broken down the game into two classes: Board and Game. This separation of concerns makes the code much cleaner and easier to manage.
The Board class is responsible for the board's data and state. It handles creating the starting board and printing the board checking.
The Game class manages the game flow. It handles user input and orchestrates the moves by calling methods on the Board instance.
Representing the Board
The Board class represents the Sudoku grid using a 2D array, or a list of lists. This is a clean and intuitive way to model the grid, with each inner list representing a row.
class Board:
def __init__(self):
self.removed_cells = []
self.board = self.create_board()
self.board, self.removed_cells = self.remove_numbers()
def create_board(self):
# Initialize a 9x9 board
# Generate a valid Sudoku board here
# Then remove some numbers to create a puzzle
new_board = [[0 for _ in range(9)] for _ in range(9)]
# Create first row with numbers 1-9 shuffled
nums = random.sample(range(1, 10), 9)
The remove_numbers function removes 50 numbers from the board that was created for the player to guess.
Handling User Input
The Game class is responsible for all user interaction. It prompts the user for row and column coordinates and validates the input to prevent common errors before passing the move to the Board instance.
A key technique here is combining string.strip().split() to clean and parse the input and a try...except block to gracefully handle non-numeric input. This makes the program much more user-friendly and stable
class Game:
def __init__(self, board):
self.board = board
def start_game(self):
print("Starting a new game of Sudoku!")
self.board.display_board()
def make_move(self):
while True:
try:
# Prompt the user for input and split it by spaces
user_input = input("Enter cell coordinates (row, col) or enter # twice to end game: ").strip().split()
# Check if the user entered exactly two values
print(user_input)
if user_input == ['##']:
print("Game ended by user.")
break
Validating a Solution
The heart of the game is checking if a board is complete. The Game class handles this by checking four separate conditions:
Are all numbers filled?
Are all rows valid?
Are all columns valid?
Are all 3x3 sub-grids valid?
An unfilled square holds a zero. Therefore, we just need to check for the presence of a zero to evaluate the first condition.
For the next three conditions, a powerful and efficient trick is to use a set. Sets only store unique values, so you can easily detect duplicates by comparing the length of a list with the length of a set created from that list.
# Helper function to check for duplicates in a list of numbers
def has_duplicates(numbers):
# We use a set for an efficient check of unique numbers.
# for a completely filled board.
numbers = [n for n in numbers]
return len(numbers) != len(set(numbers))
This concise check is the basis for validating every row, column, and sub-grid in the board, making the validation routine surprisingly simple and readable.
Generating the Board
The logic for generating a valid starting Sudoku board is a complex algorithm in itself. For this project, I drew inspiration from the techniques outlined on these websites:
https://www.sudokuoftheday.com/creation
https://gamedev.stackexchange.com/questions/56149/how-can-i-generate-sudoku-puzzles/138228#138228
Future Improvements
A few exciting next steps for this project could include:
Implementing a solver using a backtracking algorithm.
Adding a simple UI using a library like curses to handle single key presses and redraw the screen dynamically.
Adding levels of difficulty by using different initial board states.
Performing unit test.
Building a Sudoku game is a rewarding project that touches on many fundamental concepts. The process of breaking down the problem into smaller, manageable functions—like input validation and board validation—is a great way to improve your overall programming skills.
See the full code
xucenying
/
Sudoko_Terminal
A terminal Sudoku created for Codecademy portfolio
Sudoku Terminal Game
This is a terminal-based Sudoku game implemented in Python. The project includes a simple interface for playing Sudoku in the terminal.
Project Structure
sudoku-terminal
├── src
│ ├── main.py # Entry point of the application
│ ├── board.py # Contains the Board class for managing the Sudoku board
│ ├── game.py # Contains the Game class for managing game logic
│ └── utils.py # Contains utility functions for the game
├── tests
│ ├── test_board.py # Unit tests for the Board class
│ ├── test_game.py # Unit tests for the Game class
│ └── test_utils.py # Unit tests for utility functions
├── requirements.txt # Lists project dependencies
└── README.md # Project documentation
Installation
To install the required dependencies, run:
pip install -r requirements.txt
Running the Game
To start the game, execute the following command:
python src/main.py
Contributing
Contributions are welcome! Please feel free to submit a pull…
Top comments (0)