Knight's destination using recursion - c#

I've been working on a project which needs the knight(we have it's coordinates at the start) travel to destination(also known coordinates).
I tried to write using recursion but my code doesn't seem to be doing anything and I can't find the problem. Here's my code:
static bool Kelias(int dabX, int dabY, string[] Lenta, int dX, int dY, int indeksas)
{
if (dabX == dX && dabY == dY)
return true;
if (!Lenta[dabY][dabX].Equals('0'))
{
return false;
}
if (indeksas > 0)
{
StringBuilder naujas = new StringBuilder(Lenta[dabY]);
naujas[dabX] = (char)indeksas;
Lenta[dabY] = naujas.ToString();
}
// aukstyn desinen
if (GaliJudeti(dabX + 2, dabY + 1)
&& Kelias(dabX + 2, dabY + 1, Lenta, dX, dY, indeksas + 1))
{
return true;
}
// aukstyn desinen
if (GaliJudeti(dabX + 1, dabY + 2)
&& Kelias(dabX + 1, dabY + 2, Lenta, dX, dY, indeksas + 1))
{
return true;
}
// aukstyn kairen
if (GaliJudeti(dabX - 1, dabY + 2)
&& Kelias(dabX - 1, dabY + 2, Lenta, dX, dY, indeksas + 1))
{
return true;
}
// aukstyn kairen
if (GaliJudeti(dabX - 2, dabY + 1)
&& Kelias(dabX - 2, dabY + 1, Lenta, dX, dY, indeksas + 1))
{
return true;
}
// zemyn kairen
if (GaliJudeti(dabX - 2, dabY - 1)
&& Kelias(dabX - 2, dabY - 1, Lenta, dX, dY, indeksas + 1))
{
return true;
}
// zemyn kairen
if (GaliJudeti(dabX - 1, dabY - 2)
&& Kelias(dabX - 1, dabY - 2, Lenta, dX, dY, indeksas + 1))
{
return true;
}
// zemyn desinen
if (GaliJudeti(dabX + 1, dabY - 2)
&& Kelias(dabX + 1, dabY - 2, Lenta, dX, dY, indeksas + 1))
{
return true;
}
// zemyn desinen
if (GaliJudeti(dabX + 2, dabY - 1)
&& Kelias(dabX + 2, dabY - 1, Lenta, dX, dY, indeksas + 1))
{
return true;
}
indeksas--;
return false;
}
static bool GaliJudeti(int x, int y)
{
if (x >= 0 && y >= 0 && x < 8 && y < 8)
{
return true;
}
return false;
}
A little explanation about the variables and what I'm trying to do:
dabX, dabY - are the current coordinates of the Knight
Lenta - is my board(it's a string cause I'm reading the starting data from a txt file).
dX, dY - is the target destination
indeksas - is a tracker of how many moves it takes to reach the destination
Now the first if checks if we reached the destination. Second one checks if the coordinates to which we're traveling too are not obstructed(Since my board is made out of zeroes cause it's in a string we check if the symbol is equal to it cause if it's not means path is obstructed). Then we move onto the knights possible movements which is the main part of the method.
Also there's another function called GaliJudeti which checks if we're in bounds of the board(8x8).

