Build a Sudoku Game and Learn State Management in React

Sudoku is one of my favorite logic-based number-placement puzzles. Due to the lack of quality Sudoku apps on the web and app stores, I decided to build my own version. It is packed with user-friendly and beginner-friendly features that make the game much more enjoyable. You can play it here. In this post, I will talk about designing, managing and working with the game’s state for the main UIs. You will read about how the right state design helps to keep the code clean and pleasant to work with. I hope it will help you reason, structure and manage an application’s state.

Game Rules

peers: cells belonging to the same column, row or square

The Game

Game generation

Represent the Puzzle in 2D Array

with each cell’s object contains its current value as well as its notes.

The Overall Game State

  • determine the game’s progress: know whether the game is completed and how many numbers are left for each group of peers, cells belonging to the same column, row or square.
  • track possible conflicts within each peer group: know the number of times a number is used per peer group(a complete group is one with each number used exactly once)

You can identify conflicts by comparing a cell’s numeric value with values of its 24 peers(8 per column, row or square) and determine the game’s progress by scanning the entire 9x9 puzzle. However, this approach is inefficient, verbose in code and hard to understand. To keep the implementation performant, clean and pleasant to work with, the game state will track the number of times each number used on a peer group basis. On initialization it will generate the puzzle and create count objects for all the peer groups:

The Cell Component

The cell component lights up with different colors signaling useful information about its current value, relationship to the selected cell, conflicts, and notes based on the game’s current state:

Computing the Cell Component’s Inputs

component methods for getting selected cell and setting the selected coordinates

With the getSelectedCell() method in the Game component, I can now infer the values of { isSelected, sameValue, isPeer, conflict} by comparing the current cell with the selected:

The Number Control Component

The NumberControl component needs:

  • a callback that would update the selected cell’s value on user clicks
  • a computed value of the number’s progress

fillNumber(number), a Game component’s function to update the selected cell’s value is written to create handlers of user clicks on the NumberControl components:

The number’s progress is computed by the following two steps:

  1. Per column, row and square groups, get the number of groups already have the number filled
  2. Take the minimum of the three values as the progress for the number

Now the Game component has what it needs to render the NumberControl components for the numbers, 1 to 9:

The Tool Components

In order to undo or redo an update to the game, it must keep track of its update history. An array object is used to keep a linear history of user’s updates to the game. The code is also extended to keep track of the history of board updates:

initialize the game state with a history array and historyOffset

With a history array and its current historyOffset in hand, redo/undo updates are just decrement/increment updates to historyOffset of the array:

Erasing a cell is as simple as updating its current value to null. Hinting at an unfilled cell is also trivial since the correct value can be obtained from the solution in the state:

For erase and hint, I created erasedSelected and filledSelectedWithSolution respecitively

Now I have everything I need to render the action elements and pass them the correct update handlers:

Now a user has a proper Sudoku game to play with!

Wrapping Things Up

Related Materials

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sitian Liu

Chasing great designs, delightful user experiences and happy developer experiences. Find me at https://www.sitianliu.com/