0% found this document useful (0 votes)
492 views17 pages

Solving Sudoku Puzzles

This document is a project report submitted by four students for their B. Tech degree in partial fulfillment of requirements. It discusses solving Sudoku puzzles using backtracking and constraint propagation algorithms. Backtracking incrementally builds candidate solutions and abandons ("backtracks") from partial candidates that cannot be completed. Constraint propagation solves Sudoku by using possibility arrays and iterating until all spaces are filled or no progress can be made. Pseudocode and examples are provided to illustrate how each algorithm solves a sample puzzle through recursive calls and constraint checking.

Uploaded by

Ayush Bhatia
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
492 views17 pages

Solving Sudoku Puzzles

This document is a project report submitted by four students for their B. Tech degree in partial fulfillment of requirements. It discusses solving Sudoku puzzles using backtracking and constraint propagation algorithms. Backtracking incrementally builds candidate solutions and abandons ("backtracks") from partial candidates that cannot be completed. Constraint propagation solves Sudoku by using possibility arrays and iterating until all spaces are filled or no progress can be made. Pseudocode and examples are provided to illustrate how each algorithm solves a sample puzzle through recursive calls and constraint checking.

Uploaded by

Ayush Bhatia
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

SOLVING SUDOKU PUZZLES

CSE2003
DSA PROJECT REPORT
(J Component )

SUBMITTED BY:

AKHILA ESHAPULA- 16BEC0468


AYUSH BHATIA- 16BEC0061
SALONI NEGI- 18BCE0762
PRANAV V A - 18BCE0748

in partial fulfillment for the award of the degree of

B. Tech

in

SCOPE SCHOOL

Vellore-632014, Tamil Nadu, India


School of Computer Science and Engineering
March, 2019
1. ABSTRACT
In this project we solve Sudoku puzzles using backtracking method and constraint
propagation. Backtracking is a general algorithm for finding all (or some) solutions to some
computational problems, notably constraint satisfaction problems, that incrementally builds
candidates to the solutions, and abandons each partial candidate ("backtracks") as soon as it
determines that the candidate cannot possibly be completed to a valid solution. Constraint
propagation is an algorithm that solves Sudoku problems by using possibility array and
multiple iterations. For this algorithm we will initially fill all the space with the values given
in the question, after that we will put zeroes in the blank locations. In this we will find all the
possible numbers for a particular blank location and we will have an array for each blank
location, if for a particular blank location there is only one possibility then we will directly
insert the value in that location, otherwise we will have multiple iterations following to
complete the Sudoku problem.

2. INTRODUCTION
WHAT IS SUDOKU PUZZLE?
A Sudoku puzzle is defined as a logic-based, number-placement puzzle. The objective is to
fill a 9×9 grid with digits in such a way that each column, each row, and each of the nine 3×3
grids that make up the larger 9×9 grid contains all of the digits from 1 to 9. Each Sudoku
puzzle begins with some cells filled in. The player uses these seed numbers as a launching
point toward finding the unique solution.
While solving Sudoku puzzles can be significant challenge, the rules for traditional solution
finding are quite straight forward:
1. Each row, column, and nonet can contain each number (typically 1 to 9) exactly once.
2. The sum of all numbers in any nonet, row, or column must match the small number printed
in its corner. For traditional Sudoku puzzles featuring the numbers 1 to 9,
this sum is equal to 45.

3. OVERVIEW OF THE PROPOSED SYSTEM


3.1 SYSTEM ARCHITECTURE
DESCRIPTION OF BACKTRACKING

