Sunteți pe pagina 1din 9

12,231,709 members (60,039 online)

articles

quick answers

Sign in

discussions

community

Search for articles, questions, tips

help

Articles General Programming Game Development Games

Sudoku Game in Java


Eric Beijer, 18 Apr 2012

CPOL

4.80 (30 votes)

Rate this:

A Sudoku game written in Java which generates its own games on the fly.
Download Netbeans project - 36.8 KB
Download source - 8.9 KB

Introduction
This article is on the implementation of a Sudoku game in Java. This version includes an intuitive interface with the ability to use
help and to check for errors. Turning on help will mark all possible fields for the selected number. After checking for errors, the
program marks valid fields green and invalid fields red. The rules used in this implementation are as follows:
An integer may only appear once in ...

... the same row.


... the same column.
... the same 3x3 region.

A game has only one solution.

Implementation
Model

The most important part of this application is in the Game class, which includes the following functionality:

Generate a new solution;


Generate a new game from a solution;
Keep track of user input;
Check user input against generated solution;
Keep track of selected number;
Keep track of help is on or off.

Because the Game class extends Observable, it can and does notify observers when certain changes have been performed. This
particular application contains two observers, ButtonPanel and SudokuPanel. When the Game class executes
setChanged() followed by notifyObservers(...), the observers will execute their update(...) method.
Besides the Game class, the model consists of an enumeration called UpdateAction which will tell observers what kind of
update has taken place.

Generate Solution
Before we can start generating a game, we must first generate a solution. This is achieved by the method below, which needs to be
called by the user as generateSudoku(new int[9][9], 0). The following steps are taken:
1. Check if a solution is found.

Found -> solution is returned.


Not found -> continue.

2. X (of current field) is found by finding the remainder of the division of the current index by the count of fields in a row using
the modulo operation.
3. Y (of current field) is found by dividing the current index by the count of fields in a row.
4. An ArrayList is filled with the numbers 1 to 9 and shuffled. Shuffling is important because otherwise you always get the
same solution.
5. As long as there are numbers in the ArrayList, the following will be executed:

6.

1. The next possible number is obtained by the method getNextPossibleNumber(int[][], int, int,
List<Integer>), which will be explained later on. If there's no next possible number (return value of -1), null
is returned.
2. Found number is placed on the current location.
3. The method is recursively called with an increase of the index, and the returning value is stored in a variable.
4. If this variable is not null, it is returned; otherwise, the current location is put back to 0 (meaning the field is a
blank).

null is returned. This part will never be reached, hopefully.

private int[][] generateSolution(int[][] game, int index) {


if (index > 80)
return game;
int x = index % 9;

Hide Copy Code

int y = index / 9;

List<Integer> numbers = new ArrayList<Integer>();


for (int i = 1; i <= 9; i++)
numbers.add(i);
Collections.shuffle(numbers);

while (numbers.size() > 0) {


int number = getNextPossibleNumber(game, x, y, numbers);
if (number == -1)
return null;

}
}

game[y][x] = number;
int[][] tmpGame = generateSolution(game, index + 1);
if (tmpGame != null)
return tmpGame;
game[y][x] = 0;

return null;

As previously said, the method getNextPossibleNumber(int[][], int, int, List<Integer>) is used for
obtaining the next possible number. It takes a number from the list and checks whether it is possible at the given x and y position in
the given game. When found possible, the number is returned. If the list is empty and thus no number is possible at this location, -1
is returned.
private int getNextPossibleNumber(int[][] game, int x, int y, List<Integer> numbers) {
while (numbers.size() > 0) {
int number = numbers.remove(0);
if (isPossibleX(game, y, number)
&& isPossibleY(game, x, number)
&& isPossibleBlock(game, x, y, number))
return number;
}
return -1;
}

Hide Copy Code

Generate Game
Generating a game is simply achieved by constantly removing a random field and making sure the game is still valid. Valid means
there is only one solution. This is achieved by the methods below. The user should call the first method, which uses the second
method. I will describe the steps again.
1. A list is filled with all possible positions.
2. The list is shuffled. I do not know why. I suspect that this way, the blanks are better distributed. With the result that the
game is harder.
3. The list is passed to the method generateGame(int[][], List<Integer>) and the return value will be
returned.

