DEV Community

Cover image for Building a Terminal Sudoku Game in Python
xucenying
xucenying

Posted on

Building a Terminal Sudoku Game in Python

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

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

GitHub logo 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)