Conceptually, the partial candidates are represented as the nodes of a tree structure, the
potential search tree. Each partial candidate is the parent of the candidates that differ from
it by a single extension step; the leaves of the tree are the partial candidates that cannot be
extended any further. The backtracking algorithm traverses this search tree recursively,
from the root down, in depth-first order. At each node c, the algorithm checks whether c
can be completed to a valid solution. If it cannot, the whole sub-tree rooted at c is
skipped. Otherwise, the algorithm (1) checks whether c itself is a valid solution, and if so
reports it to the user; and (2) recursively enumerates all sub-trees of c. The two tests and
the children of each node are defined by usergiven procedures. Therefore, the actual
search tree that is traversed by the algorithm is only a part of the potential tree. The total
cost of the algorithm is the number of nodes of the actual tree times the cost of obtaining
and processing each node. This fact should be considered when choosing the potential
search tree and implementing the pruning test. Backtracking is an algorithm for capturing
some or all solutions to given computational issues, especially for constraint satisfaction
issues. The algorithm can only be used for problems which can accept the concept of a
“partial candidate solution” and allows a quick test to see if the candidate solution can be
a complete solution. Backtracking is considered an important technique to solve
constraint satisfaction issues and puzzles. It is also considered a great technique for
parsing and also forms the basis of many logic programming languages. The term
recursive backtracking comes from the way in which the problem tree is explored. The
algorithm tries a value, then optimistically recurs on the next cell and checks if the
solution (as built up so far) is valid. If, at some later point in execution, it is determined
that what was built so far will not solve the problem, the algorithm backs up the stack to a
state in which there could be another valid solution. Due to the way that we pass the
puzzle between calls, each recursive call uses minimal memory. We store all necessary
state on the stack, allowing us to almost completely ignore any sort of bookkeeping.

CONSTRAINT PROPAGATION

Constraint propagation is an algorithm that solves Sudoku problems by using possibility


array and multiple iterations. For this algorithm we will initially fill all the space with the
values given in the question, after that we will put zeroes in the blank locations. In this
we will find all the possible numbers for a particular blank location and we will have an
array for each blank location, if for a particular blank location there is only one possibility
then we will directly insert the value in that location, otherwise we will have multiple
iterations following to complete the Sudoku problem. In some cases where the Sudoku
problem is of hard or extreme level we won’t have a possible value after multiple
iterations. For most of the cases constraint propagation will be enough to fill the grid
completely and without any conflict.

3.2 MODULE DECSCRPTION

EXAMPLE FOR SOLVING A PROBLEM WITH BACKTRACKING:

For solving the puzzle we will have to follow a set of rules.


They are:
1) Assign numbers one by one to empty cell.
2) Before assigning we check if it is safe or not.
3) If in a cell there is no other possibility then we go to the previous cell, empty it and
then try going for some other possibility.
4) We repeat the above three steps recursively till we get the solution to the puzzle.

Here is a sample puzzle.

1) We cannot place 1, hence we place 2 in the second cell

2) We cannot place 1 to 3, hence we place 4 in the 4th cell

3) We cannot place 1 to 2, hence we place 3 in the 5th cell


4) In 6th cell there is no possibility of filling any number so we go back to 5th cell and
remove 3

5) In 5th cell we fill 4 which is the next possibility after 3

6) we place 3 in the 6th cell which is the only possibility


7) We cannot place 1 and 2, hence we place 3 in the 9th cell

8) We cannot place 1 to 3, hence we place 4 in the 11th cel

9) we place 2 in the 15th cell


10) We cannot place 1 and 2, hence we place 3 in the 16th cell. Hence we have got the
solution to the puzzle.

CONSTRAINT PROPAGATION

Two important strategies that we can use to make progress towards filling in all the squares:
(1)If a square has only one possible value, then eliminate that value from the square's peers.
(2) If a unit has only one possible place for a value, then put the value there.
As an example of strategy (1) if we assign 7 to A1, yielding {'A1': '7', 'A2':'123456789',
...},we see that A1 has only one value, and thus the 7 can be removed from its peer A2 (and
all other peers), giving us {'A1': '7', 'A2': '12345689', ...}. As an example of strategy (2), if it
turns out that none of A3 through A9 has a 3 as a possible value, then the 3 must belong in
A2, and we can update to {'A1': '7', 'A2':'3', ...}. These updates to A2 may in turn cause
further updates to its peers, and the peersof those peers, and so on. This process is called
constraint propagation.
It may seem like a good idea to place a four in the shaded box. It doesn't immediately conflict
with any other locations and after placing it all of the squares still have possible values. Next
look at the square right below the shaded one, it must be a two. Filling in a two there,
however, leaves the lower left square with no possible value. This may not seem like a big
deal, it only takes an extra two assignments to realize that the four was wrong, but what if the
two isn't the next assignment.

