Sudoku Backtracking - Order of walking through fields by amount of possible values - c#

I've created a backtracking algorithm for solving Sudoku puzzles which basicly walks through all the empty fields from left to right, top down respectively. Now I need to make an extended version in which the order in which the algorithm walks through the fields is defined by the amount of possibilities (calculated once, at initialization) for each of the fields. E.g. empty fields which initially have the fewest amount of possible values should be visited first, and only the initially possible values should be checked (both to reduce the amount of iterations needed). Now I'm not sure how to go on implementing this without increasing the amount of iterations needed to actually define these values for each field and then obtain the next field with the fewest possibilities.
For my backtracking algorithm I have a nextPosition method which determines the next empty field in the sudoku to visit. Right now it looks like this:
protected virtual int[] nextPosition(int[] position)
{
int[] nextPosition = new int[2];
if (position[1] == (n * n) - 1)
{
nextPosition[0] = position[0]+1;
nextPosition[1] = 0;
}
else
{
nextPosition[0] = position[0];
nextPosition[1] = position[1]+1;
}
return nextPosition;
}
So it basicly walks through the sudoku left-right, top-down respectively. Now I need to alter this for my new version to walk through the fields ordered by the fewest amount of possible values for the fields (and only trying the possible values for each field in my backtracking algorithm). I figured I'd try to keep a list of invalid values for each field:
public void getInvalidValues(int x, int y)
{
for (int i = 0; i < n * n; i++)
if (grid[y, i] != 0)
this.invalidValues[y, i].Add(grid[y, i]);
for (int i = 0; i < n * n; i++)
if (grid[i, x] == 0)
this.invalidValues[i, x].Add(grid[i, x]);
int nX = (int)Math.Floor((double)x / n);
int nY = (int)Math.Floor((double)y / n);
for (int x = 0; x < n; x++)
for (int y = 0; y < n; y++)
if (grid[nY * n + y, nX * n + x] != 0)
this.invalidValues[y, x].Add(grid[y, x]);
}
Calling this method for every empty field in the sudoku (represented in this.grid as 2D array [nn,nn]). However this causes even more iterations since in order to determine the amount of different invalid values for each field it'll have to walk through each list again.
So my question is whether someone knows a way to efficiently walk through the fields of the sudoku ordered by the amount of possible values for each field (at the same time keeping track of these possible values for each field since they are needed for the backtracking algorithm). If anyone could help me out on this it'd be much appreciated.
Thanks in advance!

Related

C# - How to place a given number of random mines in an array