Your code looks like it must work. I just used your algorithm, modified it a bit and everything works fine. I used classes to make it look more generally, but in fact it's all the same.
static bool MoveFirstSolution(Knight knight, Board board, Point destination, int counter, Trace trace)
{
board.Set(knight.X, knight.Y, counter);
if (knight.IsInPoint(destination))
{
//trace is an object to store found path
trace.Counter = counter;
trace.Board = board;
return true;
}
counter++;
Point[] moves = knight.AllPossibleMoves();
foreach (Point point in moves)
{
if (board.Contains(point) && board.IsFree(point))
{
knight.MoveTo(point);
if (MoveFirstSolution(knight, board.GetCopy(), destination, counter, trace))
{
return true;
}
}
}
return false;
}
However, this function will find first solution and stop. If you want best solution, you need to continue the search even when the answer is found. Here is a function to perform it:
static void Move(Knight knight, Board board, Point destination, int counter, Trace trace)
{
board.Set(knight.X, knight.Y, counter);
if (knight.IsInPoint(destination))
{
if (!trace.IsShorterThen(counter))
{
trace.Counter = counter;
trace.Board = board;
Console.WriteLine("Better trace");
Console.WriteLine("Counter: " + trace.Counter);
Console.WriteLine(trace.Board);
}
return;
}
counter++;
Point[] moves = knight.AllPossibleMoves();
foreach(Point point in moves)
{
if (board.Contains(point) && board.IsFree(point))
{
knight.MoveTo(point);
Move(knight, board.GetCopy(), destination, counter, trace);
}
}
}
The trace is overwritten each time when better one is found. But for 8 * 8 board it takes really long time to execute.
For your code I can advise to try Console.WriteLine() to be sure, that everything works. Maybe, you Lenta is not overwritten, as you expected and this causes infinite recursion. Try tracking each action of your function, to find the source of problem.
Here are my main function:
static void Main(string[] args)
{
Knight knight = new Knight(0, 0);
Board board = new Board(8, 8);
Point destination = new Point(0, 4);
Trace bestTrace = new Trace();
MoveFirstSolution(knight, board, destination, 1, bestTrace);
Console.WriteLine("Best trace: " + bestTrace.Counter);
Console.WriteLine(bestTrace.Board);
Console.ReadLine();
}
and the rest of required classes, so you can try it as working example.
class Trace
{
public Trace()
{
this.Board = null;
this.Counter = -1;
}
public Trace(Board board, int counter)
{
this.Board = board;
this.Counter = counter;
}
public bool IsShorterThen(int counter)
{
return this.Counter > 0 && this.Counter <= counter;
}
public Board Board { get; set; }
public int Counter { get; set; }
}
class Board
{
private int[][] _board;
public Board(int N, int M)
{
this._board = new int[N][];
for (int i = 0; i < N; i++)
{
this._board[i] = new int[M];
for (int j = 0; j < M; j++)
{
this._board[i][j] = 0;
}
}
}
public int N
{
get
{
return this._board.Length;
}
}
public int M
{
get
{
return this._board.Length > 0 ? this._board[0].Length : 0;
}
}
public Board GetEmptyCopy()
{
return new Board(this.N, this.M);
}
public Board GetCopy()
{
Board b = new Board(this.N, this.M);
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
b.Set(i, j, this.Get(i, j));
}
}
return b;
}
public bool Contains(int i, int j)
{
return (i >= 0) && (i < this.N) && (j >= 0) && (j < this.M);
}
public bool Contains(Point point)
{
return this.Contains(point.X, point.Y);
}
public bool IsFree(int i, int j)
{
return this._board[i][j] == 0;
}
public bool IsFree(Point point)
{
return this.IsFree(point.X, point.Y);
}
public void Set(int i, int j, int val)
{
this._board[i][j] = val;
}
public int Get(int i, int j)
{
return this._board[i][j];
}
public override string ToString()
{
string str = "";
for (int i = 0; i < this.N; i++)
{
for (int j = 0; j < this.M; j++)
{
str += String.Format("{0, 3}", this._board[i][j]);
}
str += "\r\n";
}
return str;
}
}
class Knight
{
public Knight(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; private set; }
public int Y { get; private set; }
public Point[] AllPossibleMoves()
{
Point[] moves = new Point[8];
moves[0] = new Point(this.X + 1, this.Y + 2);
moves[1] = new Point(this.X + 1, this.Y - 2);
moves[2] = new Point(this.X + 2, this.Y + 1);
moves[3] = new Point(this.X + 2, this.Y - 1);
moves[4] = new Point(this.X - 1, this.Y + 2);
moves[5] = new Point(this.X - 1, this.Y - 2);
moves[6] = new Point(this.X - 2, this.Y + 1);
moves[7] = new Point(this.X - 2, this.Y - 1);
return moves;
}
public bool IsInPoint(int x, int y)
{
return this.X == x && this.Y == y;
}
public bool IsInPoint(Point point)
{
return this.IsInPoint(point.X, point.Y);
}
public void MoveTo(int x, int y)
{
this.X = x;
this.Y = y;
}
public void MoveTo(Point point)
{
this.MoveTo(point.X, point.Y);
}
}
class Point
{
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; private set; }
public int Y { get; private set; }
}