The result is an exponential increase in the time needed for the search to realize that four was
a bad choice. The solution is to assign values that only have one possible immediately. After
each value is assigned by the search algorithm, constraint propagation iterates through the
squares assigning value to squares with only one possible value. If a square has no possible
values, the algorithm fails and returns to search which reselects the last value. If multiple
values are assigned by constraint propagation, then they repealed at once upon a fail. In the
example above after the four is assigned, constraint propagation realizes that the space below
the four must be a two. It then notices that the lower left corner has no possible value and
fails, returning to search, which chooses another value for the shaded square.

ALGORITHM FOR BACKTRAKING:

■ Include all the necessary header files.


■ Define variables with constant initial values as #define unsigned zero, #defined N 9.
■ Give prototype of all the functions used.
■ In main function take input as the grid to solve sudoku.
■ Call the function solve Sudoku ().
■ Find unassigned locations in the grid by calling functions find unassigned location(int grid
[N][N], int&row, int&col)
■ Use a loop to generate numbers from 1 to 9.
■ Call a function bool ifsafe() which will check if number assigned is valid or not.
■ This function will call function usedinrow() to check if the number is repeated in the given
row or not .
■ The function ifsafe () will call another function usedincol() to check if the number is
repeated in given coloumn or not.
■ The function will call function used in grid to check if the values in 3X3 grid formed are
unique or not.
■ If the num assigned to the location satisfies all the ,three given conditions that it is unique
in the row coloumn and the 3X3 matrix, then it will be assigned to the given location else the
value of the location will be changed to back to unassigned(=0) and the loop will perform
next iteration to look for another number.
■ If the entire 9X9 grid is filled successfully, the function solvesudoku() will return true and
main function will call function printgrid() to print the solved sudoku grid .
■ If there is any unassigned location in the sudoku 9X9 grid the function solvesudoku() will
return false and no solution will be displayed on the output screen.

CODE FOR SUDOKU USING BACKTRAKING

