Related
I am having trouble editing the values of a 2d char array.
char[,] chrRaster = new char[4, 5];
After adding values to the array and printing it to the console, I get:
// Input example:
*****
**.**
*****
****.
I am trying to make an algorithm that replaces every '*' that is beside, under or above a '.' by a '.' and then printing this to the console.
// Output after algorithm example:
**.**
*...*
**.*.
***..
I have tried converting the 2d char array to a 2d string array and then using IndexOf('*') to replace every '*' that is beside, under or above a '.', and I also tried calculating this using a number of if and for loops without any luck.
static void Main(string[] args)
{
// Variablen
int intTestgeval = 0; // Number of times you want program to repeat
int intN = 0; // Number of rows
int intM = 0; // Number of coloms
char chrGrond; // Used to store '*' or '.'
char[,] chrRaster; // 2d char array used to store all values
// Code
try
{
intTestgeval = Int32.Parse(Console.ReadLine()); // Number of times program will repeat
if(intTestgeval > 150) // Program can not repeat more then 150 times
{
throw new Exception();
}
}
catch (Exception)
{
Environment.Exit(0);
}
intN = Controle(intN); // Number of rows ophalen
intM = Controle(intM); // Number of Coloms ophalen
chrRaster = new char[intN, intM]; // Initializing array with user input
for (int intR = 0; intR < intTestgeval; intR++) // Print 2d array to console
{
for(int intY = 0; intY < intN; intY++)
{
for(int intZ = 0; intZ < intM; intZ++)
{
chrGrond = Convert.ToChar(Console.ReadKey().KeyChar);
chrRaster[intY, intZ] = chrGrond;
}
Console.WriteLine();
}
instorten[intR] = Instorten(chrRaster, intN, intM); // Ignore this part, that's another part of my assignment not related to my question.
}
}
static int Controle( int intX )
{
try
{
intX = Int32.Parse(Console.ReadLine());
if (intX > 150 || intX < 1) // Length of row and colom can not exceed 20 and can not go lower then 1
{
throw new Exception();
}
return intX;
}
catch // Program will off if value does not meet requirements
{
Environment.Exit(0);
return intX;
}
}
// It is this part of the program I need help with. This is what I tried but can't get any further
static int Instorten(char[,] chrRaster, int intN, int intM)
{
for (int intY = 0; intY < intN; intY++)
{
for (int intZ = 0; intZ < intM; intZ++)
{
if(chrRaster[intY, intZ] == '.' && chrRaster[intY, intZ + 1] == '*' || chrRaster[intY, intZ] == '*' && chrRaster[intY, intZ + 1] == '.')
{
}
}
Console.WriteLine();
}
int intm = 0;
return intm;
}
}
One way to do this would be to make a copy of the array and then iterate over it, examining each item. If the item is a '.', then update the neighbors of this item in the original array.
To determine the neighbors, we simply add one to the row to get the neighbor below, subtract one from the row to get the neighbor above, and similarly we can get the right and left neighbors by adding/subtracting from the column value. Of course we need to ensure that we're inside the bounds of the array before doing anything.
We could write a method with this logic that might look like:
private static void ExposeDotNeighbors(char[,] input)
{
if (input == null) return;
// Make a copy of the input array that we can iterate over
// so that we don't analyze items that we've already changed
var copy = (char[,]) input.Clone();
for (var row = 0; row <= copy.GetUpperBound(0); row++)
{
for (var col = 0; col <= copy.GetUpperBound(1); col++)
{
if (copy[row, col] == '.')
{
// Update neighbors in original array
// Above = [row - 1, col], Below = [row + 1, col],
// Left = [row, col - 1], Right = [row, col + 1]
// Before updating, make sure we're inside the array bounds
if (row > 0) input[row - 1, col] = '.';
if (row < input.GetUpperBound(0)) input[row + 1, col] = '.';
if (col > 0) input[row, col - 1] = '.';
if (col < input.GetUpperBound(1)) input[row, col + 1] = '.';
}
}
}
}
We can also write some helper methods that will give us the initial array and to print an array to the console (also one that will write a header to the console):
private static char[,] GetInitialArray()
{
var initialArray = new char[4, 5];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
if ((row == 1 && col == 2) || (row == 3 && col == 4))
{
initialArray[row, col] = '.';
}
else
{
initialArray[row, col] = '*';
}
}
}
return initialArray;
}
private static void PrintArrayToConsole(char[,] input)
{
if (input == null) return;
for (var row = 0; row <= input.GetUpperBound(0); row++)
{
for (var col = 0; col <= input.GetUpperBound(1); col++)
{
Console.Write(input[row, col]);
}
Console.WriteLine();
}
}
private static void WriteHeader(string headerText)
{
if (string.IsNullOrEmpty(headerText))
{
Console.Write(new string('═', Console.WindowWidth));
return;
}
Console.WriteLine('╔' + new string('═', headerText.Length + 2) + '╗');
Console.WriteLine($"║ {headerText} ║");
Console.WriteLine('╚' + new string('═', headerText.Length + 2) + '╝');
}
With these helper methods, we can then write code like:
private static void Main()
{
var chrRaster = GetInitialArray();
WriteHeader("Before");
PrintArrayToConsole(chrRaster);
ExposeDotNeighbors(chrRaster);
WriteHeader("After");
PrintArrayToConsole(chrRaster);
GetKeyFromUser("\nDone! Press any key to exit...");
}
And out output would look like:
I noticed that you also appear to be getting the values from the user, and using try/catch blocks to validate the input. A better approach might be to write a helper method that takes in a string that represents the "prompt" to the user, and a validation method that can be used to validate the input. With this, we can keep asking the user for input until they enter something valid.
Below are methods that get an integer and a character from the user, and allow the caller to pass in a function that can be used for validation. These methods will not return until the user enters valid input:
private static char GetCharFromUser(string prompt, Func<char, bool> validator = null)
{
char result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
result = Console.ReadKey().KeyChar;
} while (!(validator?.Invoke(result) ?? true));
Console.WriteLine();
return result;
}
private static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
int result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
} while (!int.TryParse(Console.ReadLine(), out result) ||
!(validator?.Invoke(result) ?? true));
return result;
}
private static void ClearSpecificLineAndWrite(int cursorTop, string message)
{
Console.SetCursorPosition(0, cursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, cursorTop);
Console.Write(message);
}
We can then re-write our GetInitialArray method to use these methods to get the dimensions and values from the user:
private static char[,] GetInitialArray()
{
const int maxCols = 20;
const int maxRows = 20;
var numCols = GetIntFromUser(
$"How many columns do you want (1 - {maxCols}): ",
i => i > 0 && i <= maxCols);
var numRows = GetIntFromUser(
$"How many rows do you want (1 - {maxRows}): ",
i => i > 0 && i <= maxRows);
var initialArray = new char[numRows, numCols];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
initialArray[row, col] = GetCharFromUser(
$"Enter value for [{row}, {col}] ('.' or '*'): ",
c => c == '.' || c == '*');
}
}
return initialArray;
}
And now our output might look like this:
If you try it, notice that you cannot enter an illegal value. The program just waits for you to read the instructions and enter a valid number or character. :)
Here is the algorithm that does what you want. I have tried to explain my code in the comments. The output will match what you're looking for.
static void Main(string[] args)
{
char STAR = '*';
char DOT = '.';
var input = new char[,]
{
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,DOT,STAR,STAR},
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,STAR,STAR,DOT}
};
var output = new char[4, 5];
// Copy each from input to output, checking if it touches a '.'
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 5; y ++)
{
if (input[x, y] == STAR)
{
var isDot = false;
// Check left
if (x > 0)
isDot = input[x - 1, y] == DOT;
// Check right
if (x < 3)
isDot = isDot || (input[x + 1, y] == DOT);
// Check above
if (y > 0)
isDot = isDot || (input[x, y - 1] == DOT);
// Check below
if (y < 4)
isDot = isDot || (input[x, y + 1]) == DOT;
output[x, y] = isDot ? DOT : STAR;
}
else
{
output[x, y] = input[x, y];
}
}
}
// Print output
for (int x = 0; x < 4; x ++)
{
for (int y = 0; y < 5; y ++)
{
Console.Write(output[x, y]);
}
Console.WriteLine();
}
Console.Read();
}
You can go like this :
using System;
public class chars
{
public static void Main(string[] args)
{
char[,] charArray = new char[,] {{'*','*','*','*','*'},
{'*','*','.','*','*'},
{'*','*','*','*','*'},
{'*','*','*','*','.'}};
int[,] holdIndex = new int[4, 5];
for(int i = 0; i<4; i++) // get allindexes containing '.'
{
for(int j = 0; j<5; j++)
{
if(charArray[i,j] == '.')
holdIndex[i,j] = 1;
else
holdIndex[i,j] = 0;
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
if(holdIndex[i,j] == 1)
{
if(i!=0)
charArray[i-1,j] = '.'; //up
if(j!=0)
charArray[i,j-1] = '.'; // left
if(j!=4)
charArray[i,j+1] = '.'; //right
if(i!=3)
charArray[i+1,j] = '.'; //down
}
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
Console.Write(charArray[i,j]);
}
Console.WriteLine();
}
Console.Read();
}
}
iam try to write min max algorithm for connect4 game but when i run this code it go in infinte loop and not return move or result, so i want a help to know what is wrong with it , i work in board of 6*7 cells
private int score()
{
int x = check_Winner();//i checked it and it work right ot return 1 if player 1 win or 2 if pc win or 0 in tie
if (x == 1) return 10;
else if (x == 2) return -10;
else return 0;
}
public int MinMax(int player_num)
{
List<pair> possiple_moves = get_possible_moves();// it works will
int score_so_far = score();
if (possiple_moves.Count == 0 || score_so_far != 0)
return score_so_far;
List<int> scores = new List<int>();
List<pair> moves = new List<pair>();
foreach (pair move in possiple_moves)
{
if (player_num == 1)
{
cells[move.x, move.y].player_num = 1;
scores.Add(MinMax(2));
}
else
{
cells[move.x, move.y].player_num = 2;
scores.Add(MinMax(1));
}
moves.Add(move);
cells[move.x, move.y].player_num = 0;
}
if (player_num == 1)
{
int max_score_indx = 0, tmp = int.MinValue;
for (int i = 0; i < scores.Count; i++)
{
if (scores[i] > tmp)
{
tmp = scores[i];
max_score_indx = i;
}
}
pc_choise = moves[max_score_indx];
return scores[max_score_indx];
}
//==================
else
{
int min_score_indx = 0, tmp = int.MaxValue;
for (int i = 0; i < scores.Count; i++)
{
if (scores[i] < tmp)
{
tmp = scores[i];
min_score_indx = i;
}
}
pc_choise = moves[min_score_indx];
return scores[min_score_indx];
}
}
#Equalsk is right, I believe: you are calling MinMax from within the foreach loop, before you reach the code that evaluates the stop conditions. So providing that the method get_possible_moves returns something different to Null, you will get stuck in foreach --> MinMax --> foreach --> MinMax --> foreach...
I'm having an issue with my Connect R program. I can have it play playervsplayer just fine but, there is something wrong wit my MinMax that I don't understand. I pass in my 2D array into the algorithm in order to traverse it and have the PlaceT algorithm in my MinMax to add into a temporary 2D array for when I recursively call the MinMax. For some reason it actually adds it to my main 2Darray so by the time the function ends its filled up when I only wanted one item to be added. I included both the PlaceT function as well as the MinMax. I also did include a picture for reference
The idea is to traverse through the 2D array from the bottom and if there is a blank space than add to a temp 2D array than recall the Max recursively, and it does this till the traversal ends. then it takes all the added moves and sees which one has the most score than returns that to the main MinMax which is supposed to be used to place the tile where its supposed to go. Let me know if you want to see any of the other code outside of those algorithms.
static void PlaceT(int ogC, int ogR, int c, int r, string[,] board, string id)
{
if (id == "R")
{
if(r - 1 >= 0)
{
if (board[r - 1, c] == "R" || board[r - 1, c] == "B")
{
PlaceT(ogC, ogR, c, r - 1, board, id);
}
else
{
board[r - 1, c] = "R";
}
}
}
else if (id == "B")
{
if(r - 1 >= 0)
{
if (board[r - 1, c] == "B" || board[r - 1, c] == "R")
{
PlaceT(ogC, ogR, c, r - 1, board, id);
}
else
{
board[r - 1, c] = "B";
}
}
}
}
static void MinMax(string [,] board, int row, int col, string ID, int count, string otherID, bool isComp)
{
string[,] tempB = board;
AIMove bestmove = new AIMove();
bestmove.x = MaxMove(tempB, row, col, ID, count, otherID, isComp).x;
PlaceT(col, row, bestmove.x, row, board, ID);
return;
}
static AIMove MaxMove(string[,] board, int row, int col, string ID, int count, string otherID, bool isComp)
{
AIMove move = new AIMove();
string[,] grid = new string[row,col];
grid = board;
if (isFull(grid))
{
move.score = 0;
return move;
}
else if(rInRow(grid, count, row, col, ID) == 10)
{
move.score = 10;
return move;
}
else if(rInRow(grid, count, row, col, otherID) == 10)
{
move.score = -10;
return move;
}
List<AIMove> moves = new List<AIMove>();
for (int y = row - 1; y >= 0; y--)
{
for (int x = col - 1; x >= 0; x--)
{
if (grid[y, x] != "R" && grid[y, x] != "B")
{
move.x = x;
move.y = y;
if(isComp)
{
PlaceT(col, row, move.x, row, grid, ID);
isComp = !isComp;
move.score = MaxMove(grid, row, col, ID, count, otherID, isComp).score;
}
else
{
PlaceT(col, row, move.x, row, grid, otherID);
isComp = !isComp;
move.score = MaxMove(grid, row, col, ID, count, otherID, isComp).score;
}
moves.Add(move);
}
}
}
grid = board;
int _best = 0;
if(isComp)
{
int _bestScore = -100;
for (int i = 0; i < moves.Count; i++)
{
if (moves[i].score > _best)
{
_best = i;
_bestScore = moves[i].score;
}
}
}
else
{
int _bestScore = 100;
for (int i = 0; i < moves.Count; i++)
{
if (moves[i].score < _best)
{
_best = i;
_bestScore = moves[i].score;
}
}
}
return moves[_best];
}
Image of Program running
This has been bugging me for a few hours so I was wondering if anyone could help me out as I might be thinking about this the wrong way.
I want to be able to get a boolean value from a set of x and y coordinates on an grid with an infinite width and height. There are also other constraints, along the x axis there needs to be at least n places between two true values, I would also need to know the number of true values in the area from 0,0 to x,y.
The width and height of the area given to getTrueCoordinatesInArea is equal to x and y as its the area is created from 0,0 to x,y
If that makes sense..
So for example:
value = coordinateContainsTrue( x, y );//return true or false.
total = getTrueCoordinatesInArea( x , y );//Returns the total true values inside the area.
Edit: This would work off a seed.
I don't understand exacly what you need but I thought it sounded like a good and fun exercise. I hoped it's what you wanted. =) It's not coded exactly how I wanted. Would rather have used a bool[,] array but don't know how to make that one dynamic and didn't want to code my own class for this, but maybe I should have.
However, this solution should work.
private List<List<bool>> grid = new List<List<bool>>();
private int N = 4;
Random randomNumberGenerator = new Random();
private bool getRandomBoolean()
{
return this.randomNumberGenerator.Next(0, 2) == 1;
}
private void testProgram()
{
var containsTrue = coordinateContainsTrue(0, 10);
var total = getTrueCoordinatesInArea(14, 2);
var isTrue = coordinateIsTrue(15, 11);
}
private bool coordinateIsTrue(int x, int y)
{
expandGridOfNeeded(x, y);
return grid[x][y];
}
private bool coordinateContainsTrue(int x, int y)
{
expandGridOfNeeded(x, y);
for (int xTemp = 0; xTemp < x; xTemp++) // Loop columns
{
for (int yTemp = 0; yTemp < y; yTemp++) // Loop rows
{
if (grid[xTemp][yTemp])
return true; // Return true if any true was found
}
}
return false;
}
private int getTrueCoordinatesInArea(int x, int y)
{
expandGridOfNeeded(x, y);
var total = 0;
for (int xTemp = 0; xTemp < x; xTemp++) // Loop columns
{
for (int yTemp = 0; yTemp < y; yTemp++) // Loop rows
{
if (grid[xTemp][yTemp])
total++; // Increase count if true was found
}
}
return total;
}
private void expandGridOfNeeded(int x, int y)
{
if (x < 0 || y < 0)
return;
// Add needed columns
while (grid.Count <= x)
{
var column = new List<bool>();
// Only add rows if the others have rows
if (grid.Count > 0)
{
while (column.Count < grid[0].Count)
{
// Check if legal to add a true value, if it is then add random else add false
bool forceFalseValue = false;
for (int i = grid.Count - 1; i > grid.Count + N && forceFalseValue == false; i--)
{
forceFalseValue = grid[i][column.Count - 1];
}
column.Add(forceFalseValue ? false : getRandomBoolean());
}
}
grid.Add(column);
}
// Add needed rows
while (grid[0].Count <= y)
{
var counter = N;
foreach (var column in grid)
{
// Check if legal to add a true value, if it is then add random else add false
if (counter < N)
{
column.Add(false);
counter++;
}
else
{
var randomValue = getRandomBoolean();
if (randomValue)
counter = 0;
else
counter++;
column.Add(randomValue);
}
}
}
}
I'm working on an algorithm to find a set of non intersected paths in a grid for a
given pairs of points..
Like this for these pairs:
(9,4) and (12,13)
The output should be something like this:
9,10,11,7,3,4
13,14,15,16,12
and print "Blocked" if it can't route all paths
First I searched for an already made algorithm to find all simple paths between 2
points in a graph or a grid. and I found this one by #Casey Watson and #svick here..
It works really well but for small graphs only.
I converted it to C#.NET and enhanced it a little bit to be able to find paths of
maximum length X. and build on it my total algorithm.
The one I built works fine in small graphs..
Here is routes 9 pairs in a 8x8 grid..
but it takes a huge time in larger ones like the 16x16 or even the final one I intended to do which is a 3D model of 16x16x2
Like this
The algorithm was developed to be a depth first search RECURSIVE algorithm, but it
took a huge time to return value to the user. so I decided to convert it to loops instead of the recursive calls so that I can benefit from yield return feature in .NET
but still it didn't help any better.
The loops version of the algorithm find a route for a pair of points in less than a second but the recursive one took more than 90 seconds.
when I tried with 2 pairs, the loops version took around 342 seconds but the recursive one took around 200..
So I can't know which is faster..!? the recursive or the loops one..
I really want to know the best way to do this..
Note : the first digit in the number of the node determine the layer (Starts at 1)..
Here is the code
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace AlgorithmTest
{
struct Connection
{
public int FirstNode;
public int SecondNode;
public Connection(int N1,int N2)
{
FirstNode = N1;
SecondNode = N2;
}
}
enum Algorithm
{ Recursion, Loops }
public class Search
{
private const int MAX = 15;
private const int Width = 16;
private const int Length = 16;
private const int Height = 2;
private static void Main(string[] args)
{
var graph = new Graph();
var str = new int[Height,Length, Width];
var level = ((int)Math.Pow(10, (Length * Width).ToString().Length) >= 100) ? (int)Math.Pow(10, (Length * Width).ToString().Length) : 100;
for (var i = 0; i < Height; i++)
{
int num = 0;
for (var j = 0; j < Length; j++)
for (var k = 0; k < Width; k++)
{
str[i, j, k] = ++num + level;
}
level += level;
}
for (var i = 0; i < Height; i++)
{
for (var j = 0; j < Length; j++)
{
for (var k = 0; k < Width; k++)
{
if (i < Height - 1) graph.addEdge(str[i, j, k], str[i + 1, j, k]);
if (i > 0) graph.addEdge(str[i, j, k], str[i - 1, j, k]);
if (k < Width - 1) graph.addEdge(str[i, j, k], str[i, j, k + 1]);
if (k > 0) graph.addEdge(str[i, j, k], str[i, j, k - 1]);
if (j < Length - 1) graph.addEdge(str[i, j, k], str[i, j + 1, k]);
if (j > 0) graph.addEdge(str[i, j, k], str[i, j - 1, k]);
}
}
}
var wt = new Stopwatch();
wt.Start();
var connectedNodes = new List<Connection>()
{
new Connection(1030, 1005),
// new Connection(1002, 1044),
// new Connection(1015, 1064),
// new Connection(1041, 1038),
// new Connection(1009, 1027),
// new Connection(1025, 1018),
// new Connection(1037, 1054),
// new Connection(1049, 1060),
// new Connection(1008, 1031),
// new Connection(1001, 1035),
};
wt.Start();
Console.WriteLine("Using Loops:");
Console.WriteLine();
var allPaths = new Search().FindAllPaths(connectedNodes, graph, MAX, Algorithm.Loops);
wt.Stop();
foreach (var path in allPaths)
{
PrintPath(path);
}
Console.WriteLine("Total Seconds: " + wt.Elapsed.TotalSeconds + ", Number of paths: " + allPaths.Count());
Console.WriteLine("***************************************************************************************************");
Console.WriteLine("Using Recursion:");
Console.WriteLine();
wt.Reset();
wt.Start();
allPaths = new Search().FindAllPaths(connectedNodes, graph, MAX, Algorithm.Recursion);
wt.Stop();
foreach (var path in allPaths)
{
PrintPath(path);
}
Console.WriteLine("Total Seconds: " + wt.Elapsed.TotalSeconds + ", Number of paths: " + allPaths.Count());
Console.WriteLine();
}
private IEnumerable<List<int>> FindAllPaths(List<Connection> connectedNodes, Graph graph, int max, Algorithm algorithm)
{
var paths=new Stack<List<int>>();
var blocked=new List<int>();
for (var i = 0; i < connectedNodes.Count; i++)
{
if (!blocked.Contains(connectedNodes[i].FirstNode)) blocked.Add(connectedNodes[i].FirstNode);
if (!blocked.Contains(connectedNodes[i].SecondNode)) blocked.Add(connectedNodes[i].SecondNode);
}
if (algorithm == Algorithm.Recursion)
{
if (FindAllPaths(connectedNodes, 0, max, graph, paths, blocked))
{
Console.WriteLine("BLOCKED");
return new List<List<int>>();
}
}
else if(algorithm==Algorithm.Loops)
{
if (!FindAllPaths2(connectedNodes, 0, max, graph, paths, blocked))
{
Console.WriteLine("BLOCKED");
return new List<List<int>>();
}
}
return paths;
}
private static bool FindAllPaths(List<Connection> connectedNodes,int order,int max, Graph graph, Stack<List<int>> allPaths, List<int> blocked)
{
if (order >= connectedNodes.Count) return false;
var paths = SearchForPaths(graph, connectedNodes[order].FirstNode, connectedNodes[order].SecondNode, max, blocked);
if (paths.Count == 0) return true;
int i;
for (i = 0; i < paths.Count; i++)
{
var path = paths[i];
allPaths.Push(path);
blocked.AddRange(path);
if (!FindAllPaths(connectedNodes, order + 1,max, graph, allPaths, blocked)) break;
allPaths.Pop();
foreach (var j in path)
{
blocked.RemoveAll(num => num==j);
}
paths.RemoveAll(list => IsListsSimilar(list,path));
i--;
}
if (i == paths.Count) return true;
return false;
}
private static bool IsListsSimilar(List<int> L1,List<int> L2)
{
if (L2.Count > L1.Count) return false;
for (int i = 0; i < L2.Count - 1; i++)
{
if (L1[i] != L2[i]) return false;
}
return true;
}
private static List<List<int>> SearchForPaths(Graph graph, int start, int end, int max, List<int> blocked)
{
blocked.Remove(start);
blocked.Remove(end);
var nodePaths = new List<List<int>>();
var visited = new LinkedList<int>();
visited.AddLast(start);
DepthFirstSearch(graph, visited, end, max, blocked, nodePaths);
nodePaths = nodePaths.OrderBy(list => list.Count).ToList();
return nodePaths;
}
private static void DepthFirstSearch(Graph graph, LinkedList<int> visited, int end, int max, List<int> blocked, List<List<int>> paths)
{
var nodes = graph.adjacentNodes(visited.Last.Value);
// examine adjacent nodes
var nodeCount = blocked.Count;
for (int i = 0; i < nodeCount; i++)
{
if (visited.Contains(blocked[i])) return;
}
if (visited.Count > max) return;
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] != end) continue;
visited.AddLast(nodes[i]);
{
paths.Add(new List<int>(visited));
}
visited.RemoveLast();
break;
}
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] == end) continue;
visited.AddLast(nodes[i]);
DepthFirstSearch(graph, visited, end, max, blocked, paths);
visited.RemoveLast();
}
}
private static bool FindAllPaths2(List<Connection> connectedNodes, int order, int max, Graph graph, Stack<List<int>> allPaths, List<int> blocked)
{
if (order >= connectedNodes.Count) return false;
foreach (var path in SearchForPaths2(graph, connectedNodes[order].FirstNode, connectedNodes[order].SecondNode, max, blocked))
{
allPaths.Push(path);
blocked.AddRange(path);
if (!FindAllPaths2(connectedNodes, order + 1, max, graph, allPaths, blocked)) break;
allPaths.Pop();
foreach (var j in path)
{
blocked.RemoveAll(num => num == j);
}
}
return true;
}
private static IEnumerable<List<int>> SearchForPaths2(Graph graph, int start, int end, int max, List<int> blocked)
{
blocked.Remove(start);
blocked.Remove(end);
var visited = new LinkedList<int>();
visited.AddLast(start);
foreach (var VARIABLE in DepthFirstSearch(graph, visited, end, max, blocked))
{
yield return VARIABLE;
}
}
private static IEnumerable<List<int>> DepthFirstSearch(Graph graph, LinkedList<int> visited, int end, int max, List<int> blocked)
{
var nodes = graph.adjacentNodes(visited.Last.Value);
var nodeCount = blocked.Count;
for (int i = 0; i < nodeCount; i++)
{
if (visited.Contains(blocked[i])) yield break;
}
if (visited.Count > max) yield break;
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] != end) continue;
visited.AddLast(nodes[i]);
yield return (new List<int>(visited));
visited.RemoveLast();
break;
}
nodeCount = nodes.Count;
for (var i = 0; i < nodeCount; i++)
{
if (visited.Contains(nodes[i]) || nodes[i] == end) continue;
visited.AddLast(nodes[i]);
foreach (var P in DepthFirstSearch(graph, visited, end, max, blocked))
{
yield return P;
}
visited.RemoveLast();
}
}
private static void PrintPath(List<int> visited)
{
for (int i = 0; i < visited.Count()-1; i++)
{
Console.Write(visited[i]);
Console.Write(" --> ");
}
Console.Write(visited[visited.Count() - 1]);
Console.WriteLine();
Console.WriteLine();
}
}
public class Graph
{
private readonly Dictionary<int, HashSet<int>> map = new Dictionary<int, HashSet<int>>();
public void addEdge(int node1, int node2)
{
HashSet<int> adjacent = null;
map.TryGetValue(node1, out adjacent);
if (adjacent == null)
{
adjacent = new HashSet<int>();
map.Add(node1, adjacent);
}
adjacent.Add(node2);
}
public List<int> adjacentNodes(int last)
{
HashSet<int> adjacent = null;
map.TryGetValue(last, out adjacent);
if (adjacent == null)
{
return new List<int>();
}
return new List<int>(adjacent);
}
}
}
I think the answer lies in how you have numbered the nodes in your grid. For a simple 2-dimensional grid, 4 nodes by 4, you would number them : 00, 01, 02, 03, 10, 11, 12 ... 30, 31, 32, 33. Think of them as composite number strings (not decimal values) acting as dimension-based node addresses.
In a 3-dimensional grid, they would be numbered 000, 001, 002, etc. up to 330, 331, 332, 333.
If you want to find all routes between two points 10 and 22 you can quickly calculate their distance by adding the dimensional differences: 1y is one away from 2y, and x0 is two away from x2. Therefore the node distance is 3, you will need to travel over 3 edges (connecting 4 nodes in total) to reach the destination.
The solution space (the only nodes that could ever be involved in a solution route) can be enumerated by creating a set of embedded FOR/NEXT loops, one for each dimension. In this case, the start and end values of 10 and 22 would produce: 10, 11, 12, 20, 21 and 22.
Now comes the clever bit. You can precompute (prepare) a table of 'forwarding' connections between the nodes in your array. Node 10 connects to 20 and 11 (both 1 dimensional difference away). From that you can generate a sequence of valid pathways from 10 to 22 by adding one to a dimension difference in which ever direction you plan to move (in a 2-D array you only get to choose one of two ways. In 3-D you get three choices).
Each answer should be the shortest possible distance. The computation time for this approach should be milliseconds. On a steam powered ZX81!