Related

What is wrong with my IEquatable<T>, IComparable<T> implementation? SortedList throws ArgumentException

I am working on solving a puzzle online and stumbled upon this problem where given a 2D matrix and a number k, I need to return the kth smallest element in the matrix.
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
return 13.
I am able to solve this problem with my own implementation of a Binary Heap. Since I am preparing for interviews, I am not sure if implementing my own Heap is an acceptable solution in all cases. So I tried to solve this with SortedList/SortedSet.
I am basically creating a Point object that takes index i, j and the value at i, j. I have implemented IComparable and IEquatable. But for some reason, with the above example, the Point object for index 1,2(value 13) and the one for index 2,1(value 13) are being considered equal when they shouldn't be. I get an ArgumentException when using a SortedList, a SortedSet meanwhile just overwrites the existing object. Is my implementation of IEquatable, IComparable wrong? I have double checked that they generate different hashcodes.
P.S. This is not a homework problem. I am solving questions from an online interview prep platform.
public class Solution {
public int KthSmallest(int[,] matrix, int k) {
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
SortedSet<Point> pq = new SortedSet<Point>();
bool[,] visited = new bool[rows, cols];
int count = 1;
int i=0, j=0;
var start = new Point(i, j, matrix[i, j]);
pq.Add(start);
visited[0, 0] = true;
while(true) {
k--;
var curr = pq.Min;
pq.Remove(pq.First());
if(k == 0)
return curr.val;
i = curr.x + 1;
j = curr.y;
if(i < rows && j < cols && !visited[i, j]) {
var next = new Point(i, j, matrix[i, j]);
Console.WriteLine(next.GetHashCode());
Console.WriteLine(i+", "+j+", "+next.val);
pq.Add(next);
visited[i, j] = true;
}
i = curr.x;
j = curr.y + 1;
if(i < rows && j < cols && !visited[i, j]) {
var next = new Point(i, j, matrix[i, j]);
Console.WriteLine(next.GetHashCode());
Console.WriteLine(i+", "+j+", "+next.val);
pq.Add(next);
visited[i, j] = true;
}
}
}
}
public class Point : IComparable<Point>, IEquatable<Point>
{
public int x { get; private set; }
public int y { get; private set; }
public int val { get; private set; }
public Point(int x, int y, int val)
{
this.x = x;
this.y = y;
this.val = val;
}
public int CompareTo(Point that)
{
if(this.val == that.val) {
if(this.x == that.x) {
return this.y.CompareTo(that.y);
}
else {
this.x.CompareTo(that.x);
}
}
return val.CompareTo(that.val);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Point)obj);
}
public bool Equals(Point p1) {
return x == p1.x && y == p1.y && val == p1.val;
}
public override int GetHashCode() {
long hashCode = ((x * 31 + y) * 31 + val);
return hashCode.GetHashCode();
}
}
You're missing a return statement in your CompareTo. I commented your original below, along with a corrected version. In the case of comparing [2,1] and [1,2], the x values don't match, but when you hit the this.x.CompareTo, you never actually return that comparison, so instead your value comparison returns.
You have:
public int CompareTo(Point that)
{
if(this.val == that.val) {
if(this.x == that.x) {
return this.y.CompareTo(that.y);
}
else {
//****MISSING RETURN STATEMENT -
//will return the val.ComapreTo statement after
//it leaves this block*****
this.x.CompareTo(that.x);
}
}
return val.CompareTo(that.val);
}
You need:
public int CompareTo(Point that)
{
if(this.val == that.val) {
if(this.x == that.x) {
return this.y.CompareTo(that.y);
}
else {
return this.x.CompareTo(that.x);
}
}
return val.CompareTo(that.val);
}

Concave Hull implementation

