<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: xucenying</title>
    <description>The latest articles on Forem by xucenying (@xucenying).</description>
    <link>https://forem.com/xucenying</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1274434%2F7fce4fa2-a49a-4abf-8764-d33e42d4ff25.png</url>
      <title>Forem: xucenying</title>
      <link>https://forem.com/xucenying</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/xucenying"/>
    <language>en</language>
    <item>
      <title>Building a Terminal Sudoku Game in Python</title>
      <dc:creator>xucenying</dc:creator>
      <pubDate>Wed, 10 Sep 2025 21:43:18 +0000</pubDate>
      <link>https://forem.com/xucenying/building-a-terminal-sudoku-game-in-python-4np6</link>
      <guid>https://forem.com/xucenying/building-a-terminal-sudoku-game-in-python-4np6</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Object-Oriented Approach
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The Board class is responsible for the board's data and state. It handles creating the starting board and printing the board checking.&lt;/p&gt;

&lt;p&gt;The Game class manages the game flow. It handles user input and orchestrates the moves by calling methods on the Board instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Representing the Board
&lt;/h2&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Board&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removed_cells&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_board&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removed_cells&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove_numbers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_board&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Initialize a 9x9 board 
&lt;/span&gt;        &lt;span class="c1"&gt;# Generate a valid Sudoku board here
&lt;/span&gt;        &lt;span class="c1"&gt;# Then remove some numbers to create a puzzle
&lt;/span&gt;        &lt;span class="n"&gt;new_board&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="c1"&gt;# Create first row with numbers 1-9 shuffled
&lt;/span&gt;        &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The remove_numbers function removes 50 numbers from the board that was created for the player to guess.&lt;/p&gt;
&lt;h2&gt;
  
  
  Handling User Input
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_game&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting a new game of Sudoku!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;display_board&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;              
                &lt;span class="c1"&gt;# Prompt the user for input and split it by spaces
&lt;/span&gt;                &lt;span class="n"&gt;user_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter cell coordinates (row, col) or enter # twice to end game: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="c1"&gt;# Check if the user entered exactly two values
&lt;/span&gt;                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;##&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Game ended by user.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Validating a Solution
&lt;/h2&gt;

&lt;p&gt;The heart of the game is checking if a board is complete. The Game class handles this by checking four separate conditions:&lt;/p&gt;

&lt;p&gt;Are all numbers filled?&lt;/p&gt;

&lt;p&gt;Are all rows valid?&lt;/p&gt;

&lt;p&gt;Are all columns valid?&lt;/p&gt;

&lt;p&gt;Are all 3x3 sub-grids valid?&lt;/p&gt;

&lt;p&gt;An unfilled square holds a zero. Therefore, we just need to check for the presence of a zero to evaluate the first condition.&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Helper function to check for duplicates in a list of numbers
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;has_duplicates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# We use a set for an efficient check of unique numbers.
&lt;/span&gt;    &lt;span class="c1"&gt;# for a completely filled board.
&lt;/span&gt;    &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generating the Board
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.sudokuoftheday.com/creation" rel="noopener noreferrer"&gt;https://www.sudokuoftheday.com/creation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gamedev.stackexchange.com/questions/56149/how-can-i-generate-sudoku-puzzles/138228#138228" rel="noopener noreferrer"&gt;https://gamedev.stackexchange.com/questions/56149/how-can-i-generate-sudoku-puzzles/138228#138228&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;A few exciting next steps for this project could include:&lt;/p&gt;

&lt;p&gt;Implementing a solver using a backtracking algorithm.&lt;/p&gt;

&lt;p&gt;Adding a simple UI using a library like curses to handle single key presses and redraw the screen dynamically.&lt;/p&gt;

&lt;p&gt;Adding levels of difficulty by using different initial board states.&lt;/p&gt;

&lt;p&gt;Performing unit test.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;
  
  
  See the full code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/xucenying" rel="noopener noreferrer"&gt;
        xucenying
      &lt;/a&gt; / &lt;a href="https://github.com/xucenying/Sudoko_Terminal" rel="noopener noreferrer"&gt;
        Sudoko_Terminal
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A terminal Sudoku created for Codecademy portfolio
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Sudoku Terminal Game&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This is a terminal-based Sudoku game implemented in Python. The project includes a simple interface for playing Sudoku in the terminal.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project Structure&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;To install the required dependencies, run:&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Running the Game&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;To start the game, execute the following command:&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;python src/main.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contributing&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Contributions are welcome! Please feel free to submit a pull…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/xucenying/Sudoko_Terminal" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>cli</category>
      <category>python</category>
    </item>
  </channel>
</rss>
