I am having trouble converting this method from recursive to iterative. The problem that I am having specifically is I do not know how to convert a recursive call that is the condition of an if statement.
This needs to be done because the data sets that I am using are causing stack overflow exceptions.
There will have to be a stack of indices that are currently arguments being used for the recursive calls, but beyond that, I do not know what to do.
public static IEnumerable<BipartiteMatch> MaximumBipartiteMatch(int m, int n, Func<int, int, bool> isMapped)
{
var matches = new int[n];
for (var i = 0; i < n; ++i)
{
matches[i] = -1;
}
for (var x = 0; x < m; x++)
{
BipartiteMatch(x, n, new bool[n], matches, isMapped);
}
for (var index = 0; index < n; index++)
{
yield return new BipartiteMatch(matches[index], index);
}
}
private static bool BipartiteMatch(int x, int n, bool[] seen, int[] matches, Func<int, int, bool> isMapped)
{
for (var y = 0; y < n; y++)
{
if (seen[y] || !isMapped(x, y)) continue;
seen[y] = true;
//HERE:
if (matches[y] >= 0 && !BipartiteMatch(matches[y], n, seen, matches, isMapped)) continue;
matches[y] = x;
return true;
}
return false;
}
If matches[y] >= 0, then we need to push the value of matches[y] to a stack, but I am not sure how to loop it so it simulates recursion.
My attempt (it is buggy):
internal static class MaximumMatchingAlgorithm
{
internal static IEnumerable<BipartiteMatch> Solve(int m, int n, Func<int, int, bool> isMapped)
{
const int invalid = -1;
var mappings = new Stack<int>[m];
var matches = new int[n];
for (var index = 0; index < n; index++)
{
matches[index] = invalid;
}
for (var x = 0; x < m; x++)
{
var mapping = mappings[x] = new Stack<int>(n);
for (var y = 0; y < n; y++)
{
if (isMapped(x, y))
{
mapping.Push(y);
}
}
var currentX = x;
while (mapping.TryPop(out var y))
{
var tempX = matches[y];
var otherMapping = tempX != invalid ? mappings[tempX] : null;
if (otherMapping == null)
{
matches[y] = currentX;
break;
}
if (otherMapping.Count == 0) continue;
matches[y] = currentX;
currentX = tempX;
mapping = otherMapping;
}
}
for (var index = 0; index < n; index++)
{
yield return new BipartiteMatch(matches[index], index);
}
}
}
UPDATE:
Here is my second attempt after #EricLippert's comments. I created a State value to store where the loop stops so it can simulate the pause that would occur during recursion. There is still a bug somewhere, but I think this may be getting closer.
public struct State
{
public int X { get; set; }
public int Y { get; set; }
public bool Result { get; set; }
}
public static void BipartiteMatch(int x, int n, bool[] seen, int[] matches, Func<int, int, bool> isMapped)
{
var stack = new Stack<State>();
stack.Push(new State {X = x, Y = -1});
while (stack.TryPop(out var state))
{
if (state.Y != -1 && state.Result)
{
matches[state.Y] = state.X;
}
else
{
for (var y = state.Y != -1 ? state.Y : 0; y < n; y++)
{
if (seen[y] || !isMapped(state.X, y)) continue;
seen[y] = true;
if (matches[y] >= 0)
{
stack.Push(new State {X = state.X, Y = y});
stack.Push(new State {X = matches[y], Y = -1});
break;
}
if (stack.TryPop(out state))
{
stack.Push(new State {X = state.X, Y = state.Y, Result = true});
break;
}
matches[y] = state.X;
return;
}
}
}
}
I think I may have figured it out, but I would like a second opinion before I say it is all good.
The logic here is each time recursion would be used, push the current state of the loop to the stack along with the state that can answer whether or not the previously stacked state is valid. If the answer to the question is true, the entire stack is unwound and the method terminates, otherwise, continue searching.
public readonly struct State
{
public State(int x, int y = 0)
{
X = x;
Y = y;
}
public int X { get; }
public int Y { get; }
}
public static void BipartiteMatch(int x, int n, bool[] seen, int[] matches, Func<int, int, bool> isMapped)
{
var stack = new Stack<State>(new[] {new State(x)});
while (stack.TryPop(out var state))
{
for (var y = state.Y; y < n; y++)
{
if (seen[y] || !isMapped(state.X, y)) continue;
seen[y] = true;
if (matches[y] >= 0)
{
stack.Push(new State(state.X, y));
stack.Push(new State(matches[y]));
break;
}
matches[y] = state.X;
while (stack.TryPop(out state))
{
matches[state.Y] = state.X;
}
break;
}
}
}
Related
I'm trying to refactor my code for higher readability and I'm new to this.
I have two functions called UpFirst() and RightFirst() and they include common lines of code and I want to clean the repeating code.
Could you show me a good way to clean them from repeating lines?
private bool UpFirst()
{
var sameBlocks = new List<Tiles>();
var isAnyMatch = false;
for (var x = 0; x < _RowCount; x++)
{
for (var y = 0; y < _ColumnCount; y++)
{
if (y > _ColumnCount - _MinNumberToBlast)
continue;
var currentBlock = _tiles[x, y];
var isAllMatch = true;
for (var i = 1; i < _MinNumberToBlast; i++)
{
var blockToCheck = _tiles[x, y + i];
var isMatch = currentBlock.Color == blockToCheck.Color;
isAllMatch = isMatch;
if (!isMatch) break;
}
if (isAllMatch)
{
isAnyMatch = true;
sameBlocks.Add(currentBlock);
var newBlocks = FloodFill(x, y);
foreach (var block in newBlocks.Where(block => !sameBlocks.Contains(block)))
{
sameBlocks.Add(block);
}
var number = sameBlocks.Count;
var matchType = TileGroupType.Default;
if (number > _ConditionACount)
{
matchType = TileGroupType.A;
if (number > _ConditionBCount)
{
matchType = TileGroupType.B;
if (number > _ConditionCCount)
{
matchType = TileGroupType.C;
}
}
}
foreach (var block in sameBlocks)
{
block.SetMatchGroupType(matchType);
}
}
sameBlocks.Clear();
}
}
return isAnyMatch;
}
private bool RightFirst()
{
var sameBlocks = new List<Tiles>();
var isAnyMatch = false;
for (var y = 0; y < _ColumnCount; y++)
{
for (var x = 0; x < _RowCount; x++)
{
if (x > _RowCount - _MinNumberToBlast)
continue;
var currentBlock = _tiles[x, y];
currentBlock.SetMatchGroupType(TileGroupType.Default);
var isAllMatch = true;
for (var i = 1; i < _MinNumberToBlast; i++)
{
var blockToCheck = _tiles[x + i, y];
var isMatch = currentBlock.Color == blockToCheck.Color;
isAllMatch = isMatch;
if (!isMatch) break;
}
if (isAllMatch)
{
isAnyMatch = true;
sameBlocks.Add(currentBlock);
var newBlocks = FloodFill(x, y);
foreach (var block in newBlocks.Where(block => !sameBlocks.Contains(block)))
{
sameBlocks.Add(block);
}
var number = sameBlocks.Count;
var matchType = TileGroupType.Default;
if (number > _ConditionACount)
{
matchType = TileGroupType.A;
if (number > _ConditionBCount)
{
matchType = TileGroupType.B;
if (number > _ConditionCCount)
{
matchType = TileGroupType.C;
}
}
}
foreach (var block in sameBlocks)
{
block.SetMatchGroupType(matchType);
}
}
sameBlocks.Clear();
}
}
return isAnyMatch;
}
thank you!
I tried creating a third function including the if(isAllMatch) block and call it from both of them but didn't work because I had to define x and y and I could not handle it.
You could add a "neutral" method having parameters for the first and second count and a delegate to get the coordinates in the right order
private bool ProcessTiles(int count1, int count2,
Func<int, int, (int, int)> getXY)
{
...
for (int i = 0; i < count1; i++)
{
for (int j = 0; j < count2; j++)
{
if (j > count2 - _MinNumberToBlast)
continue;
var (x, y) = getXY(i, j);
Tiles currentBlock = _tiles[x, y];
bool isAllMatch = true;
for (int k = 1; k < _MinNumberToBlast; k++)
{
var (dx, dy) = getXY(0, k);
var blockToCheck = _tiles[x + dx, y + dy];
...
}
...
var newBlocks = FloodFill(x, y);
...
}
}
}
private bool UpFirst()
{
ProcessTiles(_RowCount, _ColumnCount, (i, j) => (i, j));
}
private bool RightFirst()
{
ProcessTiles(_ColumnCount, _RowCount, (i, j) => (j, i));
}
Func<int, int, (int, int)> getXY is a function that takes a pair of indexes and returns a tuple with those indexes. UpFirst passes the lambda expression (i, j) => (i, j) to return the indexes in the same order, whereas RightFirst uses (i, j) => (j, i) to invert the indexes.
var (x, y) = getXY(i, j); then gets the the right x, y values from the neutral indexes. Later we get the index added to either x or y with
var (dx, dy) = getXY(0, k);
var blockToCheck = _tiles[x + dx, y + dy];
In UpFirst we will get dx = 0, dy = k and in RightFirst we will get dx = k, dy = 0.
I have two variables: long[] nextState and List<long[]> TabuList.
I use this code to add items to TabuList:
TabuList.add(nextState);
or this:
TabuList.insert(Index, nexState);
but the problem is that after either of these operations, all of TabuList’s items automatically convert to the current value of nextState.
my complete code is:
class TabuSearch
{
private long[] current { get; set; }
private double Delta;
private Random rnd = new Random();
int foundLists = 0;
public TabuSearch()
{
current = new long[Convert.ToInt32(num_list1)];
}
public long[] TabuMOSA3Objectives(long[] c)
{
assign(current, c);
long[] nextState = new long[Convert.ToInt32(num_list1)];
List<long[]> TabuList = new List<long[]>();
double proba;
double alpha = 0.969;
double temperature = 500.0;
double epsilon = 0.0001;
short domination_st;
int iter = 0;
while (temperature > epsilon)
{
iter++;
Delta = 1;
assign(nextState, GenerateNextState(primaryList, current));
domination_st = CheckDomination3Objective(nextState, current);
try { var tmp = TabuList.Find(x => x == nextState); if (tmp == null) foundLists = 0; else foundLists = tmp.Count(); }
catch { }
if (foundLists == 0)
{
if (domination_st > 0)
{
assign(current, nextState);
}
else // domination_st < 0
{
proba = rnd.NextDouble();
if (proba < 1 / (1 + Math.Exp(Delta * temperature)))
{
assign(current, nextState);
}
else
{
if (TabuList.Count == 10)
TabuList.RemoveAt(0);
assign(nextState, TabuList);
}
}
}
//cooling proces on every iteration
temperature *= alpha;
}
return current;
}
}
static void assign(long[] c, long[] n)
{
for (int i = 0; i < c.Length; i++)
c[i] = n[i];
}
static void assign(long[] item, List<long[]> list)
{
list.Add(item);
}
I wanted to count number of 0 and 1 from a 2d array with floodfill algorithm....But unfortunetly...it's showing the wrong result.
I have a matrix like this
0,1,1,0,1
1,0,1,1,0
1,0,1,1,0
1,0,1,1,0
1,0,1,1,0
It supposed to show number of 0 = 10 and 1 =15
but it showing number of 0 = 4 and 1 = 21
here is my code
int[][] input;
public static int[,] reult;
public static int count = 0,col,row;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path;
OpenFileDialog file = new OpenFileDialog();
if (file.ShowDialog() == DialogResult.OK)
{
input = File.ReadLines(file.FileName)
.Skip(0)
.Select(l => l.Split(',')
.Select(n => int.Parse(n))
.ToArray())
.ToArray();
}
reult = JaggedToMultidimensional(input);
int p = reult.GetLength(0);
int q = reult.GetLength(1);
row = p-1;
col = q - 1;
int one = p * q;
int zero = apply(row, col);
label1.Text = "" + zero;
label2.Text = "" + (one - zero);
}
public T[,] JaggedToMultidimensional<T>(T[][] jaggedArray)
{
int rows = jaggedArray.Length;
int cols = jaggedArray.Max(subArray => subArray.Length);
T[,] array = new T[rows, cols];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
array[i, j] = jaggedArray[i][j];
}
}
return array;
}
private static int apply(int x, int y)
{
int currentColor = getValueAt(x, y);
if (currentColor == 0)
{
visit(x, y);
count++;
if (x < row) apply(x + 1, y);
if(y<col) apply(x, y + 1);
if(x>0) apply(x - 1, y);
if (y>0) apply(x, y - 1);
}
return count;
}
private static int getValueAt(int x, int y)
{
if (x < 0 || y < 0 || x > row || y > col)
{
return -1;
}
else
{
return reult[x,y];
}
}
private static void visit(int x, int y)
{
reult[x,y] = 1;
}
int zero = apply(row, col);
In your flood fill algorithm, you are only going in four direction and cover the area which match your criteria. And fortunately [row,col] index has 0 and it count all four 0 from [row, col]. Now think what if apply(row,col) have 1 on that row, col index.
To get this thing right, you need to loop through whole matrix and call apply(i,j) where ever you find an array[i,j]==0
Change this line
int zero = apply(row, col);
to
int zero = 0;
for(int i=0; i<=row; i++)
{
for(int j=0; j<=col; j++)
{
if(array[i][j]==0)
{
count =0;
zero+= apply(row, col);
}
}
}
Hope this helps.
Given the requirements you should change the search criteria to search for 0's and 1's.
What you need to do is to search within the rectangle so the border of the rectangle is limit for searching.
i.e.
int[] count = {0,0};
private static int apply(int x, int y)
{
int currentColor = getValueAt(x, y);
if (currentColor != -1)
{
visit(x, y);
count[currentColor]++;
if (x < row) apply(x + 1, y);
if(y<col) apply(x, y + 1);
if(x>0) apply(x - 1, y);
if (y>0) apply(x, y - 1);
}
return count;
}
and then change your visit function to set the cell to -1 instead to avoid visiting it twice.
You can also use linq if you want (I actually prefer):
OpenFileDialog fileDialog = new OpenFileDialog();
if (fileDialog.ShowDialog() == DialogResult.OK)
{
var lines = File.ReadLines(fileDialog.FileName);
var splittedValues = lines.Where(l => !string.IsNullOrEmpty(l)).Select(l => l.Split(',')).SelectMany(l => l).ToList();
var valCount = splittedValues.GroupBy(s => s).Select(s => new { val = s.Key, count = s.Count() }).ToList();
}
It will give you following result:
[0] { val= "0", count=10} [1] { val= "1", count=15}
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!
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.