I am trying to implement the algorithm described in the following http://repositorium.sdum.uminho.pt/bitstream/1822/6429/1/ConcaveHull_ACM_MYS.pdf
I am using the following class libraries. Loyc libs come from http://core.loyc.net/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Device.Location;
using Loyc.Collections;
using Loyc.Geometry;
using Loyc;
Here is the basic class
public class Hulls
{
private static List<Point<double>> KNearestNeighbors(List<Point<double>> points, Point<double> currentPoint, int k, out int kk)
{
kk = Math.Min(k, points.Count - 1);
var ret = points
.OrderBy(x => PointMath.Length(new Vector<double>(currentPoint.X - x.X, currentPoint.Y - x.Y)))
.Take(k)
.ToList();
return ret;
}
private static double Angle(Point<double> a, Point<double> b)
{
var ret = -Math.Atan2(b.Y - a.Y, b.X - a.X);
return NormaliseAngle(ret);
}
private static double NormaliseAngle(double a)
{
//while (a < b - Math.PI) a += Math.PI * 2;
//while (b < a - Math.PI) b += Math.PI * 2;
if (a < 0.0) { return a + Math.PI + Math.PI; }
return a;
}
private static List<Point<double>> SortByAngle(List<Point<double>> kNearest, Point<double> currentPoint, double angle)
{
//kNearest
// .Sort((v1, v2) => AngleDifference(angle, Angle(currentPoint, v1)).CompareTo(AngleDifference(angle, Angle(currentPoint, v2))));
//return kNearest.ToList();
kNearest = kNearest.OrderByDescending(x => NormaliseAngle(Angle(currentPoint, x) - angle)).ToList();
return kNearest;
}
private static bool CCW(Point<double> p1, Point<double> p2, Point<double> p3)
{
var cw = ((p3.Y - p1.Y) * (p2.X - p1.X)) - ((p2.Y - p1.Y) * (p3.X - p1.X));
return cw > 0 ? true : cw < 0 ? false : true; // colinear
}
private static bool _Intersect(LineSegment<double> seg1, LineSegment<double> seg2)
{
return CCW(seg1.A, seg2.A, seg2.B) != CCW(seg1.B, seg2.A, seg2.B) && CCW(seg1.A, seg1.B, seg2.A) != CCW(seg1.A, seg1.B, seg2.B);
}
private static bool Intersect(LineSegment<double> seg1, LineSegment<double> seg2)
{
if ((seg1.A.X == seg2.A.X && seg1.A.Y == seg2.A.Y)
|| (seg1.B.X == seg2.B.X && seg1.B.Y == seg2.B.Y))
{
return false;
}
if (_Intersect(seg1, seg2))
{
return true;
}
return false;
}
public IListSource<Point<double>> KNearestConcaveHull(List<Point<double>> points, int k)
{
points.Sort((a, b) => a.Y == b.Y ? (a.X > b.X ? 1 : -1) : (a.Y >= b.Y ? 1 : -1));
Console.WriteLine("Starting with size {0}", k.ToString());
DList<Point<double>> hull = new DList<Point<double>>();
var len = points.Count;
if (len < 3) { return null; }
if (len == 3) { return hull; }
var kk = Math.Min(Math.Max(k, 3), len);
var dataset = new List<Point<double>>();
dataset.AddRange(points.Distinct());
var firstPoint = dataset[0];
hull.PushFirst(firstPoint);
var currentPoint = firstPoint;
dataset.RemoveAt(0);
double previousAngle = 0;
int step = 2;
int i;
while ((currentPoint != firstPoint || step == 2) && dataset.Count > 0)
{
if (step == 5) { dataset.Add(firstPoint); }
var kNearest = KNearestNeighbors(dataset, currentPoint, k, out kk);
var cPoints = SortByAngle(kNearest, currentPoint, previousAngle);
var its = true;
i = 0;
while (its == true && i < cPoints.Count)
{
i++;
int lastPoint = 0;
if (cPoints[i - 1] == firstPoint)
{
lastPoint = 1;
}
int j = 2;
its = false;
while (its == false && j < hull.Count - lastPoint)
{
LineSegment<double> line1 = new LineSegment<double>(hull[step - 2], cPoints[i - 1]);
LineSegment<double> line2 = new LineSegment<double>(hull[step - 2 - j], hull[step - 1 - j]);
//its = LineMath.ComputeIntersection(line1, line2, out pfrac, LineType.Segment);
its = Intersect(line1, line2);
j++;
}
}
if (its == true)
{
return KNearestConcaveHull(points, kk + 1);
}
currentPoint = cPoints[i - 1];
hull.PushLast(currentPoint);
previousAngle = Angle(hull[step - 1], hull[step - 2]);
dataset.Remove(currentPoint);
step++;
}
bool allInside = true;
i = dataset.Count;
while (allInside == true && i > 0)
{
allInside = PolygonMath.IsPointInPolygon(hull, dataset[i - 1]);
i--;
}
if (allInside == false) { return KNearestConcaveHull(points, kk + 1); }
return hull;
}
}
The above is supposed to pick a new edge for the boundary based on the furthest right-hand turn from the previous edge going around the point set counterclockwise. The code seems to pick the correct first edge from the initial vertex which has the lowest y-value, but then does not pick the next edge correctly when the offset angle is nonzero. I think the issue is the SortByAngle or Angle. -atan2 would return the clockwise turn, correct? Possibly I should be adding the offset angle?
EDIT (SOLUTION): Found the issue after following Eric's helpful advice provided in the first comment to the question. It was SortByAngle and Angle:
private static double Angle(Point<double> a, Point<double> b)
{
var ret = Math.Atan2(b.Y - a.Y, b.X - a.X);
return NormaliseAngle(ret);
}
private static double NormaliseAngle(double a)
{
if (a < 0.0) { return a + Math.PI + Math.PI; }
return a;
}
private static List<Point<double>> SortByAngle(List<Point<double>> kNearest, Point<double> currentPoint, double angle)
{
//kNearest = kNearest.OrderByDescending(x => NormaliseAngle(Angle(currentPoint, x) - angle)).ToList();
kNearest.Sort((a, b) => NormaliseAngle(Angle(currentPoint, a) - angle) > NormaliseAngle(Angle(currentPoint, b) - angle) ? 1 : -1);
return kNearest;
}
You have some bug:
var kNearest = KNearestNeighbors(dataset, currentPoint, k, out kk);
Change the kk to just some var. You override the incrementation of that "kk" value, and then you're getting StackOverflow exceptions.
Change your code to the following:
int someVal;
var kNearest = KNearestNeighbors(dataset, currentPoint, k, out someVal);