private int[][] generateGame(int[][] game) {


List<Integer> positions = new ArrayList<Integer>();
for (int i = 0; i < 81; i++)
positions.add(i);
Collections.shuffle(positions);
return generateGame(game, positions);
}
1. As long as there are positions in the list, the following will be executed:
1. A position is taken from the list and stored in a variable.

Hide Copy Code

2.
3.
4.
5.

x and y are calculated from this position.


Value at this position is stored in the variable temp.
Value at this position is set to 0 (meaning the field is a blank).
This step is critical. As the removal of the value at the position means that the game is no longer valid, the value at
the position is put back. Otherwise the game stays the same.

2. The game is returned.

private int[][] generateGame(int[][] game, List<Integer> positions) {


while (positions.size() > 0) {
int position = positions.remove(0);
int x = position % 9;
int y = position / 9;
int temp = game[y][x];
game[y][x] = 0;
}
}

Hide Copy Code

if (!isValid(game))
game[y][x] = temp;

return game;

As you can see, this method is used to pass default values. So why the new
passing an integer by reference, instead of by value.

int[] { 0 }? This is the most common way of

private boolean isValid(int[][] game) {


return isValid(game, 0, new int[] { 0 });
}

Hide Copy Code

A valid game has in every row, every column, and every region the numbers 1 to 9. Additionally, there should only be one solution
existing. To achieve this, all open fields are filled with the first valid value. Even after finding a solution, the search continues by
putting the next valid value in an open field. If a second solution is found, then the search will be stopped and the method returns
false. There will always be at least one solution (hence game is an incomplete solution), so if there are less than two solutions,
the game is valid and the method returns true. Step by step:
1. Check if a solution is found.

Found -> increase numberOfSolutions and return true if it equals 1; false otherwise.
Not found -> continue.

2. Calculate x and y from index.


3. Check if current field is a blank (equals 0).
True

1. Fill a list with numbers 1 to 9.


2. While the list contains numbers, execute the following:

1. Get the next possible number. If the returned value equals -1, perform a break resulting a return of
true.
2. Set this number at current field.
3. Call this method recursively and instantly check against the returned value.
True -> one or no solution found, continue search.
False -> more than one solution found, stop searching. Restore game and return false.

False

4. Restore value of current field to 0 (meaning it is blank).

1. Call this method recursively and instantly check against the returned value.
True -> continue (resulting in returning true).

4. Return true.

False -> return false.

private boolean isValid(int[][] game, int index, int[] numberOfSolutions) {


if (index > 80)
return ++numberOfSolutions[0] == 1;

Hide Shrink

Copy Code

int x = index % 9;
int y = index / 9;

if (game[y][x] == 0) {
List<Integer> numbers = new ArrayList<Integer>();
for (int i = 1; i <= 9; i++)
numbers.add(i);

while (numbers.size() > 0) {


int number = getNextPossibleNumber(game, x, y, numbers);
if (number == -1)
break;
game[y][x] = number;
if (!isValid(game, index + 1, numberOfSolutions)) {
game[y][x] = 0;
return false;
}
game[y][x] = 0;

}
} else if (!isValid(game, index + 1, numberOfSolutions))
return false;
}

return true;

Check Game
With checking user input, we compare each field in the game against the corresponding field in the solution. The result is stored in
a two dimensional boolean array. The selected number is also set to 0 (meaning no number is selected). All observers are notified
that the model has changed with the corresponding UpdateAction.
public void checkGame() {
selectedNumber = 0;
for (int y = 0; y < 9; y++) {
for (int x = 0; x < 9; x++)
check[y][x] = game[y][x] == solution[y][x];
}
setChanged();
notifyObservers(UpdateAction.CHECK);
}

Hide Copy Code

View & Controller


There is not much to say about the view part, only the structure of the panels. The controllers react to user input and implement
changes to the model. The model notifies it has been changed. The view responses to this notification and updates. These updates
of the view are limited to changing colors and changing the number of a field. There is no rocket science involved.

Sudoku
The view also is the entry point of this application; the Sudoku class contains the main method. This class builds up the user
interface by creating a JFrame and placing SudokuPanel and ButtonPanel inside this frame. It also creates the Game
class, and adds SudokuPanel and ButtonPanel as observers to it.

