I made a maze game in a console application and by using keys I can control character to leave the maze. Now I want to figure out how to automate that process So that my character can go by random directions and try to find the way out. Here is my class.
The problem is in the randomMovement Method.
class Player: Maze
{
public int x = 1;
public int y = 1;
public string playerName;
public static void printMv() {
while (true)
{
for (int i = 0; i < 15; i++)
{
Console.Clear();
mazeDev();
Console.Write("0");
Thread.Sleep(1000);
}
}
}
public static void movementByUser()
{
int x = 1, y = 1;
while (true)
{
Console.Clear();
mazeDev();
Console.CursorLeft = x;
Console.CursorTop = y;
Console.Write("0");
ConsoleKeyInfo mv = Console.ReadKey();
if (mv.Key == ConsoleKey.Escape) break;
if (mv.Key == ConsoleKey.A && mazeBluePrint[y, x - 1] == 0) {
x--;
}
if (mv.Key == ConsoleKey.D && mazeBluePrint[y, x + 1] == 0)
{
x++;
}
if (mv.Key == ConsoleKey.W && mazeBluePrint[y - 1, x] == 0)
{
y--;
}
if (mv.Key == ConsoleKey.S && mazeBluePrint[y + 1, x] == 0)
{
y++;
}
}
}
public static void randomMovement()
{
Random randMove = new Random();
int x = 1;
int y = 1;
int irandom = randMove.Next(4);
Console.CursorLeft = x;
Console.CursorTop = y;
if (irandom == mazeBluePrint[y, x - 1])
{
x--;
printMv();
}
else if (irandom == mazeBluePrint[y, x + 1])
{
x++;
printMv();
}
else if (irandom == mazeBluePrint[y - 1, x])
{
y--;
printMv();
}
else
{
y++;
printMv();
}
}
}
}
Your problem probably is the direction evaluation. Try this:
public static void randomMovement()
{
Random randMove = new Random();
int x = 1;
int y = 1;
int irandom = randMove.Next(4);
Console.CursorLeft = x;
Console.CursorTop = y;
if (irandom == 0 && mazeBluePrint[y, x - 1] == 0)
{
x--;
printMv();
}
else if (irandom == 1 && mazeBluePrint[y, x + 1] == 0)
{
x++;
printMv();
}
else if (irandom == 2 && mazeBluePrint[y - 1, x] == 0)
{
y--;
printMv();
}
else if (mazeBluePrint [y + 1, x] == 0)
{
y++;
printMv();
}
}
However, this code still has a lot of weaknesses (e.g. you could walk out of the boundaries of the mazeBluePrint array, which would result in an exception).
EDIT
If you want to move in the other direction if the first didn't work, you could try something like this:
public static void randomMovement()
{
Random randMove = new Random();
int x = 1;
int y = 1;
Console.CursorLeft = x;
Console.CursorTop = y;
while (true)
{
int irandom = randMove.Next(4);
if (irandom == 0 && mazeBluePrint[y, x - 1] == 0)
{
x--;
printMv();
break;
}
else if (irandom == 1 && mazeBluePrint[y, x + 1] == 0)
{
x++;
printMv();
break;
}
else if (irandom == 2 && mazeBluePrint[y - 1, x] == 0)
{
y--;
printMv();
break;
}
else if (mazeBluePrint[y + 1, x] == 0)
{
y++;
printMv();
break;
}
}
}
However, this only moves one time, beginning from 1,1.
Related
my program is
using System;
namespace MatrixCount
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter Number Of Rows and colums!");
int Row = Convert.ToInt32(Console.ReadLine());
int Colum = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Number of shiftings!");
int shift = Convert.ToInt32(Console.ReadLine());
int TotalCells = Row * Colum;
string direction = "right"; //Assigining initigal direction is right//
int[,] matrix = new int[Row,Colum];
int value1=1; //For the coOrdinate(1,2) value2=2 and value1=1//
int value2=1;
bool Flag = true;
if (shift > TotalCells)
{
Console.WriteLine("Invalid shiftings!");
}
else
{
for (int i = 1; i <= shift; i++)
{
if (direction == "right" && (i > Colum))
{
direction = "down";
value1++;
}
if (direction == "down" && (Row <i))
{
direction = "left";
value2--;
}
if (direction == "left" && (Colum < 1))
{
direction = "up";
value1--;
}
if (direction == "up" && (Row ==1))
{
direction = "right";
Colum--;
Colum--;
Row--;
Row--;
}
if (direction == "right" && Flag == false)
{
value2++;
}
if (direction == "down")
{
value1++;
}
if (direction == "left")
{
value2--;
}
if (direction == "up")
{
value1--;
}
if (direction == "right")
{
Flag = false;
}
}
}
Console.Write((value1, value2));
}
}
}
if i understand the objective correctly, something like this mayhaps?
using System;
namespace MatrixCount
{
class Program
{
enum Directions { Right, Up, Left, Down }
static void Main()
{
do
{
Console.WriteLine("Enter Number Of Rows and Colums!");
uint Rows = uint.Parse(Console.ReadLine());
uint Colums = uint.Parse(Console.ReadLine());
uint TotalCells = Rows * Colums;
uint Shifts;
bool InvalidInput;
do
{
Console.WriteLine("Enter Number of Shiftings!");
Shifts = uint.Parse(Console.ReadLine());
InvalidInput = Shifts > TotalCells;
if (InvalidInput)
{
Console.WriteLine("Invalid shiftings!");
}
} while (InvalidInput);
Directions Direction = Directions.Right;
int R = 0;
int C = 0;
uint BoundaryLeft = 0;
uint BoundaryBottom = Rows - 1;
uint BoundaryRight = Colums - 1;
uint BoundaryTop = 0;
for (int i = 0; i < Shifts; i++)
{
bool Shifted = false;
while (!Shifted)
{
switch (Direction)
{
case Directions.Right:
if (C + 1 > BoundaryRight)
Direction = Directions.Down;
else
{
C++;
Shifted = true;
}
break;
case Directions.Down:
if (R + 1 > BoundaryBottom)
Direction = Directions.Left;
else
{
R++;
Shifted = true;
}
break;
case Directions.Left:
if (C - 1 < BoundaryLeft)
Direction = Directions.Up;
else
{
C--;
Shifted = true;
}
break;
case Directions.Up:
if (R - 2 < BoundaryTop)
{
Direction = Directions.Right;
BoundaryLeft++;
BoundaryBottom--;
BoundaryRight--;
BoundaryTop++;
}
else
{
R--;
Shifted = true;
}
break;
}
}
}
Console.WriteLine("You end up at ({0}, {1})!", R, C);// add 1 to r and c if you want to be a mathematician
Console.WriteLine("Again?");
}
while (Console.ReadLine().ToUpper() == "YES");
}
}
}
I tried to make a function that finds the fastest route to the end of the array by making a recursion that chooses its path by first availability. for some reason, the recursion doesn't stop when it returns true. why?
static void Main(string[] args)
{
int[,] arr = new int[5, 5];
arr[0, 0] = 2;
if (PathFinder(arr, 0, 0))
{
printarr(arr);
}
}
static bool PathFinder(int[,] arr, int y,int x)
{
if (arr[arr.GetLength(0) - 1, arr.GetLength(1) - 1] == 2)
{
return true;
}
else
{
/////Right
if (x != arr.GetLength(1) - 1 && arr[y, x + 1] != 2 && arr[y, x + 1] == 0)
{
arr[y, x + 1] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y, x + 1);
}
/////Down
if (y != arr.GetLength(0) - 1 && arr[y + 1, x] != 2 && arr[y + 1, x] == 0)
{
arr[y + 1, x] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y + 1, x);
}
/////UP
if (y!=0 && arr[y-1,x]!=2 && arr[y - 1, x] == 0)
{
arr[y - 1, x] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr,y-1,x);
}
/////Left
if (x != 0 && arr[y, x-1] != 2 && arr[y, x - 1] == 0)
{
arr[y, x - 1] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y, x - 1);
}
return false;
}
}
static void printarr(int[,] arr)
{
for (int row = 0; row < arr.GetLength(0); row++)
{
for (int colom = 0; colom < arr.GetLength(1); colom++)
{
Console.Write(arr[row, colom] + " ");
}
Console.WriteLine("");
}
}
If you call a method that has a return type recursively without storing that return value, it will proceed after the call. You have called it by name PathFinder(... so when true is returned your recursive call doesn't pass it on. Change your code like this:
static bool PathFinder(int[,] arr, int y, int x)
{
if (arr[arr.GetLength(0) - 1, arr.GetLength(1) - 1] == 2)
{
return true;
}
else
{
/////Right
if (x != arr.GetLength(1) - 1 && arr[y, x + 1] != 2 && arr[y, x + 1] == 0)
{
arr[y, x + 1] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y, x + 1);
}
/////Down
if (y != arr.GetLength(0) - 1 && arr[y + 1, x] != 2 && arr[y + 1, x] == 0)
{
arr[y + 1, x] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y + 1, x);
}
/////UP
if (y != 0 && arr[y - 1, x] != 2 && arr[y - 1, x] == 0)
{
arr[y - 1, x] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y - 1, x);
}
/////Left
if (x != 0 && arr[y, x - 1] != 2 && arr[y, x - 1] == 0)
{
arr[y, x - 1] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y, x - 1);
}
return false;
}
}
This way, when you hit return true;, that value will be passed along all the way back the call stack and you won't continue processing until your return false;
Recursive calls to methods without a return type should have a return; statement somewhere so they can escape otherwise you'll hit a StackOverflowException.
My code generates characters 'L' into 2D-Array on random place, but I need program to check if there isn't 'L' already and if it is there, program should go through process of generation again. But there comes the problem, because Stackoverflowexception shows up. Does anybody have an idea how to change my code, or how to increase stack size?
(I have to mention, that I already tried increase stack size using Project Properties, but I don't have there Linker option. And also I'm new to programming, so I don't know how to use editbin or commands). Thanks in advance.
EDIT:
public void Generate()
{
Fill();
Fleet();
}
public void Fleet()
{
Ship2(Utility.R(1,9),Utility.R(1,9),Utility.R(4));
Ship3(Utility.R(1,9),Utility.R(1,9),Utility.R(4));
Ship3(Utility.R(1,9),Utility.R(1,9),Utility.R(4));
Ship4(Utility.R(1,9),Utility.R(1,9),Utility.R(4));
Ship5(Utility.R(1,9),Utility.R(1,9),Utility.R(4));
}
public void Ship2(int x, int y, int r)
{
if (r == 0)
{
CreateShip(x, y);
CreateShip(x, (y + 1));
}
if (r == 1)
{
CreateShip(x, y);
CreateShip(x, (y + -1));
}
if (r == 2)
{
CreateShip(x, y);
CreateShip((x-1), (y));
}
if (r == 3)
{
CreateShip(x, y);
CreateShip((x+1), (y));
}
}
public void CreateShip(int x, int y)
{
if (x <= 9 && y <= 9 && x >= 0 && y >= 0)
{
if (Board[x, y] == 'L')
{
Generate();
}
else
{
Board[x, y] = 'L';
}
}
else
{
Generate();
}
}
This is the important part of code.
What you can do is: If Creation fails pass back a bool and try again from scratch.
public void Generate()
{
Fill();
while(!Fleet())
{
// I assume Fill clears your board again?!
Fill();
}
}
public bool Fleet()
{
return Ship2(Utility.R(1,9),Utility.R(1,9),Utility.R(4)) &&
Ship3(Utility.R(1,9),Utility.R(1,9),Utility.R(4)) &&
Ship3(Utility.R(1,9),Utility.R(1,9),Utility.R(4)) &&
Ship4(Utility.R(1,9),Utility.R(1,9),Utility.R(4)) &&
Ship5(Utility.R(1,9),Utility.R(1,9),Utility.R(4));
}
public bool Ship2(int x, int y, int r)
{
if (r == 0)
{
return CreateShip(x, y) &&
CreateShip(x, (y + 1));
}
if (r == 1)
{
return CreateShip(x, y) &&
CreateShip(x, (y + -1));
}
if (r == 2)
{
return CreateShip(x, y) &&
CreateShip((x-1), (y));
}
if (r == 3)
{
return CreateShip(x, y) &&
CreateShip((x+1), (y));
}
return false;
}
public bool CreateShip(int x, int y)
{
if (x <= 9 && y <= 9 && x >= 0 && y >= 0)
{
if (Board[x, y] == 'L')
{
return false;
}
else
{
Board[x, y] = 'L';
}
}
else
{
return false;
}
return true;
}
Note: This will still not work, if the input parameters to CreateShip never change. You will now not see any Exception but the Generate method will never finish.
I am writing a game of minesweeper. Below is code for 3 methods in minesweeper. The first method is to check all the spaces around the button pressed and to count how many bombs are around it. The next method is to be called recursively, in order that if the user pressed a button with 0 buttons around it, it will open all of the squares that also indicate 0 squares around it. The third method is to check that it will be in bound the check. The empty space recursive call is getting me a stackoverflow error, what am I doing wrong?
Thanks!
private int GameLogicChecker(int x, int y)
{
int count = 0;
if (_grid[x, y] != -1)
{
if (x + 1 < SizeX)
{ //Right
if (_grid[x + 1, y] == -1)
count++;
}
if (x - 1 > 0)
{ //Left
if (_grid[x - 1, y] == -1)
count++;
}
if (y + 1 < SizeY)
{ //Upper
if (_grid[x, y + 1] == -1)
count++;
}
if (y - 1 > 0)
{ //Lower
if (_grid[x, y - 1] == -1)
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY)
{ //Right-Upper
if (_grid[x + 1, y + 1] == -1)
count++;
}
if (x + 1 < SizeX && y - 1 > 0)
{ //Right-Lower
if (_grid[x + 1, y - 1] == -1)
count++;
}
if (x - 1 > 0 && y + 1 < SizeY)
{ //Left-Upper
if (_grid[x - 1, y + 1] == -1)
count++;
}
if (x - 1 > 0 && y - 1 > 0)
{ //Left-Lower
if (_grid[x - 1, y - 1] == -1)
count++;
}
}
return count;
}
void OpenEmptySpace(int x, int y)
{
for (var k = -1; k <= 1; k++)
{
for (var l = -1; l <= 1; l++)
{
if (CheckBounds(x + k, y + l) && GameLogicChecker(x + k, y + l) == 0)
{
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
}
}
}
private bool CheckBounds(int x, int y)
{
return x >= 0 && x < SizeX && y >= 0 && y < SizeY;
}
For k = 0 and l = 0, you are calling yourself again and again and again...
Thanks to #BenVoigt for pointing out that two zeroes adjacent to each other will also lead to infinite recursion. So, in order to solve that one method is to create a boolean grid too and set a particular cell's value to true if it has been run through once. Assuming the grid is called Explored, I've added the condition for it in the code below.
If you insist on your current code, try changing the condition to:
if (CheckBounds(x + k, y + l)
&& GameLogicChecker(x + k, y + l) == 0
&& !(k == 0 && l == 0)
&& !Explored[x + k, y + l])
{
Explored[x + k, y + l] = true;
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
Here is another answer for you, rewriting your methods one-by-one following better coding practices. Like in the other answer, a boolean grid called Explored[SizeX, SizeY] has been assumed.
1. GameLogicChecker()
private int GameLogicChecker(int x, int y)
{
if (_grid[x, y] == -1) return 0;
int count = 0;
if (x + 1 < SizeX && _grid[x + 1, y] == -1) //Right
{
count++;
}
if (x - 1 > 0 && _grid[x - 1, y] == -1) //Left
{
count++;
}
if (y + 1 < SizeY && _grid[x, y + 1] == -1) //Upper
{
count++;
}
if (y - 1 > 0 && _grid[x, y - 1] == -1) //Lower
{
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY && _grid[x + 1, y + 1] == -1) //Right-Upper
{
count++;
}
if (x + 1 < SizeX && y - 1 > 0 && _grid[x + 1, y - 1] == -1) //Right-Lower
{
count++;
}
if (x - 1 > 0 && y + 1 < SizeY && _grid[x - 1, y + 1] == -1) //Left-Upper
{
count++;
}
if (x - 1 > 0 && y - 1 > 0 && _grid[x - 1, y - 1] == -1) //Left-Lower
{
count++;
}
return count;
}
What's better? Quicker returning from the method for special case. Reduced nesting in If(...) blocks.
2. OpenEmptySpace()
public/private void OpenEmptySpace(int x, int y)
{
for (var deltaX = -1; deltaX <= 1; deltaX += 2)
{
for (var deltaY = -1; deltaY <= 1; deltaY += 2)
{
var thisX = x + deltaX;
var thisY = y + deltaY;
if (OpeningNotNeeded(thisX, thisY))
{
continue;
}
Explored[thisX, thisY] = true;
_buttons[thisX, thisY].Text = "0";
OpenEmptySpace(thisX, thisY);
}
}
}
private bool OpeningNotNeeded(int x, int y)
{
return !CheckBounds(x, y)
|| GameLogicChecker(x, y) != 0
|| Explored[x, y];
}
What's better? Properly named indexing variables in both loops. Properly written condition (+= 2 instead of ++). Reduced nesting in If(...). Easier to read method call in the If(...) instead of three predicates. Useful temporary variables added which make it clear what x + k and y + l were in the code written earlier.
3. CheckBounds() is written fine.
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 8 years ago.
I'm tried to port this code:
http://www.emanueleferonato.com/2008/12/08/perfect-maze-generation-tile-based-version-as3/
to c#, and write it with XNA.
But I got broken maze:
I'm new to c#, maybe someone can help me?
Here is my C# code (I remove draw method):
class Maze
{
private int MAZE_WIDTH = 30;
private int MAZE_HEIGHT = 30;
private int TILE_SIZE = 10;
private int _width;
private int _height;
private int [,] _maze;
private List<int> _moves;
private int _startX;
private int _startY;
private int _finishX;
private int _finishY;
public Maze()
{
_width = MAZE_WIDTH *2 - 1;
_height = MAZE_HEIGHT *2 - 1;
_startX = 1;
_startY = 1;
_finishX = _height - 2;
_finishY = _height - 2;
Generate();
}
public void Generate()
{
InitMaze();
CreateMaze();
}
private void InitMaze()
{
_maze = new int[_width, _height];
for (var x = 0; x < _height; x++)
{
for (var y = 0; y < _width; y++)
_maze[x, y] = 1;
}
_maze[_startX, _startY] = 0;
}
private void CreateMaze()
{
var posX = _startX;
var posY = _startY;
_moves = new List<int>();
_moves.Add(posY + (posX*_width));
while (_moves.Count > 0)
{
string possibleDirections = "";
if ((posX + 2 < _height) && (_maze[posX + 2, posY] == 1) && (posY + 2 != 0) && (posX + 2 != _height - 1))
{
possibleDirections += "S";
}
if ((posX - 2 >= 0) && (_maze[posX - 2, posY] == 1) && (posX - 2 != 0) && (posX - 2 != _height - 1))
{
possibleDirections += "N";
}
if ((posY - 2 >= 0) && (_maze[posX, posY - 2] == 1) && (posY - 2 != 0) && (posY - 2 != _width - 1))
{
possibleDirections += "W";
}
if ((posY + 2 < _width) && (_maze[posX, posY + 2] == 1) && (posY + 2 != 0) && (posY + 2 != _width - 1))
{
possibleDirections += "E";
}
if (possibleDirections.Length > 0)
{
var move = Utils.RandInt(0, (possibleDirections.Length - 1));
switch (possibleDirections[move].ToString())
{
case "N":
_maze[posX - 2, posY] = 0;
_maze[posX - 1, posY] = 0;
posX -= 2;
break;
case "S":
_maze[posX + 2, posY] = 0;
_maze[posX + 1, posY] = 0;
posX += 2;
break;
case "W":
_maze[posX,posY - 2] = 0;
_maze[posX,posY - 1] = 0;
posY -= 2;
break;
case "E":
_maze[posX,posY + 2] = 0;
_maze[posX,posY + 1] = 0;
posY += 2;
break;
}
}
else
{
var back = _moves[_moves.Count - 1];
_moves.RemoveAt(_moves.Count - 1);
posX = back/_width;
posY = back%_width;
}
}
}
public void DrawMaze(ScreenBase screen)
{
//just drawing tiles
}
private int RandInt(int min, int max)
{
return new Random().Next(min, max);
}
//End of class
}
class Utils
{
private static readonly Random rnd = new Random();
public static int RandInt(int min, int max)
{
return rnd.Next(min, max);
}
}
You're generating a new Random object every time you're calling RandInt(). When that occurs in quick succession, it uses the same seed since it's based on the system time and you end up getting the same "random" value over and over.
One way to fix it would be to add another field:
private Random _random = new Random();
And then change your RandInt() method to:
private int RandInt(int min, int max)
{
return _random.Next(min, max);
}