Generating a maze in C# - It Doesn't Show the maze

Although there is a maze.display() in this code, there isn't any maze appearing in the console for my console application. It just says "Press any key to continue..."
source is http://rosettacode.org/wiki/Maze_generation
Here is the code :
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Drawing;
namespace MazeGeneration
{
public static class Extensions
{
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
var e = source.ToArray();
for (var i = e.Length - 1; i >= 0; i--)
{
var swapIndex = rng.Next(i + 1);
yield return e[swapIndex];
e[swapIndex] = e[i];
}
}
public static CellState OppositeWall(this CellState orig)
{
return (CellState)(((int)orig >> 2) | ((int)orig << 2)) & CellState.Initial;
}
}
[Flags]
public enum CellState
{
Top = 1,
Right = 2,
Bottom = 4,
Left = 8,
Visited = 128,
Initial = Top | Right | Bottom | Left,
}
public struct RemoveWallAction
{
public Point Neighbour;
public CellState Wall;
}
public class Maze
{
private readonly CellState[,] _cells;
private readonly int _width;
private readonly int _height;
private readonly Random _rng;
public Maze(int width, int height)
{
_width = width;
_height = height;
_cells = new CellState[width, height];
for (var x = 0; x < width; x++)
for (var y = 0; y < height; y++)
_cells[x, y] = CellState.Initial;
_rng = new Random();
VisitCell(_rng.Next(width), _rng.Next(height));
}
public CellState this[int x, int y]
{
get { return _cells[x, y]; }
set { _cells[x, y] = value; }
}
public IEnumerable<RemoveWallAction> GetNeighbours(Point p)
{
if (p.X > 0) yield return new RemoveWallAction { Neighbour = new Point(p.X - 1, p.Y), Wall = CellState.Left };
if (p.Y > 0) yield return new RemoveWallAction { Neighbour = new Point(p.X, p.Y - 1), Wall = CellState.Top };
if (p.X < _width - 1) yield return new RemoveWallAction { Neighbour = new Point(p.X + 1, p.Y), Wall = CellState.Right };
if (p.Y < _height - 1) yield return new RemoveWallAction { Neighbour = new Point(p.X, p.Y + 1), Wall = CellState.Bottom };
}
public void VisitCell(int x, int y)
{
this[x, y] |= CellState.Visited;
foreach (var p in GetNeighbours(new Point(x, y)).Shuffle(_rng).Where(z => !(this[z.Neighbour.X, z.Neighbour.Y].HasFlag(CellState.Visited))))
{
this[x, y] -= p.Wall;
this[p.Neighbour.X, p.Neighbour.Y] -= p.Wall.OppositeWall();
VisitCell(p.Neighbour.X, p.Neighbour.Y);
}
}
public void Display()
{
var firstLine = string.Empty;
for (var y = 0; y < _height; y++)
{
var sbTop = new StringBuilder();
var sbMid = new StringBuilder();
for (var x = 0; x < _width; x++)
{
sbTop.Append(this[x, y].HasFlag(CellState.Top) ? "+--" : "+ ");
sbMid.Append(this[x, y].HasFlag(CellState.Left) ? "| " : " ");
}
if (firstLine == string.Empty)
firstLine = sbTop.ToString();
Debug.WriteLine(sbTop + "+");
Debug.WriteLine(sbMid + "|");
Debug.WriteLine(sbMid + "|");
}
Debug.WriteLine(firstLine);
}
}
class Program
{
static void Main(string[] args)
{
var maze = new Maze(20, 20);
maze.Display();
}
}
}
Maybe try to change Debug.WriteLine to Console.WriteLine
The output isn't going to the console, it is going to the output window in Visual Studio. If your output window isn't visible, enable it with Ctrl+W, O
If you really do want the output to go to the console, replace instances of Debug.WriteLine to Console.WriteLine