I'm new to c#. I have a task to make a type of minesweeper, but which immediately opens a solution.
static void Main(string[] args)
{
Console.Write("Enter the width of the field: ");
int q = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter the length of the field: ");
int w = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter the number of bombs: ");
int c = Convert.ToInt32(Console.ReadLine());
Random rand = new Random();
var charArray = new char[q, w];
var intArray = new int[q, w];
for (int i = 0; i < q; i++)
{
for (int j = 0; j < w; j++)
{
intArray[i, j] = rand.Next(2);
charArray[i, j] = intArray[i, j] == 0 ? '_' : '*';
Console.Write(charArray[i, j]);
}
Console.WriteLine();
}
}
}
}
Two arrays should be output. Everything should be closed on the first one, that is, there should be only the characters: _ and *
0 - these are places without mines, I replaced them with a symbol _
1 - these are places with mines, I replaced them with an asterisk symbol, but they do not accept the number of mines entered by the user. And it is necessary that there are as many "*" characters as there are mines.
And in the second array there should be an already open solution of the game. That is, the cells next to which there are mines should take a number meaning the number of mines next to this cell.
Please help me..
Compiling the current code
Random random = new Random();
while(c > 0)
{
var rq = random.Next(q);
var rw = random.Next(w);
if(intArray[rq,rw] == 0)
{
intArray[rq, rw] = 1;
c--;
}
}
I would suggest dividing the problem in smaller manageable chunks. For instance, you can place the bombs in a initial step, and on a second step build the solution. You can build the solution at the same time you place the bombs, although for clarity you can do it after.
Naming of variables is also important. If you prefer using single letter variable names, I believe that's fine for the problem limits, however I would use meaningful letters easier to remember. eg: W and H for the width and height of the board, and B for the total number of bombs.
The first part of the problem then can be described as placing B bombs in a WxH board. So instead of having nested for statements that enumerate WxH times, it's better to have a while loop that repeats the bomb placing logic as long as you have remaining bombs.
Once you generate a new random location on the board, you have to check you haven't placed a bomb there already. You can have an auxiliary function HasBomb that checks that:
bool HasBomb(char[,] charArray, int x, int y)
{
return charArray[x,y] == '*';
}
I'll leave error checking out, this function being private can rely on the caller sending valid coordinates.
Then the bomb placing procedure can be something like:
int remainingBombs = B;
while (remainingBombs > 0)
{
int x = rand.Next(W);
int y = rand.Next(H);
if (!HasBomb(charArray, x, y)
{
charArray[x,y] = '*';
remainingBombs--;
}
}
At this point you may figure out another concern. If the number B of bombs to place is larger than the available positions on the board WxH, then you wont be able to place the bombs on the board. You'll have to check for that restriction when requesting the values for W, H and B.
Then in order to create the array with the number of bombs next to each position, you'll need some way to check for all the neighbouring positions to a given one. If the position is in the middle of the board it has 8 neighbour positions, if it's on an edge it has 5, and if it's on a corner it has 3. Having a helper function return all the valid neighbour positions can be handy.
IEnumerable<(int X, int Y)> NeighbourPositions(int x, int y, int W, int H)
{
bool leftEdge = x == 0;
bool topEdge = y == 0;
bool rightEdge = x == W - 1;
bool bottomEdge = y == H - 1;
if (!leftEdge && !topEdge)
yield return (x-1, y-1);
if (!topEdge)
yield return (x, y-1);
if (!rightEdge && !topEdge)
yield return (x+1, y-1);
if (!leftEdge)
yield return (x-1, y);
if (!rightEdge)
yield return (x+1, y);
if (!leftEdge && !bottomEdge)
yield return (x-1, y+1);
if (!bottomEdge)
yield return (x, y+1);
if (!rightEdge && !bottomEdge)
yield return (x+1, y+1)
}
This function uses Iterators and touples. If you feel those concepts are too complex as you said are new to C#, you can make the function return a list with coordinates instead.
Now the only thing left is to iterate over the whole intArray and increment the value on each position for each neighbour bomb you find.
for (int x = 0; x < W; x++)
{
for (int y = 0; y < H; y++)
{
foreach (var n in NeighbourPositions(x, y, W, H))
{
if (HasBomb(charArray, n.X, n.Y))
intArray[x,y]++;
}
}
}
The answers here are mostly about generating random x and random y put in loop and trying to put the mine into empty cells. It is ok solution, but if you think of it, it is not that sufficient. Every time you try to find a new random cell, there is chance that cell is already a mine. This is pretty much alright, if you don't put too many mines into your field, but if you put some greater number of mines, this event can occur quite often. This means that the loop might take longer than usually. Or, theoretically, if you wanted to put 999 mines into 1000 cell field, it would be really hard for the loop to fill all the necessary cells, especially for the last mine. Now, I am not saying that the solutions here are bad, I think, it's really alright solution for many people. But if someone wanted a little bit efficient solution, I have tried to crate it.
Solution
In this solution, you iterate each cell and try to calculate a probability of the mine to be placed there. I have come up with this easy formula, which calculates the probability:
Every time you try to place a mine into one cell, you calculate this formula and compare it to random generated number.
bool isMine = random.NextDouble() < calcProbability();

Distribute quantities into buckets - Not evenly

I've been searching around for a solution to this, but I think because of how I'm thinking about it, my search phrases might be a bit loaded in favor of topics that aren't completely relevant.
I have a number, say 950,000. This represents an inventory of [widgets] within an entire system. I have about 200 "buckets" that should each receive a portion of this inventory such that there are no widgets left over.
What I would like to happen is for each bucket to receive different amounts. I don't have any solid code to show right now, but here's some pesudo code to illustrate what I've been thinking:
//List<BucketObject> _buckets is a collection of "buckets", each of which has a "quantity" property for holding these numbers.
int _widgetCnt = 950000;
int _bucketCnt = _buckets.Count; //LINQ
//To start, each bucket receives (_widgetCnt / _bucketCnt) or 4750.
for (int _b = 0; b< _bucketCnt - 1; i++)
{
int _rndAmt = _rnd.Next(1, _buckets[i].Quantity/2); //Take SOME from this bucket...
int _rndBucket = _rnd.Next(0,_bucketCnt - 1); //Get a random bucket index from the List<BucketObject> collection.
_buckets.ElementAt(_rndBucket).Quantity += _rndAmt;
_buckets.ElementAt(i).Quantity -= _rndAmt;
}
Is this a statistically/mathematically proper way to handle this, or is there a distribution formula out there that handles this? The kicker is that while this pseudo code would run 200 times (so each bucket has a chance to alter its quantities) it would have to run X number of times depending on the TYPE of widget (which currently stands at just 11 flavors, but is expected to expand significantly in the future).
{EDIT}
This system is for a commodity trading game. Quantities at the 200 shops must differ because the inventory will determine the price at that station. The distro can't be even because that would make all prices the same. Over time, prices will naturally get out of balance, but the inventory must start out off-balance. And all inventories have to be at least similar in scope (ie, no one shop can have 1 item, and another have 900,000)
Sure, there is a solution. You could use Dirichlet Distribution for such task. Property of the distribution is that
Sumi xi = 1
So solution would be to sample 200 (equal the number of buckets) random values from Dirichlet, and then multiply each value by 950,000 (or whatever total inventory is) and that would give you number of items per bucket. If you want non-uniform sampling, you could tweak alpha in the Dirichlet sampling.
Items per bucket shall be rounded up/down, of course, but that is pretty trivial
I have Dirichlet sampling in C# somewhere, if you struggle to implement it - tell me and I would dig it out
UPDATE
I found some code, .NET Core 2, below is the excerpt. I used to sample Dirichlet RNs with the sample alphas, making all of them different is trivial.
//
// Dirichlet sampling, using Gamma sampling from Math .NET
//
using MathNet.Numerics.Distributions;
using MathNet.Numerics.Random;
static void SampleDirichlet(double alpha, double[] rn)
{
if (rn == null)
throw new ArgumentException("SampleDirichlet:: Results placeholder is null");
if (alpha <= 0.0)
throw new ArgumentException($"SampleDirichlet:: alpha {alpha} is non-positive");
int n = rn.Length;
if (n == 0)
throw new ArgumentException("SampleDirichlet:: Results placeholder is of zero size");
var gamma = new Gamma(alpha, 1.0);
double sum = 0.0;
for(int k = 0; k != n; ++k) {
double v = gamma.Sample();
sum += v;
rn[k] = v;
}
if (sum <= 0.0)
throw new ApplicationException($"SampleDirichlet:: sum {sum} is non-positive");
// normalize
sum = 1.0 / sum;
for(int k = 0; k != n; ++k) {
rn[k] *= sum;
}
}

Selection sort with strings

Okay, I've been using this code to do a selection sort on integers:
public void selectSort(int [] arr)
{
//pos_min is short for position of min
int pos_min,temp;
for (int i=0; i < arr.Length-1; i++)
{
pos_min = i; //set pos_min to the current index of array
for (int j=i+1; j < arr.Length; j++)
{
if (arr[j] < arr[pos_min])
{
//pos_min will keep track of the index that min is in, this is needed when a swap happens
pos_min = j;
}
}
//if pos_min no longer equals i than a smaller value must have been found, so a swap must occur
if (pos_min != i)
{
temp = arr[i];
arr[i] = arr[pos_min];
arr[pos_min] = temp;
}
}
}
but now I want to run the same algorithm on a string list instead.
How could that be accomplished? It feels really awkward and like you would need additional loops to compare multiple chars of different strings..?
I tried a lot, but I couldn't come up with anything useful. :/
Note:
I know, selection sort isn't very efficient. This is for learning purposes only. I'm not looking for alternative algorithms or classes that are already part of C#. ;)
IComparable is an interface that gives us a function called CompareTo, which is a comparison operator. This operator works for all types which implement the IComparable interface, which includes both integers and strings.
// Forall types A where A is a subtype of IComparable
public void selectSort<A>(A[] arr)
where A : IComparable
{
//pos_min is short for position of min
int pos_min;
A temp;
for (int i=0; i < arr.Length-1; i++)
{
pos_min = i; //set pos_min to the current index of array
for (int j=i+1; j < arr.Length; j++)
{
// We now use 'CompareTo' instead of '<'
if (arr[j].CompareTo(arr[pos_min]) < 0)
{
//pos_min will keep track of the index that min is in, this is needed when a swap happens
pos_min = j;
}
}
//if pos_min no longer equals i than a smaller value must have been found, so a swap must occur
if (pos_min != i)
{
temp = arr[i];
arr[i] = arr[pos_min];
arr[pos_min] = temp;
}
}
}
The System.String class has a static int Compare(string, string) method that returns a negative number if the first string is smaller than the second, zero if they are equal, and a positive integer if the first is larger.
By "smaller" I mean that it comes before the other in the lexical order and by larger that it comes after the other in lexical order.
Therefore you can compare String.Compare(arr[j], arr[pos_min]) < 0 instead of just arr[j] < arr[pos_min] for integers.
I am writing the code in python 3.6
First import sys module for use of various features in our syntax.
import sys
Consider an array of string data type items.
A = ['Chuck', 'Ana', 'Charlie', 'Josh']
for i in range(0, len(A)):
min_val = i
for j in range(i+1, len(A)):
if A[min_val] > A[j]:
min_val = j
Swapping the indexed and minimum value here.
(A[min_val], A[i]) = (A[i], A[min_val])
print("Sorted Array is :")
for i in range(len(A)):
print("%s" % A[i])
This works perfectly fine for an array of string datatype and sorts out the input data in an alphabetical way out.
As in the input 'Charlie' and 'Chuck' are being compared according to their alphabetical preference till the 3rd place and arranged accordingly.
The output of this program on python console is
Sorted Array is :
Ana
Charlie
Chuck
Josh

C# Using .Count with Tuple Items

I am trying to compare the contents of a number of Tuples inside of a List. The code runs reasonable well, but on certain occasions, completeList[z].Item1.Count will come back with the wrong number. When I look in the debugger, in one example a = completeList[z].Item1.Count might return 18 when the count is 9. So this causes it to go out of range.
completeList.Count returns correctly, as does completeList[z].Item1[b], so I'm not sure what I could be doing wrong with completeList[z].Item1.Count.
Thanks for any insights!
int x = completeList.Count;
int y = 0;
while (y < x)
{
for (int z = 0; z < x; z++)
{
if (y != z && completeList[y].Item6.Equals(completeList[z].Item6))
{
int a = completeList[z].Item1.Count;
a = a -1;
for (int b = 0; b < a; b++)
{
if (completeList[y].Item1.Contains(completeList[z].Item1[b]))
{
completeList[z].Item1.RemoveAt(b);
completeList[z].Item2.RemoveAt(b);
completeList[z].Item3.RemoveAt(b);
completeList[z].Item4.RemoveAt(b);
completeList[z].Item5.RemoveAt(b);
}
}
}
}
y++;
}
You're removing items from the list. This is changing the count, and also moving around the indexes of the existing items. The count is correct at the start of the loop, but by the time you've actually removed an item, the count is no longer valid.
The most effective solution is to not iterate the list while removing items at all; instead rely on the list's RemoveAll method to remove all of the items that match your list of items to remove. While it's possible for you to manage the indexes properly to remove while iterating, you should avoid this complexity.

Random selection for a variable set with a guarantee of every item at least once

I am working on a game in c# but that detail is not really neccessary to solve my problem.
At I high level here is what I want:
I have a set that could have any number of items in it.
I want to randomly select 10 items from that set.
If the set has less than 10 items in then I expect to select the same
item more than once.
I want to ensure every item is selected at least once.
What would be the algorithm for this?
Sorry I'm not sure if this is an appropriate place to ask, but I've got no pen and paper to hand and I can't quite get my head round what's needed so appreciate the help.
In addition I might also want to add weights to the items to
increase/decrease chance of selection, so if you are able to
incorporate that into your answer that would be fab.
Finally thought I should mention that my set is actually a List<string>, which might be relevent if you prefer to give a full answer rather than psuedo code.
This is what I use to randomize an array. It takes an integer array and randomly sorts that list a certain amount of times determined by the random number (r).
private int[] randomizeArray(int[] i)
{
int L = i.Length - 1;
int c = 0;
int r = random.Next(L);
int prev = 0;
int curr = 0;
int temp;
while (c < r)
{
curr = random.Next(0, L);
if (curr != prev)
{
temp = i[prev];
i[prev] = i[curr];
i[curr] = temp;
c++;
}
}
return i;
}
If you look for effective code, my answer isnt it. In theory, create some collection you can remove from that will mirror your set. Then select random member of the object from it ...and remove, this will garantee items wont repeat(if possible).
Random rnd = new Random();
List<int> indexes = new List<int>(items.Count);
for (int i = 0; i < items.Count; i++)
indexes.Add(i);
List<string> selectedItems = new List<string>(10);
int tmp;
for(int i = 0; i < 10; i++)
{
tmp = rnd.Next(1,10000); //something big
if(indexes.Count > 0)
{
selectedItems.Add(yourItems[indexes[tmp%indexes.Count]]);
indexes.RemoveAt(tmp%indexes.Count);
}
else
selectedItems.Add(yourItems[rnd.Next(0,9)]); //you ran out of unique items
}
where items is your list and yourItems is list of selected items, you dont need to store them if you want process them right away
Perhaps shuffle the collection and pick elements from the front until you have the required amount.
Once you've gone through all the elements, you should perhaps shuffle it again, so you don't just repeat the same sequence.
The basic algorithm for shuffling: (in pseudo-code)
for i from n − 1 downto 1 do
j ← random integer with 0 ≤ j ≤ i
exchange a[j] and a[i]
With the above algorithm (or a minor variation), it's possible to just shuffle until you reach the required number of elements, no need to shuffle the whole thing.

Categories