SudokuPanel and Fields

SudokuPanel contains 9 sub panels each containing 9 fields. All sub panels and fields are placed in a GridLayout of 3x3.

Each sub panel represents a region of a Sudoku game, and is primarily used for drawing a border visually separating each region.
They also get the SudokuController added to them, which is in charge of processing user input by mouse.

ButtonPanel

ButtonPanel contains two panels with a titled border. The first panel contains three buttons. Button New for starting a new

game, button Check for checking user input, and button Exit for exiting the application. The second panel contains 9 toggle buttons
placed inside a button group. This way, they react like radio buttons. Clicking one of these toggle buttons will set the
corresponding selected number in the Game class.

Points of Interest

For passing an integer by reference instead of by value, use an integer array.


isValid(game, 0, new int[] { 0 });
private boolean isValid(int[][] game, int index, int[] numberOfSolutions);
Finding the base x and y values of a region, use the following:
int x1 = x < 3 ? 0 : x < 6 ? 3 : 6;
int y1 = y < 3 ? 0 : y < 6 ? 3 : 6;

Hide Copy Code

Hide Copy Code

History

Initial release.

Apologies
One, if I have driven you mad with my bad English, I apologize. Two, if I have driven you mad before because usually my source
doesn't contain comments, I apologize, and I can tell you, in this case, it does. Not because I acknowledge their usefulness, but to
avoid discussions. Three, if I didn't mention before that you can use your right mouse button to clear a field, I apologize.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

EMAIL

TWITTER

About the Author

Eric
Beijer

Software Developer Fortes Solutions BV


Netherlands
It's good to be me.

You may also be interested in...


Sudoku game using Java

Scalability for Social Gaming Apps

Sudoku Game in C#

How-To Intel IoT Code Samples:


Watering System

Sudoku

How-To Intel IoT Technology


Code Samples: Robot arm in C++

Comments and Discussions


You must Sign In to use this message board.
Search Comments

Profile popupsSpacing Relaxed

y and x

Proj Folder

code does not RUN


urgent

just want to ask this

what the algorithm you use?


Filling in the fields
thanks a lot

loading and saving sudoku


Sudoku...
SUDOKU

Re: SUDOKU

add backtracking algorithm

Re: add backtracking algorithm

Re: add backtracking algorithm

Buttons Disappear?
sudoku code

My vote of 5

Numbers to Letters
End results?

Re: End results?

cant run the program

Re: cant run the program

unable to run

Layout Normal

Per page 25

Update

First Prev Next

Member 12381135

22-Mar-16 19:44

Member 12347332

23-Feb-16 16:09

Member 12176094

21-Dec-15 23:42

Member 12217597

19-Dec-15 5:20

Member 11760149

21-Jun-15 7:05

Bang Jhidat Paho

1-Oct-14 9:07

branoc

5-Apr-14 0:30

Member 10725055

4-Apr-14 7:36

Marco Giadone

24-Jan-14 4:51

Member 10427855

29-Nov-13 6:56

Member 10431549

27-Nov-13 23:30

ichsanelf

28-Nov-13 14:37

ichsanelf

27-Nov-13 20:50

Member 10427855

29-Nov-13 6:59

ichsanelf

29-Nov-13 15:11

CodeKing499

18-Jan-13 13:44

Sai Sathveer

26-Dec-12 4:57

Serhiy Perevoznyk

10-Oct-12 8:05

Yuwan Enginco

23-Sep-12 2:30

Abbott Clyde Chrysler

13-Sep-12 21:24

developer00

14-Sep-12 12:40

Abbott Clyde Chrysler

12-Sep-12 6:47

Eric Beijer

12-Sep-12 7:17

Member 8551910

9-Sep-12 7:21

Eric Beijer

Re: unable to run


Last Visit: 31-Dec-99 19:00 Last Update: 25-Apr-16 0:33
General

News

Suggestion

Question

10-Sep-12 4:32
Refresh

Bug

Answer

Joke

Praise

1 2 Next
Rant

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160418.1 | Last Updated 18 Apr 2012

Layout: fixed | fluid

Admin

Article Copyright 2010 by Eric Beijer


Everything else Copyright CodeProject, 1999-2016

S-ar putea să vă placă și