OutOfMemoryException For Maze Solver of Large Dimensions

The Program Works for arrays upto 20x20 But for anything larger it throws an OutOfMemoryException.
Below is the code:
public static Point GetFinalPath(int x, int y) {
queue.Enqueue(new Point(x,y, null));
while(queue.Count>0) {
Point p = queue.Dequeue();
if (arr[p.x,p.y] == 9) {
Console.WriteLine("Found Destination");
return p;
}
if(IsOpen(p.x+1,p.y)) {
arr[p.x,p.y] = 1;
queue.Enqueue(new Point(p.x+1,p.y, p));
}
//similarly for the other directions
}
return null;
}
public int[,] SolutionMaze()
{
Point p = GetFinalPath(0, 0);
while (p.getParent() != null)
{
solvedarray[p.x, p.y] = 9;
p = p.getParent();
}
return solvedarray;
}
ok people here is the rest of the code
public static Queue<Point> queue=new Queue<Point>();
public static bool IsOpen(int x, int y)
{
//BOUND CHECKING
if ((x >= 0 && x < XMAX) && (y >= 0 && y < YMAX) && (arr[x,y] == 0 || arr[x,y] == 9))
{
return true;
}
return false;
}
public class Point
{
public int x;
public int y;
Point parent;
public Point(int x, int y, Point parent)
{
this.x = x;
this.y = y;
this.parent = parent;
}
public Point getParent()
{
return this.parent;
}
}
Assumes start to be 0,0 and final destination is set as 9 at the constructor.
Help me implement this for an array of size 500x500
Well, looking at your code I found one problem. You perform the wrong check. You should check if your point is already added to a queue. What do you do now? We'll, you are just marking processed cell as not open. It's easy to see that you can add to queue same node twice.
Let's follow my example:
1 | . .
0 | ! .
--+----
yx| 0 1
Queue: point (0,0)
We are starting at point(0,0). At this moment, we are adding points (0, 1) and (1,0) to our queue and mark point(0,0) as processed
1 | . .
0 | X !
--+----
yx| 0 1
Queue: point (0,1), point (1,0)
Now we dequeue point(0,1), marking it processed and adding point(1,1) to queue.
1 | ! .
0 | X X
--+----
yx| 0 1
Queue: point (1,0), point(1,1)
Now we dequeue point(1,0), marking it as processed and adding point(1,1) to queue:
1 | X !
0 | X X
--+----
yx| 0 1
Queue: point (1,1), point (1,1)
And now we have same point twice in a queue. And that is not your last problem. Your points have a reference to all it parents, so your previous points (doubled too) can't be processed with Garbage Collector.
Okay i found an answer to the OutOfMemory. Now the code works even for 500x500 matrix
As it turns out i just implemented a node list which keeps track of added nodes in queue using y*MAX_X_LENGTH + x formula
public static Queue<Point> queue=new Queue<Point>();
public SolveMaze(int[,] array,int staX,int staY,int finX,int finY)
{
//sets Destination as 9
arr = array;
XMAX = array.GetLength(0);
YMAX = array.GetLength(1);
finishY = finX; finishX = finY; startY = staX; startX = staY;
solvedarray = new int[XMAX, YMAX];
}
public static List<int> nodelist=new List<int>();
public void AddPointToQueueIfOpenAndNotAlreadyPresent(Point p,int direction)
{
if (nodelist.Contains(XMAX * p.y + p.x))
return;
else
{
switch(direction){
case 1:
//north
if (IsOpen(p.x, p.y - 1))
{
arr[p.x, p.y] = 1;
queue.Enqueue(new Point(p.x, p.y - 1, p));
nodelist.Add(XMAX * (p.y - 1) + p.x);
}
break;
case 0:
//east
if (IsOpen(p.x + 1, p.y))
{
arr[p.x, p.y] = 1;
queue.Enqueue(new Point(p.x + 1, p.y, p));
nodelist.Add(XMAX * (p.y) + p.x + 1);
}
break;
case 3:
//south
if (IsOpen(p.x, p.y + 1))
{
arr[p.x, p.y] = 1;
queue.Enqueue(new Point(p.x, p.y +1, p));
nodelist.Add(XMAX * (p.y + 1) + p.x);
}
break;
case 2:
//west
if (IsOpen(p.x - 1, p.y))
{
arr[p.x, p.y] = 1;
queue.Enqueue(new Point(p.x - 1, p.y, p));
nodelist.Add(XMAX * (p.y) + p.x-1);
}
break; }
}
}
public Point GetFinalPath(int x, int y) {
if (arr[finishX, finishY] == 0)
arr[finishX, finishY] = 9;
else
return null;
queue.Enqueue(new Point(x, y, null));
nodelist.Add(XMAX * y + x);
while(queue.Count>0) {
Point p = queue.Dequeue();
nodelist.Remove(p.y * XMAX + p.x);
if (arr[p.x,p.y] == 9) {
Console.WriteLine("Exit is reached!");
return p;
}
for (int i = 0; i < 4; i++)
{
AddPointToQueueIfOpenAndNotAlreadyPresent(p, i);
}
}
return null;
}
public static bool IsOpen(int x, int y)
{
//BOUND CHECKING
if ((x >= 0 && x < XMAX) && (y >= 0 && y < YMAX) && (arr[x,y] == 0 || arr[x,y] == 9))
{
return true;
}
return false;
}
public int[,] SolutionMaze()
{
Point p = GetFinalPath(startX, startY);
if(p!=null)
while (p.getParent() != null)
{
solvedarray[p.x, p.y] = 9;
p = p.getParent();
}
return solvedarray;
}
}
public class Point
{
public int x;
public int y;
Point parent;
public Point(int x, int y, Point parent)
{
this.x = x;
this.y = y;
this.parent = parent;
}
public Point getParent()
{
return this.parent;
}
}

