How can I refactor these two functions with repeating code? - c#

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.

Related

How do I fix my stack overflow error for Sudoku solver c#? Has to do with Recursive function?

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.

How to convert this recursive function to an iterative one?

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;
}
}
}

Unable to detect if two rectangles are colliding C#

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:

How to convert ND array to 1D and revert it back

I need to convert n array (dimension is not known) to 1d and revert it back to nd array.
I loop through the whole array and add elements to 1d to convert, but I don't know how to revert it back.
public class ArrayND<T>
{
private int[] _lengths;
private Array _array;
public ArrayND(int[] length)
{
_lengths = length;
_array = Array.CreateInstance(typeof (T), _lengths);
}
}
///Loop through
public float[] ConvertTo1D(ArrayND<float> ndArray)
{
float[] OneDArray = new float[ndArray.Values.Length];
System.Collections.IEnumerator myEnumerator = ndArray.Values.GetEnumerator();
int cols = ndArray.Values.GetLength(ndArray.Values.Rank - 1);
int j = 0;
while (myEnumerator.MoveNext())
{
OneDArray[j] = (float)myEnumerator.Current;
j++;
}
return OneDArray;
}
public class ArrayND<T>
{
private int[] _lengths;
private Array _array;
public ArrayND(int[] length)
{
_lengths = length;
_array = Array.CreateInstance(typeof(T), _lengths);
}
public T GetValue(int[] index) => (T)_array.GetValue(index);
public void SetValue(T value, int[] index) => _array.SetValue(value, index);
public T[] ToOneD() => _array.Cast<T>().ToArray();
public static ArrayND<T> FromOneD(T[] array, int[] lengths)
{
if (array.Length != lengths.Aggregate((i, j) => i * j))
throw new ArgumentException("Number of elements in source and destination arrays does not match.");
var factors = lengths.Select((item, index) => lengths.Skip(index).Aggregate((i, j) => i * j)).ToArray();
var factorsHelper = factors.Zip(factors.Skip(1).Append(1), (Current, Next) => new { Current, Next }).ToArray();
var res = new ArrayND<T>(lengths);
for (var i = 0; i < array.Length; i++)
res.SetValue(array[i],
factorsHelper.Select(item => i % item.Current / item.Next).ToArray());
return res;
}
public override bool Equals(object obj) =>
(obj is ArrayND<T> ndArray) &&
_lengths.SequenceEqual(ndArray._lengths) &&
_array.Cast<T>().SequenceEqual(ndArray._array.Cast<T>());
public override int GetHashCode() =>
new[] { 17 }
.Concat(_lengths.Select(i => i.GetHashCode()))
.Concat(_array.Cast<T>().Select(i => i.GetHashCode()))
.Aggregate((i, j) => unchecked(23 * i + j));
}
It works with any number of dimensions.
Test it:
int I = 2, J = 3, K = 4;
var a = new ArrayND<int>(new[] { I, J, K });
var v = 0;
for (var i = 0; i < I; i++)
for (var j = 0; j < J; j++)
for (var k = 0; k < K; k++)
a.SetValue(++v, new[] { i, j, k });
var b = a.ToOneD();
var c = ArrayND<int>.FromOneD(b, new[] { I, J, K });
Console.WriteLine(a.Equals(c)); // True
or:
int I = 2, J = 3;
var a = new ArrayND<int>(new[] { I, J });
var v = 0;
for (var i = 0; i < I; i++)
for (var j = 0; j < J; j++)
a.SetValue(++v, new[] { i, j });
var b = a.ToOneD();
var c = ArrayND<int>.FromOneD(b, new[] { I, J });
Console.WriteLine(a.Equals(c)); // True
or:
int I = 2, J = 3, K = 4, M = 5;
var a = new ArrayND<int>(new[] { I, J, K, M });
var v = 0;
for (var i = 0; i < I; i++)
for (var j = 0; j < J; j++)
for (var k = 0; k < K; k++)
for (var m = 0; m < M; m++)
a.SetValue(++v, new[] { i, j, k, m });
var b = a.ToOneD();
var c = ArrayND<int>.FromOneD(b, new[] { I, J, K, M });
Console.WriteLine(a.Equals(c)); // True
Well, I solve it in a weird way. I am open to better approaches
public ArrayND<string> convert1DtoND(string[] oneDarray, int[] dimension)
{
ArrayND<string> ndArray = new ArrayND<string>(dimension);
int[] index = new int[ndArray.Values.Rank];
int[] length = new int[ndArray.Values.Rank];
int j = 0;
for (int i = 0; i < length.Length; i++)
{
length[i] = ndArray.Values.GetLength(i);
}
do
{
ndArray[index] = oneDarray[j];
j++;
} while (Increment(index, length));
return ndArray;
}
public static bool Increment(int[] index, int[] length)
{
int i = index.Length - 1;
index[i]++;
while (i >= 0 && index[i] == length[i] && length[i] > 0)
{
index[i--] = 0;
if (i >= 0)
index[i]++;
}
if (i < 0 || length[i] == 0)
return false;
else
return true;
}

Knuth Morris Pratt algorithm implementation

I'm trying to implement KMP algorithm. Part "if (W[i] == S[m + i])" returns index out of range exception and I can't get it to work.
I was following example on Wikipedia: https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
static int[] KMPTable(string W)
{
int[] T = new int[W.Length];
int pos = 2;
int cnd = 0;
T[0] = -1;
T[1] = 0;
while (pos < W.Length)
{
if (W[pos - 1] == W[cnd])
{
T[pos] = cnd + 1;
cnd = cnd + 1;
pos = pos + 1;
}
else
if (cnd > 0)
{
cnd = T[cnd];
}
else
{
T[pos] = 0;
pos = pos + 1;
}
}
return T;
}
static int[] KMPSearch(string S, string W)
{
int m = 0;
int i = 0;
int[] kmpNext = KMPTable(S);
List<int> result = new List<int>();
while (m + i < S.Length)
{
if (W[i] == S[m + i])
{
if (i == W.Length - 1)
{
result.Add(m);
}
i = i + 1;
}
else
{
m = m + i - kmpNext[i];
if (kmpNext[i] > -1)
i = kmpNext[i];
else
i = 0;
}
}
return result.ToArray();
}
When m + i < S.Length, then it might be W[i] that is out of its index. Try checking with a step-by-step debug.

Categories