i am working on improving this tower defence gtame that i finished from this tutorial http://xnatd.blogspot.com/ i now wish to load the levels from a text file but not quite sure how i would do this using a streamreader, any tips? heres the source code for my level class;
public class Level
{
protected int temperature;
protected int levelNo;
private Queue<Vector2> waypoints = new Queue<Vector2>();
public Queue<Vector2> Waypoints
{
get
{
return waypoints;
}
}
int[,] map = new int[,]
{
{0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,},
{0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,},
{0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,},
{0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,},
{0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,},
{0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,},
{0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,},
{0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,},
{0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,},
{0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,},
{0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,},
{0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,},
{0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,},
{0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,},
{0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,},
{0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,},
};
public int Temperature // get the width of the level (how many numbers are in a row)
{
get
{
return temperature;
}
}
public int LevelNo // get the width of the level (how many numbers are in a row)
{
get
{
return levelNo;
}
set
{
levelNo = value;
}
}
public int Width // get the width of the level (how many numbers are in a row)
{
get
{
return map.GetLength(1);
}
}
public int Height // get the height of our level (how many numbers are there in a column)
{
get
{
return map.GetLength(0);
}
}
public int GetIndex(int cellX, int cellY) // return the index of the requested cell.
{
if (cellX < 0 || cellX > Width - 1 || cellY < 0 || cellY > Height - 1)
{
return 0;
}
else
{
return map[cellY, cellX];
}
}
public List<Texture2D> tileTextures = new List<Texture2D>(); // list to contain all the textures
/// <summary>
/// CONSTRUCTOR NEW LEVEL
/// </summary>
public Level()
{
SetWayPoints(map);
this.temperature = 1000;
this.levelNo = 2;
}
private void SetWayPoints(int[,] map)
{
int currentPosVal = map[0, 0];
int lPos = 0;
int rPos = 0;
int uPos = 0;
int dPos = 0;
int storedXPos = 99;
int storedYPos = 99;
int endstoredXPos = 99;
int endstoredYPos = 99;
int lastY = 0;
int lastX = 0;
//Search top ROW for start
for (int i = 0; i < Width; i++)
{
currentPosVal = map[0, i];
if (currentPosVal == 1)
{
storedXPos = i;
storedYPos = 0;
waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32);
lastX = storedXPos;
lastY = storedYPos;
break;
}
}
//if start not set
if (storedXPos == 99 && storedXPos == 99)
{
//look in 1st coloum for start
for (int i = 0; i < Height; i++)
{
currentPosVal = map[i, 0];
if (currentPosVal == 1)
{
storedXPos = 0;
storedYPos = i;
waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32);
lastX = storedXPos;
lastY = storedYPos;
break;
}
}
}
//search end COLOUM for end
for (int i = 0; i < Height; i++)
{
currentPosVal = map[i, Width - 1];
if (currentPosVal == 1)
{
endstoredXPos = Width - 1;
endstoredYPos = i;
}
}
//If end not set look in bottom row for end
if (endstoredXPos == 99 && endstoredYPos == 99)
{
for (int i = 0; i < Width; i++)
{
currentPosVal = map[7, i];
if (currentPosVal == 1)
{
endstoredXPos = i;
endstoredYPos = Height - 1;
}
}
if (endstoredXPos == 99 && endstoredYPos == 99)
{
}
}
// start midlle loop
while (true)
{
lPos = 0;
rPos = 0;
uPos = 0;
dPos = 0;
//If current pos is not down the left hand edge
if (storedXPos > 0) { lPos = map[storedYPos, storedXPos - 1]; }
//If current pos square is not down the right hand edge
if (storedXPos < Width - 1) { rPos = map[storedYPos, storedXPos + 1]; }
//If current pos square is not in the top row
if (storedYPos > 0) { uPos = map[storedYPos - 1, storedXPos]; }
//If current pos square is not in the bottom row
if (storedYPos < Height - 1) { dPos = map[storedYPos + 1, storedXPos]; }
if (lPos == 1 && (lastX != storedXPos - 1 || lastY != storedYPos))
{
lastX = storedXPos;
lastY = storedYPos;
storedXPos--;
waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32);
}
else if (rPos == 1 && (lastX != storedXPos + 1 || lastY != storedYPos))
{
lastX = storedXPos;
lastY = storedYPos;
storedXPos++;
waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32);
}
else if (dPos == 1 && (lastX != storedXPos || lastY != storedYPos + 1))
{
lastX = storedXPos;
lastY = storedYPos;
storedYPos++;
waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32);
}
else if (uPos == 1 && (lastX != storedXPos || lastY != storedYPos - 1))
{
lastX = storedXPos;
lastY = storedYPos;
storedYPos--;
waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32);
}
if (storedXPos == endstoredXPos && storedYPos == endstoredYPos)
{
break;
}
}
}
public void AddTexture(Texture2D texture) // method adds a texture to our texture list.
{
tileTextures.Add(texture);
}
//Reads number from array, store its value in textureIndex, Use textureIndex to get the texture from tileTextures,
public void Draw(SpriteBatch batch) //Draw appropiate texture, Repeat through all elements of the array
{
int textureIndex;
Texture2D texture;
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
if (levelNo == 0)
{
textureIndex = map[y, x];
if (textureIndex == -1)
continue;
texture = tileTextures[textureIndex];
batch.Draw(texture, new Rectangle(x * 32, y * 32, 32, 32), Color.White);
}
if (levelNo > 0)
{
textureIndex = map[y, x];
textureIndex += (levelNo * 2);
if (textureIndex == -1)
continue;
texture = tileTextures[textureIndex];
batch.Draw(texture, new Rectangle(x * 32, y * 32, 32, 32), Color.White);
}
}
}
}
}
}
Since C# is compiled and can't do evals like scripted languages can (not that you should be doing that anyway) you should probably use streamreader to read the data from file (formatted perhaps as delimited text: csv or tsv)
Assuming you're loading something similar to the map you have up there then a map file could look something like
0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0
0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0
0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0
0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0
0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0
0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0
0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0
0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0
0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0
0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0
0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0
0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0
0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0
0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0
0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0
0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1
where you would then loop through the file and read each line
As each line is read in, you can then split the line by "," to create a 1d array which can then be assigned to an index in the 2d array. Loop for each line to create the entire 2d map array
Take a look at this if you need help splitting strings in C#; note that the sample code splits at spaces " " and that you should use s.Split(','); for csv
With a file that small i would use:
File.ReadAllLines , and after readling it loop over the lines with a foreach loop.
Related
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:
I've tried to reimplement the Fast Graphics Gems Ray/AABB Intersection Method in C#:
// Based on "Fast Ray-Box Intersection" algorithm by Andrew Woo, "Graphics Gems", Academic Press, 1990
public unsafe Vector? IntersectionWith(Cuboid other) {
const int NUM_DIMENSIONS = 3;
Assure.Equal(NUM_DIMENSIONS, 3); // If that value is ever changed, this algorithm will need some maintenance
const byte QUADRANT_MIN = 0;
const byte QUADRANT_MAX = 1;
const byte QUADRANT_BETWEEN = 2;
// Step 1: Work out which direction from the start point to test for intersection for all 3 dimensions, and the distance
byte* quadrants = stackalloc byte[NUM_DIMENSIONS];
float* candidatePlanes = stackalloc float[NUM_DIMENSIONS];
float* cuboidMinPoints = stackalloc float[NUM_DIMENSIONS];
float* cuboidMaxPoints = stackalloc float[NUM_DIMENSIONS];
float maxDistance = Single.NegativeInfinity;
byte maxDistanceDimension = 0;
bool startPointIsInsideCuboid = true;
cuboidMinPoints[0] = other.X;
cuboidMinPoints[1] = other.Y;
cuboidMinPoints[2] = other.Z;
cuboidMaxPoints[0] = other.X + other.Width;
cuboidMaxPoints[1] = other.Y + other.Height;
cuboidMaxPoints[2] = other.Z + other.Depth;
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
if (StartPoint[i] < cuboidMinPoints[i]) {
quadrants[i] = QUADRANT_MIN;
candidatePlanes[i] = cuboidMinPoints[i];
startPointIsInsideCuboid = false;
}
else if (StartPoint[i] > cuboidMaxPoints[i]) {
quadrants[i] = QUADRANT_MAX;
candidatePlanes[i] = cuboidMaxPoints[i];
startPointIsInsideCuboid = false;
}
else {
quadrants[i] = QUADRANT_BETWEEN;
}
}
if (startPointIsInsideCuboid) return StartPoint;
// Step 2: Find farthest dimension from cuboid
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
// ReSharper disable once CompareOfFloatsByEqualityOperator Exact check is desired here: Anything other than 0f is usable
if (quadrants[i] != QUADRANT_BETWEEN && Orientation[i] != 0f) {
float thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i];
if (thisDimensionDist > maxDistance) {
maxDistance = thisDimensionDist;
maxDistanceDimension = i;
}
}
}
if (maxDistance < 0f) return null;
if (maxDistance - Length > MathUtils.FlopsErrorMargin) return null;
float* intersectionPoint = stackalloc float[NUM_DIMENSIONS];
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
if (maxDistanceDimension == i) {
intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i];
if (cuboidMinPoints[i] - intersectionPoint[i] > MathUtils.FlopsErrorMargin || intersectionPoint[i] - cuboidMaxPoints[i] > MathUtils.FlopsErrorMargin) return null;
}
else intersectionPoint[i] = candidatePlanes[i];
}
Vector result = new Vector(intersectionPoint[0], intersectionPoint[1], intersectionPoint[2]);
if (!IsInfiniteLength && Vector.DistanceSquared(StartPoint, result) > Length * Length) return null;
else return result;
}
However, although it sort of works, I'm getting incorrect results on the following part of a unit test:
Cuboid cuboid = new Cuboid(frontBottomLeft: new Vector(0f, 7.1f, 0f), width: 0f, height: 5f, depth: 0f);
Ray testRayC = new Ray(startPoint: new Vector(30f, 30f, 30f), orientation: new Vector(-1f, -1f, -1f));
Assert.AreEqual(
null,
testRayC.IntersectionWith(cuboid)
);
I am expecting null from the call to testRayC.IntersectionWith(cuboid), but instead it returns a Vector(0, 12.1, 0), which is not a point on the ray at all.
So is it just a case of adding a final check that the calculated point is on the ray? Or (and this is what I suspect), have I made an error in transcribing the code? I have double and triple checked but didn't see anything obvious...
The problem in your code is when you do if (maxDistanceDimension == i) {. The original code checks if (whichPlane != i) {. I don't have your data structures, but a fix should look like:
for (byte i = 0; i < NUM_DIMENSIONS; ++i)
{
if (maxDistanceDimension != i)
{
intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i];
if (intersectionPoint[i] < cuboidMinPoints[i] - MathUtils.FlopsErrorMargin || intersectionPoint[i] > cuboidMaxPoints[i] + MathUtils.FlopsErrorMargin)
return null;
}
else
{
intersectionPoint[i] = candidatePlanes[i];
}
}
Next, the following isn't in the original code. What is this for?
if (maxDistance - Length > MathUtils.FlopsErrorMargin)
return null;
If you are trying to check if the hit is within the extent of the ray, this may be a bug. Given that your Orientation does not appear to be normalized, maxDistance is not necessarily in units of length. This may not matter in the original algorithm, but if you are going to check maxDistance against some other length you need to normalize Orientation (make it dimensionless) so that
thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i];
will have units of length.
Incidentally, in the original I think the following is wrong:
if(inside) {
coord = origin;
return (TRUE);
}
Assuming this code is c and not c++, this simply sets the the coord pointer to have the same reference as the origin pointer, which will have no effect on the caller. This issue doesn't apply to your version, however.
Also, in the course of looking at this, I made a more literal c# transcription of the algorithm here:
public static class RayXCuboid
{
enum HitQuadrant
{
Right = 0,
Left = 1,
Middle = 2,
}
const int Dimension = 3;
[Conditional("DEBUG")]
static void AssertValidArguments<TDoubleList>(params TDoubleList[] args) where TDoubleList : IList<double>
{
Debug.Assert(Dimension == 3);
foreach (var list in args)
Debug.Assert(list != null && list.Count == Dimension);
}
public static bool HitBoundingBox<TDoubleList>(TDoubleList minB, TDoubleList maxB, TDoubleList origin, TDoubleList dir, TDoubleList coord) where TDoubleList : IList<double>
{
AssertValidArguments(minB, maxB, origin, dir, coord);
HitQuadrant[] quadrant = new HitQuadrant[Dimension];
double[] maxT = new double[Dimension];
double[] candidatePlane = new double[Dimension];
/* Find candidate planes; this loop can be avoided if
rays cast all from the eye(assume perpsective view) */
bool inside = true;
for (int i = 0; i < Dimension; i++)
if (origin[i] < minB[i])
{
quadrant[i] = HitQuadrant.Left;
candidatePlane[i] = minB[i];
inside = false;
}
else if (origin[i] > maxB[i])
{
quadrant[i] = HitQuadrant.Right;
candidatePlane[i] = maxB[i];
inside = false;
}
else
{
quadrant[i] = HitQuadrant.Middle;
}
/* Ray origin inside bounding box */
if (inside)
{
CopyTo(origin, coord);
return true;
}
/* Calculate T distances to candidate planes */
for (int i = 0; i < Dimension; i++)
if (quadrant[i] != HitQuadrant.Middle && dir[i] != 0.0)
maxT[i] = (candidatePlane[i] - origin[i]) / dir[i];
else
maxT[i] = -1.0;
/* Get largest of the maxT's for final choice of intersection */
int whichPlane = 0;
for (int i = 1; i < Dimension; i++)
if (maxT[whichPlane] < maxT[i])
whichPlane = i;
/* Check final candidate actually inside box */
if (maxT[whichPlane] < 0.0)
{
FillWithDefault(coord);
return false;
}
for (int i = 0; i < Dimension; i++)
if (whichPlane != i)
{
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
if (coord[i] < minB[i] || coord[i] > maxB[i])
{
FillWithDefault(coord);
return false;
}
}
else
{
coord[i] = candidatePlane[i];
}
return true; /* ray hits box */
}
static void FillWithDefault<T>(IList<T> list)
{
for (int i = 0; i < list.Count; i++)
list[i] = default(T);
}
static void CopyTo<T>(IList<T> from, IList<T> to)
{
int arrayIndex = 0;
foreach (var item in from)
to[arrayIndex++] = item;
}
}
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);
}
I encountered a System.StackOverflowException problem when I was trying to Marshal.Copy()
Here is the screen shot of the code where exception happens:
Here is the function:
private static void ImageUpdate(IntPtr returnArray, ref int channels)
{
if (_prevTickCount == 0)
{
_sumTickCount = 0;
}
else
{
_sumTickCount = _sumTickCount * .75 + (Environment.TickCount - _prevTickCount) * .25;
}
//only copy to the buffer when pixel data is not being read
if (_pixelDataReady == false)
{
int width = 0;
int height = 0;
if (false == GetImageDimensions(ref width, ref height))
{
return;
}
_dataLength = width * height;
_colorChannels = channels;
if ((_pixelData == null) || (_pixelData.Length != (_dataLength * _colorChannels)))
{
_pixelData = new short[_dataLength * _colorChannels];
//_pixelDataHistogram = new int[_colorChannels][];
_pixelDataHistogram = new int[MAX_CHANNELS][];
if (_colorChannels == 1)
{
_pixelDataByte = new byte[_dataLength];
}
else
{
_pixelDataByte = new byte[_dataLength * 3];
}
//for (int i = 0; i < _colorChannels; i++)
for (int i = 0; i < MAX_CHANNELS; i++)
{
_pixelDataHistogram[i] = new int[PIXEL_DATA_HISTOGRAM_SIZE];
}
}
//2^n == FULL_RANGE_NORMALIZATION_FACTOR
const int SHIFT_VALUE = 6;
switch (_colorChannels)
{
case 1:
{
Marshal.Copy(returnArray, _pixelData, 0, _dataLength * _colorChannels);
//factor is derived by taking CAMERA_MAX_INTENSITY_VALUE/256
//const double FULL_RANGE_NORMALIZATION_FACTOR = 64.0;
//clear the histogram
for (int i = 0; i < PIXEL_DATA_HISTOGRAM_SIZE; i++)
{
_pixelDataHistogram[0][i] = 0;
}
for (int i = 0; i < _dataLength * _colorChannels; i++)
{
double valHist;
if (_pixelData[i] < 0)
{
valHist = (_pixelData[i] + 32768) >> SHIFT_VALUE;
}
else
{
valHist = (_pixelData[i]) >> SHIFT_VALUE;
}
_pixelDataHistogram[0][(byte)valHist]++;
}
}
break;
default:
{
Marshal.Copy(returnArray, _pixelData, 0, _dataLength * _colorChannels);
}
break;
}
_dataWidth = width;
_dataHeight = height;
_pixelDataReady = true;
ThorLog.Instance.TraceEvent(TraceEventType.Verbose, 1, "ImageUpdate pixeldata updated");
}
else
{
ThorLog.Instance.TraceEvent(TraceEventType.Verbose, 1, "ImageUpdate pixeldata not ready");
}
_prevTickCount = Environment.TickCount;
}
The whole idea is to copy image buffer from native code. This exception occurs only when image size is large 4K X 4K, but I dont have a problem processing a size below that.
I have no idea how I should correct this. Anyone care to educate? Thanks!
I traced it down, eventually, if was the returnArray which is not newed large enough to cause this problem.
i want to write a shape with " * " and " | " the shape is below.
The program must take height and width from user.Width is column number without ' | '.I tried to write but confused.My code sometimes works great and sometimes being stupid.For example when i enter height : 13, width : 4 it writes one more,if witdh is 1 it enters infinite loop.While trying to solve it became too conflicted.Must i fix it or rewrite ? Here is the code : height =10, width = 5
|*____|
|_*___|
|__*__|
|___*_|
|____*|
|___*_|
|__*__|
|_*___|
|*____|
|_*___|
private static void Function()
{
int height, width;
if (width == 2)
while (height > 0)
{
FirstPart(width, height);
height -= width;
}
else
while (height > 0)
{
if (height > 1)
{
FirstPart(width, height);
height -= width;
}
if (height > 0)
{
SecondPart(width, height);
height -= width - 2;
}
}
}
private static void FirstPart(int width,int height)
{
if(height > width)
for (int i = 0; i < width; i++)
{
for (int j = 0; j < width+2; j++)
{
if (j == 0 || j == width + 1)
Console.Write("|");
else
if (i + 1 == j)
Console.Write("*");
else
Console.Write(" ");
}
Console.WriteLine();
}
else
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width + 2; j++)
{
if (j == 0 || j == width + 1)
Console.Write("|");
else
if (i + 1 == j)
Console.Write("*");
else
Console.Write(" ");
}
Console.WriteLine();
}
}
private static void SecondPart(int width,int height)
{
if(height > width)
for (int i = 0; i < width-2; i++)
{
for (int j = 0; j < width+2; j++)
{
if (j == 0 || j == width + 1)
Console.Write("|");
else
if (i + j == width-1)
Console.Write("*");
else
Console.Write(" ");
}
Console.WriteLine();
}
else
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width + 2; j++)
{
if (j == 0 || j == width + 1)
Console.Write("|");
else
if (i + j == width - 1)
Console.Write("*");
else
Console.Write(" ");
}
Console.WriteLine();
}
}
private static void WriteStars(int width, int height)
{
int j = 0;
for (int i = 0; i < height; i++)
{
Console.Write("|");
for (int f = 0; f < width; f++)
{
if (f == Math.Abs(j))
{
Console.Write("*");
}
else
{
Console.Write(" ");
}
}
j++;
if (Math.Abs(j) == width - 1)
{
j *= -1;
}
Console.WriteLine("|");
}
}
Probably going to get downvoted for giving you a complete answer, but maybe it'll show you one correct approach and you can learn something from it...
I see a
while (Height > 0)
so your infinite loop is coming from Height never getting less or equal to 0.
It's better to rewrite. When you do, decouple the code into several functions so that one function draws a single line, and another one calls the former to draw all the lines.
void WriteStars(int Width,int Height)
{
int _sp=1; //Star Pos
bool _left = false;
for(int i =0;i<Height;i++)
{
Console.Write("|");
int j;
for(j=1;j<Width-1;j++)
{
if(j==_sp)
{
Console.Write("*");
if(_left)
{
_sp--;
}
else
{
_sp++;
}
j++;
break;
}
else
{
Console.Write("_");
}
}
for(;j<Width-1;j++)
{
Console.Write("_");
}
Console.WriteLine("|");
if(_sp==0)
{
_left = false;
}
else if(_sp==Width)
{
_left = true;
}
}
}
Try if it works, wrote it right here.
even shorter:
static void Variante_2(int height, int width)
{
byte[][] arr = new byte[height][];
int pos = 0;
int mov = 1;
for (int line = 0; line < height; line++)
{
arr[line] = new byte[width];
for (int col = 0; col < width; col++) { arr[line][col] = 45; }
arr[line][pos] = 42;
pos += mov;
if (pos == 0 || pos == (width - 1)) { mov *= -1; }
Console.WriteLine("|" + ASCIIEncoding.ASCII.GetString(arr[line]) + "|");
}
string temp = Console.ReadLine();
}
and it is possible to do it with less code:
static void Variante_3(int height, int width)
{
int pos = 1;
int mov = 1;
for (int line = 0; line < height; line++)
{
Console.WriteLine("|" + "*".PadLeft(pos, '_') + "|".PadLeft(width - pos, '_'));
pos += mov;
if (pos == 1 || pos == (width - 1)) { mov *= -1; }
}
string temp = Console.ReadLine();
}
Sorry to all not doing others homework, but I couldnĀ“t sleep without showing this g