#include <iostream>
#include "stdio.h"
using namespace std;
// UNASSIGNED is used for empty cells in sudoku grid
#define UNASSIGNED 0
// N is used for size of Sudoku grid. Size will be NxN
#define N 9
// This function finds an entry in grid that is still unassigned
bool FindUnassignedLocation(int grid[N][N], int &row, int &col);
// Checks whether it will be legal to assign num to the given row,col
bool isSafe(int grid[N][N], int row, int col, int num);
/* Takes a partially filled-in grid and attempts to assign values to
all unassigned locations in such a way to meet the requirements
for Sudoku solution (non-duplication across rows, columns, and boxes) */
bool SolveSudoku(int grid[N][N])
{
int row, col;
// If there is no unassigned location, we are done
if (!FindUnassignedLocation(grid, row, col))
return true; // success!
// consider digits 1 to 9
for (int num = 1; num <= 9; num++)
{
// if looks promising
if (isSafe(grid, row, col, num))
{
// make tentative assignment
grid[row][col] = num;
// return, if success, yay!
if (SolveSudoku(grid))
return true;
// failure, unmake & try again
grid[row][col] = UNASSIGNED;
}
}
return false; // this triggers backtracking
}
/* Searches the grid to find an entry that is still unassigned. If
found, the reference parameters row, col will be set the location
that is unassigned, and true is returned. If no unassigned entries
remain, false is returned. */
bool FindUnassignedLocation(int grid[N][N], int &row, int &col)
{
for (row = 0; row < N; row++)
for (col = 0; col < N; col++)
if (grid[row][col] == UNASSIGNED)
return true;
return false;
}
/* Returns a boolean which indicates whether any assigned entry
in the specified row matches the given number. */
bool UsedInRow(int grid[N][N], int row, int num)
{
for (int col = 0; col < N; col++)
if (grid[row][col] == num)
return true;
return false;
}
/* Returns a boolean which indicates whether any assigned entry
in the specified column matches the given number. */
bool UsedInCol(int grid[N][N], int col, int num)
{
for (int row = 0; row < N; row++)
if (grid[row][col] == num)
return true;
return false;
}
/* Returns a boolean which indicates whether any assigned entry
within the specified 3x3 box matches the given number. */
bool UsedInBox(int grid[N][N], int boxStartRow, int boxStartCol, int num)
{
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++)
if (grid[row+boxStartRow][col+boxStartCol] == num)
return true;
return false;
}
/* Returns a boolean which indicates whether it will be legal to assign
num to the given row,col location. */
bool isSafe(int grid[N][N], int row, int col, int num)
{
/* Check if 'num' is not already placed in current row,
current column and current 3x3 box */
return !UsedInRow(grid, row, num) &&
!UsedInCol(grid, col, num) &&
!UsedInBox(grid, row - row%3 , col - col%3, num);
}
/* A utility function to print grid */
void printGrid(int grid[N][N])
{
for (int row = 0; row < N; row++)
{
for (int col = 0; col < N; col++)
printf(" %2d ", grid[row][col]);
printf("\n");
}
}
/* Driver Program to test above functions */
int main()
{
// 0 means unassigned cells
int grid[N][N] = {{6, 5, 0, 8, 7, 3, 0, 9, 4},
{0, 4, 3, 2, 5, 0, 0, 0, 8},
{9, 8, 0, 1, 0, 4, 3, 5, 7},
{1, 2, 5, 4, 0, 0, 0, 0, 9},
{4, 0, 9, 5, 0, 0, 0, 0, 2},
{0, 6, 0, 9, 0, 0, 5, 0, 3},
{5, 7, 8, 3, 0, 1, 0, 2, 6},
{2, 0, 0, 0, 4, 8, 9, 0, 0},
{0, 9, 4, 6, 2, 5, 0, 8, 1}};
if (SolveSudoku(grid) == true)
printGrid(grid);
else
printf("No solution exists");
return 0;
}
4. RESULTS AND DISCUSSION

OUTPUT
ALGORITHM ANALYSIS :
Backtracking
Backtracking is an optimization technique. We start with a possible solution which satisfies
all the required conditions, Then we move to the next level and if that does not produces
satisfactory solution, We return one level back and start with a new option.
Example =Sudoku solver, going through mare, eight queen problem
The backtracking algorithm enumerates a set of partial candidates that, in principle, could be
completed in various ways to give all the possible solutions to the given problem. The
completion is done incrementally, by a sequence of candidate extension steps. Conceptually,
the partial candidates are represented as the nodes of a tree structure, the potential search tree.
Each partial candidate is the parent of the candidates that differ from it by a single extension
step; the leaves of the tree are the partial candidates that cannot be extended any further. The
backtracking algorithm traverses this search tree recursively, from the root down, in depth-
first order. At each node c, the algorithm checks whether c can be completed to a valid
solution. If it cannot, the whole sub-tree rooted at c is skipped (pruned). Otherwise, the
algorithm (1) checks whether c itself is a valid solution, and if so reports it to the user; and (2)
recursively enumerates all sub-trees of c. The two tests and the children of each node are
defined by user-given procedures. Divide and Conquer Divide and Conquer is an algorithmic
paradigm.
A typical Divide and Conquer algorithm solves a problem using following three steps.
1. Divide: Break the given problem into sub problems of same type.
2. Conquer: Recursively solve these sub problems
3. Combine: Appropriately combine the answers
Example:-Binary Search , quick sort , Merge sort