Connect 4 check diagonally [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Hallo I can see this question been asked before. However I do not understand or can see how I can implment it myself. If its possible could you explain what you are doing and maybe add some kind of pseudo code so I can see the flow of the script.
I've done the vertical and horizontal lines like this and yes PlayingBoard is a 2d Array:
private void HasWon(int xPlaced, int yPlaced) {
//MessageBox.Show(xPlaced.ToString()+","+yPlaced.ToString());
int[] Coords = new int[2];
/// <summary>
/// This part checks if we have a win on East or West
/// </summary>
Coords[0] = xPlaced;
Coords[1] = yPlaced;
while(Coords[0] != 0)
{
Coords[0] -= 1;
if (PlayingBoard[Coords[0], Coords[1]] == playerValue)
{
foundInRow += 1;
}
else { break; }
}
Coords[0] = xPlaced;
Coords[1] = yPlaced;
while (Coords[0] < 6)
{
Coords[0] += 1;
if (PlayingBoard[Coords[0], Coords[1]] == playerValue)
{
foundInRow += 1;
}
else { break; }
}
if (foundInRow > 2) { MessageBox.Show("You won."); Won = true; }
else { foundInRow = 0; Won = false; }
/// <summary>
/// This part checks if we have a win on North or South
/// </summary>
Coords[0] = xPlaced;
Coords[1] = yPlaced;
while(Coords[1] != 0)
{
Coords[1] -= 1;
if (PlayingBoard[Coords[0], Coords[1]] == playerValue)
{
foundInRow += 1;
}
else { break; }
}
Coords[0] = xPlaced;
Coords[1] = yPlaced;
while (Coords[1] < 6)
{
Coords[1] += 1;
if (PlayingBoard[Coords[0], Coords[1]] == playerValue)
{
foundInRow += 1;
}
else { break; }
}
if (foundInRow > 2) { MessageBox.Show("You won."); Won = true; }
else { foundInRow = 0; Won = false; }
}
Here is a connect four solver which works using recursion.
It accepts a 2 dimensional array b which represents the board. each element in the array can be populated with an int where 0 represents an empty space 1 player one, 2 player two etc
the Checkboard method returns an int where -1 represents no winner and positive integers represent the winning players number
the method works by iterating through each square in the array from 0,0 and checking the three possible directions, left, diagonal and down for a further 3 adjacent elements containing the same number. if a row of 4 is found the method returns the number in the square it was checking at the time.
public class Connect4Solver
{
public int Checkboard(int[,] b)
{
for (int x = 0; x < b.GetLength(0); x++)
{
for (int y = 0; y < b.GetLength(1); y++)
{
for (int d = 0; d < 3; d++)
{
int p = b[x, y];
if (p != 0)
{
if (countDir(0, b, x, y, d, p) >= 3)
{
//win for p
return p;
}
}
}
}
}
return -1;
}
protected int countDir(int depth, int[,] b, int x, int y, int dir, int p)
{
int x2;
int y2;
if (getposdir(b, x, y, dir, out x2, out y2) == p)
{
//good
depth++;
return countDir(depth, b, x2, y2, dir, p);
}
else
{
return depth;
}
}
protected int getposdir(int[,] b, int x, int y, int dir, out int x2, out int y2)
{
if (dir == 0)
{
x2 = x + 1;
y2 = y;
}
else if (dir == 1)
{
x2 = x + 1;
y2 = y + 1;
}
else if (dir == 2)
{
x2 = x;
y2 = y + 1;
}
else
{
throw new Exception("unknown");
}
return getpos(b, x2, y2);
}
protected int getpos(int[,] b, int x, int y)
{
if (b.GetLength(0) <= x)
{
return -1;
}
if (b.GetLength(1) <= y)
{
return -1;
}
return b[x, y];
}
}
note: I forgot to check 'down and right' assuming it would like 'down'
and 'left' not be required. I leave this as an exercise for the reader
to add

Categories