here will be my code for famous Knights Tour for 8x8 deck. So, the main idea of my code is: we will choose from Turns our destination, check it with isPossible and then go recursevly to it, marked this cell to '1'. So, check every cell, and if we will be in 64's cell - return true.
But my code goes to infinite recurssion, and I can't debug it, any recommendation will be greatly appreciated.
class Class1
{
static void Main(string[] args)
{
int x = 0;
int y = 0;
Console.WriteLine("Enter X and press enter");
x = Int32.Parse(Console.ReadLine());
Console.WriteLine("Enter Y and press enter");
y = Int32.Parse(Console.ReadLine());
TurnVariation Turns = new TurnVariation();
EmptyBoard Board = new EmptyBoard();
if (TryPut.Put(Board, x, y, Turns, 1, false))
{
Console.WriteLine("МОЖНА!!!!");
}
else
{
Console.WriteLine("NET!!");
}
}
}
public class TryPut : EmptyBoard
{
public static bool Put(EmptyBoard Board, int x, int y, TurnVariation Turns, int count, bool flag)
{
int tempX = 0;
int tempY = 0;
if (count >= 64)
{
Console.WriteLine("yeab");
return true;
}
for (int i = 0; i <= 7; i++)
{
tempX = x + Turns.Turns[i,0];
tempY = y + Turns.Turns[i,1];
//Console.WriteLine(count);
if (IsPossible(Board, tempX, tempY))
{
Board.Array[tempX, tempY] = 1;
flag = Put(Board, tempX, tempY, Turns, count+1, flag);
if (flag)
{
break;
}
Board.Array[tempX, tempY] = 0;
}
}
if (flag)
return true;
else
return false;
}
public static bool IsPossible(EmptyBoard Board, int x, int y)
{
if ((x < 0) || (x > 7) || (y < 0) || (y > 7))
return false;
if (Board.Array[x, y] == 1)
return false;
return true;
}
}
public class TurnVariation
{
public int[,] Turns = new int[8, 2];
public TurnVariation()
{
Turns[0, 0] = -2; Turns[0, 1] = 1;
Turns[1,0] = -2; Turns[1,1] = -1;
Turns[2,0] = -1; Turns[2,1] = 2;
Turns[3,0] = 1; Turns[3,1] = 2;
Turns[4,0] = 2; Turns[4,1] = 1;
Turns[5,0] = 2; Turns[5,1] = -1;
Turns[6,0] = 1; Turns[6,1] = -2;
Turns[7,0] = -1; Turns[7,1] = -2;
}
}
public class EmptyBoard
{
public const int N = 8;
public int[,] Array = new int[N, N];
public EmptyBoard()
{
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
Array[i, j] = 0;
}
}
I think your problem is that your testing for count<64, but you never assign to count. You just pass (by value!) 'Count + 1' to the put method. You are probably thinking that this will bewritten back to the count variable. But that is not the case...
Do note that debugging is the first skill you need to learn!
Related
I am trying to make a Sudoku solver. Whenever I try to run it it gives me a Stack Overflow Error:
System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.'
I believe that it probably has to do with the solve function calling on the FindEmpy function too much?
Any help is greatly appreciated!
Thanks so much!
using System;
namespace sudokusolver
{
class Program
{
static public void PrintBoard(int[][] bo)
{
for (int i = 0; i < bo.Length; i++)
{
if (i % 3 == 0 && i != 0)
{
Console.WriteLine("- - - - - - - - - - - - -");
}
for (int j = 0; j < bo[0].Length; j++)
{
if (j % 3 == 0 && j != 0)
{
Console.Write(" | ");
}
if (j == 8)
{
Console.WriteLine(bo[i][j]);
}
else
{
Console.Write(bo[i][j] + " ");
}
}
}
}
static public (int,int) FindEmpty(int[][] bo)
{
for (int i = 0; i < bo.Length; i++)
{
for (int j = 0; j < bo[0].Length; j++)
{
if (bo[i][j] == 0)
{
return (i, j);
}
}
}
return (100, 100);
}
static public bool Solve(int[][] bo)
{
int x;
int y;
if (FindEmpty(bo) == (100, 100))
{
return true;
}
else
{
y = FindEmpty(bo).Item1;
x = FindEmpty(bo).Item2;
}
for (int i = 0; i < 10; i++)
{
if (IsValid(bo, i, x, y) == true)
{
bo[y][x] = i;
if (Solve(bo) == true)
{
return true;
}
else
{
bo[y][x] = 0;
}
}
}
return false;
}
static public bool IsValid(int[][] bo, int num, int x, int y)
{
for (int i = 0; i < bo.Length; i++)
{
if (bo[y][i] == num && x != i)
{
return false;
}
}
for (int i = 0; i < bo[0].Length; i++)
{
if (bo[i][x] == num && y != i)
{
return false;
}
}
int boxx = x / 3;
int boxy = y / 3;
for (int i = boxy * 3; i < boxy * 3 + 3; i++)
{
for (int j = boxx * 3; j < boxx * 3 + 3; j++)
{
if (bo[i][j] == num && i != y && j != x)
{
return false;
}
}
}
return true;
}
static void Main(string[] args)
{
int[][] board = {
new int[] {7,0,0,0,0,0,2,0,0},
new int[] {4,0,2,0,0,0,0,0,3},
new int[] {0,0,0,2,0,1,0,0,0},
new int[] {3,0,0,1,8,0,0,9,7},
new int[] {0,0,9,0,7,0,6,0,0},
new int[] {6,5,0,0,3,2,0,0,1},
new int[] {0,0,0,4,0,9,0,0,0},
new int[] {5,0,0,0,0,0,1,0,6},
new int[] {0,0,6,0,0,0,0,0,8}
};
PrintBoard(board);
Solve(board);
PrintBoard(board);
}
}
}
static public bool Solve(int[][] bo)
{
int x;
int y;
if (FindEmpty(bo) == (100, 100))
{
return true;
}
else
{
y = FindEmpty(bo).Item1;
x = FindEmpty(bo).Item2;
}
- for (int i = 0; i < 10; i++)
+ for (int i = 1; i < 10; i++)
{
if (IsValid(bo, i, x, y) == true)
{
bo[y][x] = i;
if (Solve(bo) == true)
{
return true;
}
else
{
bo[y][x] = 0;
}
}
}
return false;
}
At some point IsValid(bo, 0, x, y) returns true, so you replace the zero with another zero forever.
I am working on a procedural room generator in c#, I would like the rooms not to overlap and I am having a hard time getting that to work. After #Idle_Mind's comments, I have a new problem. The Image produced by the program has many overlapping rooms. Bellow is the class that should handle the intersection checking and the placement of the rooms onto the tilemap
public int XSize, YSize;
private Cell[ , ] cells;
private List<Room> rooms;
public Tilemap(int xSize, int ySize)
{
XSize = xSize;
YSize = ySize;
rooms = new List<Room>();
cells = new Cell[XSize, YSize];
for (int y = 0; y < YSize; y++)
{
for (int x = 0; x < XSize; x++)
{
cells[x, y].type = CellType.Empty;
}
}
for (int i = 0; i < 10; i++)
{
GenerateRandomRoomSafe(10);
}
}
private Room GetRoomBounds()
{
Utils.Int2 min = new Utils.Int2(0, 0);
Utils.Int2 max = new Utils.Int2(XSize,YSize);
Utils.Int2 q1 = Utils.GetRandomCoords(min, max);
max.X = XSize - 1 - q1.X;
max.Y = YSize - 1 - q1.Y;
Utils.Int2 siz = Utils.GetRandomCoords(min, max);
Room check = new Room(q1.X, q1.Y, siz.X, siz.Y);
return check;
}
public void GenerateRandomRoomSafe(int maxTries)
{
Room check = new Room(0, 0, 0, 0);
bool isValid = false;
int tries = 0;
if (rooms.Count == 0)
{
isValid = true;
check = GetRoomBounds();
tries = 1;
}
else
{
while (!isValid && tries < maxTries)
{
check = GetRoomBounds();
for (int i = 0; i < rooms.Count; i++)
{
if (!rooms[i].Walls.IntersectsWith(check.Walls))
{
isValid = true;
break;
}
}
tries++;
}
}
if (isValid)
{
Console.WriteLine(check + " was placed after " + tries + " tries");
PlaceRoomUnsafe(check);
}
}
public void PlaceRoomUnsafe(Room r)
{
for (int y = r.Walls.Y; y <= r.Walls.Y + r.Walls.Height; y++)
{
cells[r.Walls.X, y].type = CellType.Wall;
}
for (int y = r.Walls.Y; y <= r.Walls.Y + r.Walls.Height; y++)
{
cells[r.Walls.X + r.Walls.Width, y].type = CellType.Wall;
}
for (int x = r.Walls.X; x <= r.Walls.X + r.Walls.Width; x++)
{
cells[x, r.Walls.Y].type = CellType.Wall;
}
for (int x = r.Walls.X; x <= r.Walls.X + r.Walls.Width; x++)
{
cells[x, r.Walls.Y + r.Walls.Height].type = CellType.Wall;
}
for (int y = r.Floor.Y; y < r.Floor.Y + r.Floor.Height; y++)
{
for (int x = r.Floor.X; x < r.Floor.X + r.Floor.Width; x++)
{
cells[x, y].type = CellType.Floor;
}
}
rooms.Add(r);
}
public void GenerateRandomRoomUnsafe()
{
Room r = GetRoomBounds();
PlaceRoomUnsafe(r);
}
public int GetCellPixel(int x, int y)
{
return (int) cells[x, y].type;
}
public class Room
{
public Rectangle Walls;
public Rectangle Floor;
public Room(int q1X, int q1Y, int xSize, int ySize)
{
Walls.X = q1X;
Walls.Y = q1Y;
Walls.Width = xSize;
Walls.Height = ySize;
Floor.X = q1X + 1;
Floor.Y = q1Y + 1;
Floor.Width = xSize - 1;
Floor.Height = ySize - 1;
}
public override string ToString()
{
return "[Walls: " + Walls + "\n Floor: " + Floor + "]";
}
}
}
Image below for reference
Your logic in GenerateRandomRoomSafe() is backwards.
In this code block:
while (!isValid && tries < maxTries)
{
check = GetRoomBounds();
for (int i = 0; i < rooms.Count; i++)
{
if (!rooms[i].Walls.IntersectsWith(check.Walls))
{
isValid = true;
break;
}
}
tries++;
}
What you're saying is, "If it doesn't intersect with at least one room, then it must be valid".
Just because it doesn't intersect with the current room, doesn't mean it won't intersect with a different one!
It should look more like: (note the comments)
while (!isValid && tries < maxTries)
{
isValid = true; // assume it's good until proven otherwise
check = GetRoomBounds();
for (int i = 0; i < rooms.Count; i++)
{
if (rooms[i].Walls.IntersectsWith(check.Walls)) // if it DOES intersect...
{
isValid = false; // .. then set valid to false.
break;
}
}
tries++;
}
So we start by assuming it is valid, then when we encounter a room that DOES intersect, we set valid to false and stop the for loop so another random room can be tried (assuming we haven't exceeded the number of tries).
Some of the maps it produced:
I'm trying to implement the MinMax algorithm for four in a row (or connect4 or connect four) game.
I think I got the idea of it, it should build a tree of possible boards up to a certain depth, evaluate them and return their score, then we just take the max of those scores.
So, aiChooseCol() checks the score of every possible column by calling MinMax() and returns the column with the max score.
Now I wasn't sure, is this the right way to call MinMax()?
Is it right to check temp = Math.Max(temp, 1000);?
I still haven't made the heuristic function but this should at least recognize a winning column and choose it, but currently it just choose the first free column from the left... I can't figure out what am I doing wrong.
private int AiChooseCol()
{
int best = -1000;
int col=0;
for (int i = 0; i < m_Board.Cols; i++)
{
if (m_Board.CheckIfColHasRoom(i))
{
m_Board.FillSignInBoardAccordingToCol(i, m_Sign);
int t = MinMax(5, m_Board, board.GetOtherPlayerSign(m_Sign));
if (t > best)
{
best = t;
col = i;
}
m_Board.RemoveTopCoinFromCol(i);
}
}
return col;
}
private int MinMax(int Depth, board Board, char PlayerSign)
{
int temp=0;
if (Depth <= 0)
{
// return from heurisitic function
return temp;
}
char otherPlayerSign = board.GetOtherPlayerSign(PlayerSign);
char checkBoard = Board.CheckBoardForWin();
if (checkBoard == PlayerSign)
{
return 1000;
}
else if (checkBoard == otherPlayerSign)
{
return -1000;
}
else if (!Board.CheckIfBoardIsNotFull())
{
return 0; // tie
}
if (PlayerSign == m_Sign) // maximizing Player is myself
{
temp = -1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Max(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
else
{
temp = 1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Min(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
return temp;
}
Some notes:
FillSignInBoardAccordingToCol() returns a boolean if it was successful.
The board type has a char[,] array with the actual board and signs of the players.
This code is in the AI Player class.
So I decided to write my own MinMax Connect 4. I used the depth to determine the value of a win or loss so that a move that gets you closer to winning or blocking a loss will take precedence. I also decide that I will randomly pick the move if more than one has the same heuristic. Finally I stretched out the depth to 6 as that's how many moves are required to find possible win paths from the start.
private static void Main(string[] args)
{
var board = new Board(8,7);
var random = new Random();
while (true)
{
Console.WriteLine("Pick a column 1 -8");
int move;
if (!int.TryParse(Console.ReadLine(), out move) || move < 1 || move > 8)
{
Console.WriteLine("Must enter a number 1-8.");
continue;
}
if (!board.DropCoin(1, move-1))
{
Console.WriteLine("That column is full, pick another one");
continue;
}
if (board.Winner == 1)
{
Console.WriteLine(board);
Console.WriteLine("You win!");
break;
}
if (board.IsFull)
{
Console.WriteLine(board);
Console.WriteLine("Tie!");
break;
}
var moves = new List<Tuple<int, int>>();
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(2, i))
continue;
moves.Add(Tuple.Create(i, MinMax(6, board, false)));
board.RemoveTopCoin(i);
}
int maxMoveScore = moves.Max(t => t.Item2);
var bestMoves = moves.Where(t => t.Item2 == maxMoveScore).ToList();
board.DropCoin(2, bestMoves[random.Next(0,bestMoves.Count)].Item1);
Console.WriteLine(board);
if (board.Winner == 2)
{
Console.WriteLine("You lost!");
break;
}
if (board.IsFull)
{
Console.WriteLine("Tie!");
break;
}
}
Console.WriteLine("DONE");
Console.ReadKey();
}
private static int MinMax(int depth, Board board, bool maximizingPlayer)
{
if (depth <= 0)
return 0;
var winner = board.Winner;
if (winner == 2)
return depth;
if (winner == 1)
return -depth;
if (board.IsFull)
return 0;
int bestValue = maximizingPlayer ? -1 : 1;
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(maximizingPlayer ? 2 : 1, i))
continue;
int v = MinMax(depth - 1, board, !maximizingPlayer);
bestValue = maximizingPlayer ? Math.Max(bestValue, v) : Math.Min(bestValue, v);
board.RemoveTopCoin(i);
}
return bestValue;
}
public class Board
{
private readonly int?[,] _board;
private int? _winner;
private bool _changed;
public Board(int cols, int rows)
{
Columns = cols;
Rows = rows;
_board = new int?[cols, rows];
}
public int Columns { get; }
public int Rows { get; }
public bool ColumnFree(int column)
{
return !_board[column, 0].HasValue;
}
public bool DropCoin(int playerId, int column)
{
int row = 0;
while (row < Rows && !_board[column,row].HasValue)
{
row++;
}
if (row == 0)
return false;
_board[column, row - 1] = playerId;
_changed = true;
return true;
}
public bool RemoveTopCoin(int column)
{
int row = 0;
while (row < Rows && !_board[column, row].HasValue)
{
row++;
}
if (row == Rows)
return false;
_board[column, row] = null;
_changed = true;
return true;
}
public int? Winner
{
get
{
if (!_changed)
return _winner;
_changed = false;
for (int i = 0; i < Columns; i++)
{
for (int j = 0; j < Rows; j++)
{
if (!_board[i, j].HasValue)
continue;
bool horizontal = i + 3 < Columns;
bool vertical = j + 3 < Rows;
if (!horizontal && !vertical)
continue;
bool forwardDiagonal = horizontal && vertical;
bool backwardDiagonal = vertical && i - 3 >= 0;
for (int k = 1; k < 4; k++)
{
horizontal = horizontal && _board[i, j] == _board[i + k, j];
vertical = vertical && _board[i, j] == _board[i, j + k];
forwardDiagonal = forwardDiagonal && _board[i, j] == _board[i + k, j + k];
backwardDiagonal = backwardDiagonal && _board[i, j] == _board[i - k, j + k];
if (!horizontal && !vertical && !forwardDiagonal && !backwardDiagonal)
break;
}
if (horizontal || vertical || forwardDiagonal || backwardDiagonal)
{
_winner = _board[i, j];
return _winner;
}
}
}
_winner = null;
return _winner;
}
}
public bool IsFull
{
get
{
for (int i = 0; i < Columns; i++)
{
if (!_board[i, 0].HasValue)
return false;
}
return true;
}
}
public override string ToString()
{
var builder = new StringBuilder();
for (int j = 0; j < Rows; j++)
{
builder.Append('|');
for (int i = 0; i < Columns; i++)
{
builder.Append(_board[i, j].HasValue ? _board[i,j].Value.ToString() : " ").Append('|');
}
builder.AppendLine();
}
return builder.ToString();
}
}
I'm a beginner in C#, trying to make a lottery form applicaton.
There are types, first when you have 5 tips ( otos bool ) and 5 tips ( hatos bool ).
And there are many types of how many numbers will be raffled (tiz, harminc, kilencven, negyvenot).
I tried to scan the numbers after the raffle with Array.Equals with this code:
for (int i = 0; i <= 4; i++)
{
for (int y = 0; y <= 4; y++)
{
if (Array.Equals(lottoszamok[i], lottoszamok[y]))
lottoszamok[i] = r.Next (1, ?);
}
}
but at this the number will be scanned with itself too, so it will be always equal.
here is my code by the way:
if (otos == true)
{
for (int i = 0; i <= 5; i++)
{
if (tiz == true)
{
lottoszamok[i] = r.Next(1, 10);
}
else if (harminc == true)
{
lottoszamok[i] = r.Next(1, 30);
}
else if (kilencven == true)
{
lottoszamok[i] = r.Next(1, 90);
}
else if (negyvenot == true)
{
lottoszamok[i] = r.Next(1, 45);
}
else if (egyeni == true)
{
lottoszamok[i] = r.Next(1, (egyeniertek + 1));
}
}
}
if (hatos == true)
{
for (int i = 0; i <= 6; i++)
{
if (tiz == true)
{
lottoszamok[i] = r.Next(1, 10);
}
else if (harminc == true)
{
lottoszamok[i] = r.Next(1, 30);
}
else if (kilencven == true)
{
lottoszamok[i] = r.Next(1, 90);
}
else if (negyvenot == true)
{
lottoszamok[i] = r.Next(1, 45);
}
else if (egyeni == true)
{
lottoszamok[i] = r.Next(1, (egyeniertek + 1));
}
}
}
If you're trying to pick numbers from a range 1..n without repetitions, you need to "shuffle" the numbers out:
int[] allPossibleNumbers = Enumerable.Range(1, maxNumber).ToArray();
int[] picked = new int[numberToPick];
for (int i = 0; i < numberToPick; i++)
{
int index = r.Next(i, maxNumber);
picked[i] = allPossibleNumbers[index];
allPossibleNumbers[index] = allPossibleNumbers[i];
}
where numberToPick is 5 if otos or 6 if hatos, and maxNumber depends on tiz, harminc, kilencven, negyvenot, egyeni and egyeniertek.
If your maxNumber is huge and you only want to pick a few numbers, the following doesn't require the whole range to be in memory at once:
Dictionary<int, int> outOfPlace = new Dictionary<int,int>();
int[] picked = new int[numberToPick];
for (int i = 0; i < numberToPick; i++)
{
int shuffleOut = outOfPlace.ContainsKey(i) ? outOfPlace[i] : i;
int index = r.Next(i, maxNumber);
picked[i] = 1 + (outOfPlace.ContainsKey(index) ? outOfPlace[index] : index);
outOfPlace[index] = shuffleOut;
outOfPlace.Remove(i);
}
Try this one!
if (i!=y && Array.Equals(lottoszamok[i], lottoszamok[y]))
I made it this way, if you want you could put swapping like method.
static void SwapInts(int[] array, int position1, int position2)
{
// Swaps elements in an array.
int temp = array[position1]; // Copy the first position's element
array[position1] = array[position2]; // Assign to the second element
array[position2] = temp; // Assign to the first element
}
static void Main()
{
Random rng = new Random();
int n = int.Parse(Console.ReadLine());
int[] intarray = new int[n];
for (int i = 0; i < n; i++)
{
// Initialize array
intarray[i] = i + 1;
}
// Exchange resultArray[i] with random element in resultArray[i..n-1]
for (int i = 0; i < n; i++)
{
int positionSwapElement1 = i + rng.Next(0, n - i);
SwapInts(intarray, i, positionSwapElement1);
}
for (int i = 0; i < n; i++)
{
Console.Write(intarray[i] + " ");
}
}
}
I spend many time to get this, but i believe i can do it, now it's done, By the Easier way in the word, this kill every think about Random not duplicate,very simply code without any philosophy or difficulty of Developers made ... (welcome to my work) that (BEST OF THE BEST):
Numbers between (1-10) without any duplicate, 1- MY WORK in C#
private void TenNumbersRandomly()
{
int[] a = new int[10];
Random r = new Random();
int x;
for (int i = 0; i < 10; i++)
{
x= r.Next(1, 11);
for (int j = 0; j <= i ; j++)
{
while (a[j] == x)
{
x = r.Next(1, 11);
j = 0;
}
}
a[i] = x;
tb1.Text += a[i]+"\n";
}
}
2- in VB some Different i also have it :
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim x As Integer, i As Integer, j As Integer
x = Int(Rnd() * 10) + 1
Label1.Text = ""
Dim a(9) As Integer
For i = 0 To 9
x = Int(Rnd() * 10) + 1
For j = 0 To i
While (a(j) = x)
x = Int(Rnd() * 10) + 1
j = 0
End While
Next j
a(i) = x
Label1.Text += a(i).ToString() + " "
Next i
What I am developing is that initially the entire sudoku board is empty.
One of the random cells(out of 81) is filled with a random value(1-9).
Now I want to fill all the remaining cells using brute force approach.
From what I came to know after googling is that we should start with the first cell and fill it with 1(if it's valid), then fill the second cell with 2(if it's valid, we will begin checking with a number greater than the last filled cell, which in this case is 1, once we reach 9, we reset it with 1).
The thing is that it's not working properly!
Can anyone link me to the exact algorithm.
Here's an implementation of the backtracking approach:
import java.util.Random;
public class Sudoku {
public static void main(String[] args) {
Random rand = new Random();
int r = rand.nextInt(9);
int c = rand.nextInt(9);
int value = rand.nextInt(9) + 1;
Board board = new Board();
board.set(r, c, value);
System.out.println(board);
solve(board, 0);
System.out.println(board);
}
private static boolean solve(Board board, int at) {
if (at == 9*9)
return true;
int r = at / 9;
int c = at % 9;
if (board.isSet(r, c))
return solve(board, at + 1);
for (int value = 1; value <= 9; value++) {
if (board.canSet(r, c, value)) {
board.set(r, c, value);
if (solve(board, at + 1))
return true;
board.unSet(r, c);
}
}
return false;
}
static class Board {
private int[][] board = new int[9][9];
private boolean[][] rs = new boolean[9][10];
private boolean[][] cs = new boolean[9][10];
private boolean[][][] bs = new boolean[3][3][10];
public Board() {}
public boolean canSet(int r, int c, int value) {
return !isSet(r, c) && !rs[r][value] && !cs[c][value] && !bs[r/3][c/3][value];
}
public boolean isSet(int r, int c) {
return board[r][c] != 0;
}
public void set(int r, int c, int value) {
if (!canSet(r, c, value))
throw new IllegalArgumentException();
board[r][c] = value;
rs[r][value] = cs[c][value] = bs[r/3][c/3][value] = true;
}
public void unSet(int r, int c) {
if (isSet(r, c)) {
int value = board[r][c];
board[r][c] = 0;
rs[r][value] = cs[c][value] = bs[r/3][c/3][value] = false;
}
}
public String toString() {
StringBuilder ret = new StringBuilder();
for (int r = 0; r < 9; r++) {
for (int c = 0; c < 9; c++)
ret.append(board[r][c]);
ret.append("\n");
}
return ret.toString();
}
}
}
I used a method without backtracing, although the while loop might be it. To quote an algorithm book I've read "Nothing in recursion can't be duplicated using iteration".
I've been using my eyes to inspect this, and since I can't wrap my head around the recursive method, even though recursion is relatively understood:
This method, I kinda wrote with some guidance, had a bug in the grid checker, when I found it, it seems to be working now. I'm positing it 'cause it's hard to find complete-and-working code. IOS SDK.
#define WIDTH 9
#define HEIGHT 9
#interface ViewController ()
//- (BOOL) numberConflicts:(int)testNum;
- (BOOL) number:(int)n conflictsWithRow:(int)r;
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
- (int) incrementSudokuValue:(int)v;
#end
static int sudoku[WIDTH][HEIGHT];
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
/// Initialize it
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
sudoku[x][y] = 0;
}
}
///
int tries = 0;
for (int j = 0; j < HEIGHT; j++)
{
for (int i = 0; i < WIDTH; i++)
{
int num = arc4random()%9 + 1;
while ([self number:num conflictsAtGridPointX:i andPointY:j])
{
num = [self incrementSudokuValue:num];
tries++;
if (tries > 10) { //restart the column
tries = 0;
for(int count = 0; count < WIDTH; count++)
{
sudoku[count][j] = 0;
}
i = 0;
}
}
if(sudoku[i][j] == 0)
sudoku[i][j] = num;
tries = 0;
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
printf("%i ", sudoku[x][y]);
}
printf("\n");
}
printf("\n");
}
}
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
printf("%i ", sudoku[y][x]);
}
printf("\n"); //newline
}
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL) number:(int)n conflictsWithRow:(int)r;
{
for (int y = 0; y < HEIGHT; y++) {
if (sudoku[y][r] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
{
for (int x = 0; x < WIDTH; x++) {
if (sudoku[c][x] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
{
if ([self number:n conflictsWithRow:yPoint])
{
return YES;
}
if ([self number:n conflictsWithColumn:xPoint])
{
return YES;
}
if ([self number:n conflictsWithSquareInPointX:xPoint andPointY:yPoint]) {
return YES;
}
return NO;
}
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
{
int leftX = x - (x % 3); //used to use int division
// leftX *= 3;
int topY = y - (y % 3);
// topY *= 3;
int rightX = leftX + 2;
int bottomY = topY + 2;
for(int subY = topY; subY <= bottomY; subY++) //bug was here, used < instead of less N equal to...
{
for ( int subX = leftX; subX <= rightX; subX++)
{
if (sudoku[subX][subY] == n) {
return YES;
}
}
}
NSLog(#"Testing grid at %i, %i", x/3, y/3);
NSLog(#"LeftX: %i TopY: %i", leftX, topY);
return NO;
}
- (int) incrementSudokuValue:(int)v;
{
if (v < 9) {
v++;
return v;
}
return 1;
}
Note: The header file is empty, paste this into iOS single View application if you desire.
Caution: might loop infinitely( and above does sometimes, but is very fast), may want another more global "tries" variable, and restart the algorithm as a safety, or give it a seed/do both
edit: the below should be safe from infinite loops, if the source grid is solvable (or nonexistant)
#define WIDTH 9
#define HEIGHT 9
#interface ViewController ()
//- (BOOL) numberConflicts:(int)testNum;
- (BOOL) number:(int)n conflictsWithRow:(int)r;
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
- (int) incrementSudokuValue:(int)v;
#end
static int sudoku[WIDTH][HEIGHT];
#implementation ViewController
- (BOOL) fillGridWithNext:(int)next;
{
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
if (sudoku[x][y] != 0)
{
if (x == 8 && y == 8) {
return YES;
}
continue;
}
for (int count = 0; count < (HEIGHT-1); count++)
{
if ([self number:next conflictsAtGridPointX:x andPointY:y])
{
next = [self incrementSudokuValue:next];
}
else
{
sudoku[x][y] = next;
if( [self fillGridWithNext:arc4random()%9+1])
{
return YES;
}
}
}
sudoku[x][y] = 0;
return NO;
}
}
return NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
/// Initialize it
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
sudoku[x][y] = 0;
}
}
sudoku[0][0]=9;
int next;
next = (arc4random()%9)+1;
if( [self fillGridWithNext:next]) //seeded
{
NSLog(#"Solved");
}
else
{
NSLog(#"No solution");
}
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
printf("%i ", sudoku[y][x]);
}
printf("\n"); //newline
}
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL) number:(int)n conflictsWithRow:(int)r;
{
for (int y = 0; y < HEIGHT; y++) {
if (sudoku[y][r] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsWithColumn:(int)c;
{
for (int x = 0; x < WIDTH; x++) {
if (sudoku[c][x] == n) {
return YES;
}
}
return NO;
}
- (BOOL) number:(int)n conflictsAtGridPointX:(int)xPoint andPointY:(int)yPoint;
{
if ([self number:n conflictsWithRow:yPoint])
{
return YES;
}
if ([self number:n conflictsWithColumn:xPoint])
{
return YES;
}
if ([self number:n conflictsWithSquareInPointX:xPoint andPointY:yPoint]) {
return YES;
}
return NO;
}
- (BOOL) number:(int)n conflictsWithSquareInPointX:(int)x andPointY:(int)y;
{
int leftX = x - (x % 3); //used to use int division
// leftX *= 3;
int topY = y - (y % 3);
// topY *= 3;
int rightX = leftX + 2;
int bottomY = topY + 2;
for(int subY = topY; subY <= bottomY; subY++) //bug was here, used < instead of less N equal to...
{
for ( int subX = leftX; subX <= rightX; subX++)
{
if (sudoku[subX][subY] == n) {
return YES;
}
}
}
NSLog(#"Testing grid at %i, %i", x/3, y/3);
NSLog(#"LeftX: %i TopY: %i", leftX, topY);
return NO;
}
- (int) incrementSudokuValue:(int)v;
{
if (v < 9) {
v++;
return v;
}
return 1;
}
#end
Summary: The first version is flawed but (mostly) gets the job done. It generates every row at random, if the row is invalid, it wipes and starts over. This will wipe out source grids, and can go forever, but works most of the time.
The lower code uses recursion. I don't think it backtracks properly, but it has solved empty and semi-seeded grids on my tests. I think I need to save a "state" grid to backtrack with, but I'm not doing this. I'm posting both since they both answer "Brute force"... on my own, I should study recursion, I can't explain why the lower one works, I personally could use help with doing it.
Note: The first one finishes in a blink or so when it does finish... if speed means more than reliability to your application (somewhat counter-intuitive in this case, with the infinite looping, heh).
This simple random walk algorithm should work too (but is inefficient- use at your own risk!!!):
EDIT: - added fix for unresolvable solutions.
For each empty cell in grid
array = Get_Legal_Numbers_for_cell(row,col);
If (array is empty) {
Clear_All_cells()
} else {
number = Random_number_from(array);
Put_Number_in_Cell(number);
}
EDIT 2
If someone are interested here are described methods for solving sudoku with random-based search.