I tried to make a function that finds the fastest route to the end of the array by making a recursion that chooses its path by first availability. for some reason, the recursion doesn't stop when it returns true. why?
static void Main(string[] args)
{
int[,] arr = new int[5, 5];
arr[0, 0] = 2;
if (PathFinder(arr, 0, 0))
{
printarr(arr);
}
}
static bool PathFinder(int[,] arr, int y,int x)
{
if (arr[arr.GetLength(0) - 1, arr.GetLength(1) - 1] == 2)
{
return true;
}
else
{
/////Right
if (x != arr.GetLength(1) - 1 && arr[y, x + 1] != 2 && arr[y, x + 1] == 0)
{
arr[y, x + 1] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y, x + 1);
}
/////Down
if (y != arr.GetLength(0) - 1 && arr[y + 1, x] != 2 && arr[y + 1, x] == 0)
{
arr[y + 1, x] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y + 1, x);
}
/////UP
if (y!=0 && arr[y-1,x]!=2 && arr[y - 1, x] == 0)
{
arr[y - 1, x] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr,y-1,x);
}
/////Left
if (x != 0 && arr[y, x-1] != 2 && arr[y, x - 1] == 0)
{
arr[y, x - 1] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y, x - 1);
}
return false;
}
}
static void printarr(int[,] arr)
{
for (int row = 0; row < arr.GetLength(0); row++)
{
for (int colom = 0; colom < arr.GetLength(1); colom++)
{
Console.Write(arr[row, colom] + " ");
}
Console.WriteLine("");
}
}
If you call a method that has a return type recursively without storing that return value, it will proceed after the call. You have called it by name PathFinder(... so when true is returned your recursive call doesn't pass it on. Change your code like this:
static bool PathFinder(int[,] arr, int y, int x)
{
if (arr[arr.GetLength(0) - 1, arr.GetLength(1) - 1] == 2)
{
return true;
}
else
{
/////Right
if (x != arr.GetLength(1) - 1 && arr[y, x + 1] != 2 && arr[y, x + 1] == 0)
{
arr[y, x + 1] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y, x + 1);
}
/////Down
if (y != arr.GetLength(0) - 1 && arr[y + 1, x] != 2 && arr[y + 1, x] == 0)
{
arr[y + 1, x] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y + 1, x);
}
/////UP
if (y != 0 && arr[y - 1, x] != 2 && arr[y - 1, x] == 0)
{
arr[y - 1, x] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y - 1, x);
}
/////Left
if (x != 0 && arr[y, x - 1] != 2 && arr[y, x - 1] == 0)
{
arr[y, x - 1] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y, x - 1);
}
return false;
}
}
This way, when you hit return true;, that value will be passed along all the way back the call stack and you won't continue processing until your return false;
Recursive calls to methods without a return type should have a return; statement somewhere so they can escape otherwise you'll hit a StackOverflowException.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
i need help, i had my friend to help me debug this code, and we found that the code stops at random points on the code, sometimes on first loop, sometimes on last loop and so on.
the code is just to make a 9x9 sudoku board with all the rules applied. when i tested each block separately it worked and printed a well done sudoku board, but the problem here is that is gets stuck somehow.
help will be appreciated.
int[,] helpblock = new int[10, 10];
int[,] helplines = new int[10, 10];
int[,] helpcols = new int[10, 10];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
helplines[i, j] = 0;
helpcols[i, j] = 0;
helpblock[i, j] = 0;
}
}
Random rnf = new Random();
int help1;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
help1 = rnf.Next(1, 10);
if (i == 0 || i == 1 || i == 2) {
if (j == 0 || j == 1 || j == 2) {
if (helplines[i, help1] != 0 || helpblock[0, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[0, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[0, help1]++;
} else if (j == 3 || j == 4 || j == 5) {
if (helplines[i, help1] != 0 || helpblock[1, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[1, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[1, help1]++;
} else if (j == 6 || j == 7 || j == 8) {
if (helplines[i, help1] != 0 || helpblock[2, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[2, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[2, help1]++;
}
} else if (i == 3 || i == 4 || i == 5) {
if (j == 0 || j == 1 || j == 2) {
if (helplines[i, help1] != 0 || helpblock[3, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[3, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[3, help1]++;
} else if (j == 3 || j == 4 || j == 5) {
if (helplines[i, help1] != 0 || helpblock[4, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[4, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[4, help1]++;
} else if (j == 6 || j == 7 || j == 8) {
if (helplines[i, help1] != 0 || helpblock[5, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[5, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[5, help1]++;
}
} else if (i == 6 || i == 7 || i == 8) {
if (j == 0 || j == 1 || j == 2) {
if (helplines[i, help1] != 0 || helpblock[6, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[6, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[6, help1]++;
} else if (j == 3 || j == 4 || j == 5) {
if (helplines[i, help1] != 0 || helpblock[7, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[7, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[7, help1]++;
} else if (j == 6 || j == 7 || j == 8) {
if (helplines[i, help1] != 0 || helpblock[8, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[8, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[8, help1]++;
}
}
}
}
PrintSudoku(map);
This is not really an answer, but hopefully it will help you debug the program. Inside your for loops you have a whole bunch of if statements that look something like:
if (i == 0 || i == 1 || i == 2) {
if (j == 0 || j == 1 || j == 2) {
It looks like you are using this logic to determine which block you're in, because that's the one array that you are using a hard-coded value for the first index.
Instead of doing it this way, consider calculating the block using a formula based on the current row and column value.
Your grid currently looks something like this:
| 0 1 2 | 3 4 5 | 6 7 8 |
--+-------+-------+--------
0 | | | |
1 | [0] | [1] | [2] |
2 | | | |
--+-------+-------+--------
3 | | | |
4 | [3] | [4] | [5] |
5 | | | |
--+-------+-------+--------
6 | | | |
7 | [6] | [7] | [8] |
8 | | | |
---------------------------
What you might notice is that if you take the row number and do an integer division by 3, you will get the Block row number (0, 1, or 2). Multiplying this number by 3 gives you the first block in each row (0, 3, and 6). Now, if we take the current column and integer-divide that by 3, we will get the current block column (0, 1, or 2). Adding the "block row" to the "block column" then will give us the block index:
int block = ((row / 3) * 3) + (column / 3);
(Note that it looks like you could simplify this since row is being divided by three and then multiplied by three, but remember that integer division rounds down, so 2 / 3 == 0, not .6667)
By calculating the block this way, you can drastically reduce the number of lines you have to walk through.
Also, using some more meaningful variable names will help with the readability.
I simplified your code to something that I believe does the exact same thing. Maybe it will help your analysis:
int[,] blocks = new int[10, 10];
int[,] rows = new int[10, 10];
int[,] columns = new int[10, 10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
rows[i, j] = 0;
columns[i, j] = 0;
blocks[i, j] = 0;
}
}
Random rnd = new Random();
int randomNumber;
for (int row = 0; row < 9; row++)
{
for (int column = 0; column < 9; column++)
{
int block = ((row / 3) * 3) + (column / 3);
randomNumber = rnd.Next(1, 10);
while (rows[row, randomNumber] != 0 ||
blocks[block, randomNumber] != 0 ||
columns[column, randomNumber] != 0)
{
System.Threading.Thread.Sleep(1);
randomNumber = rnd.Next(1, 10);
}
map[row, column] = randomNumber;
rows[row, randomNumber]++;
columns[column, randomNumber]++;
blocks[block, randomNumber]++;
}
}
After playing with this, of course, I got interested in the problem. Below is what I came up with to solve it, which is pretty much a brute-force method:
Start with numbers 1-9 available for each row, column, and block
From the list of available numbers for a cell, assign one of them at random, one cell at a time
Remove that number from the available numbers for that row, column, and block
If we run into the case where there is no valid number available for the cell, reset everything and try again.
Notice there is potential that this will run and never finish, but in my testing it usually finds a solution in less than 400 tries (which is relatively fast from a user's point of view).
What I did differently was, instead of using arrays to store the row/column/block information, I decided to use a Dictionary<int, List<int>>, which stores the row/column/block index as the key, and the value for each key is a List of available numbers for that index.
Then in our loop, I just put the intersection of the available numbers left for the current row, column, and block into a List. Then I pick a random index in that list and assign that value to the cell (and remove it from the available items in that row, column, and block).
I also added some logging to find out how many times it failed before finding a solution.
Here's the code, which also prints the solution at the end:
static void Main()
{
int[,] map = new int[9, 9];
var blocks = new Dictionary<int, List<int>>();
var rows = new Dictionary<int, List<int>>();
var columns = new Dictionary<int, List<int>>();
// initialize lists of available numbers
for (int i = 0; i < 9; i++)
{
blocks.Add(i, new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
rows.Add(i, new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
columns.Add(i, new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
}
Random rnd = new Random();
int failCount = 0;
// For each row
for (int row = 0; row < 9; row++)
{
// For each column in this row
for (int column = 0; column < 9; column++)
{
// Calculate block based on current row and column
int block = ((row / 3) * 3) + (column / 3);
// Get set of available numbers for this cell by getting the intersection
// of available numbers for the row, column, and block
var availableItems =
rows[row].Intersect(
columns[column].Intersect(
blocks[block])).ToList();
// If we reach a point where there are no availableItems, then this is
// not a valid Sudoku pattern. Reset everything and try again
if (availableItems.Count == 0)
{
failCount++;
Console.WriteLine($"Failed {failCount} times. Trying again...");
// Reset to the first cell
row = 0;
column = 0;
block = 0;
// Initialize data
for (int i = 0; i < 9; i++)
{
blocks[i] = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
rows[i] = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
columns[i] = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
availableItems = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
// Grab a number from the available numbers by choosing a random index
var randomNumber = availableItems[rnd.Next(0, availableItems.Count)];
// Update our map with this item
map[row, column] = randomNumber;
// Remove this item from our lists
rows[row].Remove(randomNumber);
columns[column].Remove(randomNumber);
blocks[block].Remove(randomNumber);
}
}
// Print our Sudoku map:
Console.WriteLine(new string('-', 25));
for(int i = 0; i < 9; i++)
{
Console.Write("|");
for (int j = 0; j < 9; j++)
{
Console.Write($" {map[i, j]}");
if ((j + 1) % 3 == 0) Console.Write(" |");
}
Console.WriteLine();
if ((i + 1) % 3 == 0) Console.WriteLine(new string('-', 25));
}
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Ouput:
These loops look deadly:
while (helplines[i, help1] != 0 || helpblock[5, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
If the new value of help1 doesn't change the while condition to false, it will loop forever.