Greedy Method
A greedy algorithm is an algorithmic paradigm that follows the problem solving heuristic of
making the locally optimal choice at each stage with the hope of finding a global optimum. In
many problems, a greedy strategy does not in general produce an optimal solution, but
nonetheless a greedy heuristic may yield locally optimal solutions that approximate a global
optimal solution in a reasonable time.
It is quite easy to come up with a greedy algorithm (or even multiple greedy algorithms) for a
problem.
Analyzing the run time for greedy algorithms will generally be much easier than for other
techniques (like Divide and conquer). For the Divide and conquer technique, it is not clear
whether the technique is fast or slow. This is because at each level of recursion the size of
gets smaller and the number of sub-problems increases.
The difficult part is that for greedy algorithms you have to work much harder to understand
correctness issues. Even with the correct algorithm, it is hard to prove why it is correct.
Proving that a greedy algorithm is correct is more of an art than a science. It involves a lot of
creativity. Dynamic Programming Dynamic programming (usually referred to as DP ) is a
very powerful technique to solve a particular class of problems. It demands very elegant
formulation of the approach and simple thinking and the coding part is very easy.
Some famous Dynamic Programming algorithms are:
Unix diff for comparing two files
Bellman-Ford for shortest path routing in networks
TeX the ancestor of LaTeX
WASP - Winning and Score Predictor
The core idea of Dynamic Programming is to avoid repeated work by remembering partial
results and this concept finds it application in a lot of real life situations.
In programming, Dynamic Programming is a powerful technique that allows one to solve
different types of problems in time O(n2 ) or O(n3 ) for which a naive approach would take
exponential time Branch and Bound programming
Branch and bound (BB, B&B, or BnB) is an algorithm design paradigm for discrete and
combinatorial optimization problems, as well as mathematical optimization . A branchand-
bound algorithm consists of a systematic enumeration of candidate solutions by means of
state space search : the set of candidate solutions is thought of as forming a rooted tree with
the full set at the root. The algorithm explores branches of this tree, which represent subsets
of the solution set. Before enumerating the candidate solutions of a branch, the branch is
checked against upper and lower estimated bounds on the optimal solution, and is discarded
if it cannot produce a better solution than the best one found so far by the algorithm.

Advantage of depth first search

The advantage of depth-first Search is that memory requirement is only linear with respect to
the search graph. This is in contrast with breadth-first search which requires more space. The
reason is that the algorithm only needs to store a stack of nodes on the path from the root to
the current node.
The time complexity of a depth-first Search to depth d is O(b^d) since it generates the same
set of nodes as breadth-first search , but simply in a different order. Thus practically
depthfirst search is time-limited rather than space-limited. If depth-first search finds solution
without exploring much in a path then the time and space it takes will be very less

Disadvantage of depth first search

The disadvantage of Depth-First Search is that there is a possibility that it may go down the
left-most path forever. Even a finite graph can generate an infinite tree. One solution to this
problem is to impose a cut off depth on the search. Although the ideal cut off is the solution
depth d and this value is rarely known in advance of actually solving the problem. If the
chosen cut off depth is less than d, the algorithm will fail to find a solution, whereas if the cut
off depth is greater than d, a large price is paid in execution time, and the first solution found
may not be an optimal one.
Depth-First Search is not guaranteed to find the solution. And there is no guarantee to find a
minimal solution, if more than one solution exists.

5. CONCLUSION

In this project we successfully solved Sudoku puzzles using backtracking method and
constraint propagation. This gave us immense knowledge on backtracking and
constraint propagation.
REFERENCES
www.google.com
www.hackernoon.com
Vijayranjan Sir’s notes
Algorithms+Data Structures (By Niklaus Wirth)

You might also like