c# how to check if pieces are ordered? - c#

Picture 1.
Picture 2.
I made method for checking if all pieces are in base or goal if yes it returns true,now i need another method.
If its like on Picture 1. i need to change number of throws to 3 ,if its ordered like on Picture 2 i can allow only 1 throw.
I got 4 goalPositions and 4 piecePositions,and need to check if pieces are ordered on them properly from 54-51 path positions(path is array of 55 fields 0-54) ,if yes return true if not return false.
I am new to C# never had chance to work with order checking till now.
I was trying to do it with 3 int lists goalPositions (populated with 51,52,53,54 path positions),piecePositions(populated with pieces positions with getPosition() method),and piecesOnGoal (reserved for counting pieces on goal positions). but no luck with that.
I'll add some code. Part of Player class with that lists and method for checking pieces in goal or base
class Player {
protected PieceSet[] pieces;
Color color;
int numberOfThrows;
Dice dice;
public List<int> goalPositions;
public List<int> piecePositions;
public List<int> piecesOnGoal;
public enum Color
{
Yellow, Green, Blue, Red
}
public Player(Color color)
{
int[] path = new int[55];
this.color = color;
dice = new Dice();
numberOfThrows = 3;
switch (color)
{
case Color.Yellow:
path = BoardHelper.getYellowPath();
break;
case Color.Green:
path = BoardHelper.getGreenPath();
break;
case Color.Blue:
path = BoardHelper.getBluePath();
break;
case Color.Red:
path = BoardHelper.getRedPath();
break;
}
pieces = new PieceSet[4];
pieces[0] = new PieceSet(path, 0);
pieces[1] = new PieceSet(path, 1);
pieces[2] = new PieceSet(path, 2);
pieces[3] = new PieceSet(path, 3);
piecePositions = new List<int>(4);
piecePositions.Add(pieces[0].getPosition());
piecePositions.Add(pieces[1].getPosition());
piecePositions.Add(pieces[2].getPosition());
piecePositions.Add(pieces[3].getPosition());
goalPositions = new List<int>(4);
goalPositions.Add(51);
goalPositions.Add(52);
goalPositions.Add(53);
goalPositions.Add(54);
piecesOnGoal =new List<int>();
}
public bool isAllPiecesInBaseOrGoal()
{
if ((pieces[0].getPosition() < 4 || pieces[0].getPosition() > 50) &&
(pieces[1].getPosition() < 4 || pieces[1].getPosition() > 50) &&
(pieces[2].getPosition() < 4 || pieces[2].getPosition() > 50) &&
(pieces[3].getPosition() < 4 || pieces[3].getPosition() > 50))
return true;
else
return false;
}
And this is how I was thinking to solve my problem: Check if goalPositions contains piecePositions. If yes, add that position into piecesOnGoal. Now I need somehow to check if these piecesOnGoal are ordered. If yes, return true. If not, false.
I am open for any suggestion.
public bool isAllPiecesAreOrderedInGoal()
{
for (int i = 0; i < 4; i++)
{
if (goalPositions.Contains(piecePositions[i]))
{
piecesOnGoal.Add(piecePositions[i]);
}
}
}
Any help is appreciated.

I would suggest a method that checks if any move is possible. A move is possible if there are pieces outside the home or goal or if there are pieces in the goal which have an empty spot before them:
bool IsMovePossible()
{
// check every piece
for(int iPiece = 0; iPiece < 4; ++iPiece)
{
// if it is outside of home or goal, there is a possible move
if(piecePositions[iPiece] > 3 && piecePositions[iPiece] < goalPositions.First())
return true;
// if it is in the goal, check the next position
if(piecePositions[iPiece] >= goalPositions.First()
&& piecePositions[iPiece] < goalPositions.Last()
&& !piecePositions.Any(p => p == piecePositions[iPiece] + 1))
return true;
}
// we have found no piece with a possible move
return false;
}
Then, decide how often the user can roll the dice based on this method's return value. Note that the last check (piecePositions.Any) could be done more efficiently if you maintain an inverted map (i.e. for every position, store which piece is on that position). But checking four pieces should be fine.

Related

A loop that only adds non duplicate values to a a list?

EDIT: OP here, its answered. Can't accept my own answer for 2 days? Dunno I'm a stack noob. Thanks to people that helped.
I want to have a loop that generates a random coordinate and adds it to a list only if that coordinate does not already exist in the list.
And just keeps looping until the correct number of coordinates are in the list.
while (spawnPositions.Count < myPlayer.myPlayerUnits.Count)
{
Debug.Log("While");
int[,] rnd = new int[UnityEngine.Random.Range(minX, maxX), UnityEngine.Random.Range(minZ, maxZ)];
if (spawnPositions.Contains(rnd) == false)
{
Debug.Log("SpawnPos Added!");
spawnPositions.Add(rnd);
}
}
Problem is the if statement is always true. Console output shows the loop loops X amount of times and the if statement is also true X amount of times.
Is this just not possible to do in while-loop. Or am i doing something wrong? Thanks!
EDIT: Oh and to be clear yes duplicates are added. I'm trying to generate 5 unique coordinates on a 3x3 area and there is almost always duplicates!
If I understand you right you want to compare the content of multidimensional arrays or maybe only their dimensions. But the .Contains() method looks for the reference equality and this is always unique because you are calling "new".
I defined a extension method for it.
public static bool IsContentEqualTo(this int[,] array1, int[,] array2)
{
if (array1 == null) throw new ArgumentNullException(nameof(array1), "Array cannot be null");
if (array2 == null) throw new ArgumentNullException(nameof(array2), "Array cannot be null");
if (array1.GetLowerBound(0) != array2.GetLowerBound(0)) return false;
if (array1.GetUpperBound(0) != array2.GetUpperBound(0)) return false;
if (array1.GetLowerBound(1) != array2.GetLowerBound(1)) return false;
if (array1.GetUpperBound(1) != array2.GetUpperBound(1)) return false;
var xMin = array1.GetLowerBound(0);
var xMax = array1.GetUpperBound(0);
var yMin = array1.GetLowerBound(1);
var yMax = array1.GetUpperBound(1);
for (var x = xMin; x <= xMax; x++)
for (var y = yMin; y <= yMax; y++)
{
if (array1[x, y] != array2[x, y]) return false;
}
return true;
}
And you can call it like that.
if (!spawnPositions.Any(array => array.IsContentEqualTo(rnd)))
{
Debug.Log("SpawnPos Added!");
spawnPositions.Add(rnd);
}
EDIT: OP here, its answered. Can't accept my own answer for 2 days? Dunno I'm a stack noob. Thanks to people that helped.
I fixed it, its not pretty but it works. An array of booleans to keep track if the value have been used already. And not actaully adding/removing values from the list from within the while-loop (had a few infinite-loops trying out things :S).
bool[,] tileOccupied = new bool[maxX, maxZ];
for (int i = 0; i < myPlayer.myPlayerUnits.Count; i++)
{
int tileValue = UnityEngine.Random.Range(0, myPlayer.mySpawnArea.Count);
int[,] spawnTile = myPlayer.mySpawnArea[tileValue];
if (tileOccupied[spawnTile.GetLength(0), spawnTile.GetLength(1)] == true)
{
do
{
tileValue = UnityEngine.Random.Range(0, myPlayer.mySpawnArea.Count - 1);
spawnTile = myPlayer.mySpawnArea[tileValue];
} while (tileOccupied[spawnTile.GetLength(0), spawnTile.GetLength(1)] == true);
}
tileOccupied[spawnTile.GetLength(0), spawnTile.GetLength(1)] = true;
spawnPositions.Add(spawnTile);
}

Choosing a random number from an array and returning it to a label

I'm creating a program that allows users to input genes and randomly chooses a weighted option.
For example:
// If statements for gene 1 (NNN)
if (intSireBuild == 1)
{
if (intDamBuild == 1)
{
lblResults1.Content = "NNN";
}
}
else if (intSireBuild == 1)
{
if (intDamBuild == 2)
{
// Random number thing
int[] NNNxNna;
NNNxNna = new int[5];
NNNxNna[0] = 1;
NNNxNna[1] = 1;
NNNxNna[2] = 1;
NNNxNna[3] = 1;
NNNxNna[4] = 2;
NNNxNna[5] = 2;
Random random = new Random();
int gene2 = random.Next(NNNxNna.Length);
// The problem is occurring here, I believe
if (gene2 == 1)
{
lblResults1.Content = "NNN";
}
else
{
lblResults1.Content = "Nna";
}
}
}
// When you click the button, a calculation will be made using user inputed genes
I realize that there is most likely a simpler way to do this, but this is the way I'd like to do it.
The issue that I'm having is that somwehere between the array that carries a list of numbers (1,1,1,1,2,2,) (meant so that the gene 'NNN - or '1'' is more common than than 'Nna'), what's happening, is that the program gets confused and doesn't output any information to the label that I'm using.
I was wondering if someone could help me figure out what I'm missing / not coding correctly?
This following will never happen otherwise it would have enter the first "if"
else if (intSireBuild == 1)
You should have remove the second condition and leaving it with the following
if (intSireBuild == 1)
{
if (intDamBuild == 1)
{
lblResults1.Content = "NNN";
}
else if (intDamBuild == 2)
{
// Random number thing
// Rest of the code
Additionally, this is incorrect bound index NNNxNna[5] = 2; because array with a size of 5 can only have indices between 0 to 4.

Optimisation of route finding code

Small bit of background first. I am developing a system that generates a "route" between locations. Locations have a pre-defined list of neighbours not limited to those adjacent to it. The search can safely assume that by picking the closest neighbour (numerically) to the target destination, it is making the optimal move towards it.
I have working code as shown below:
public Route GetRoute(int StartPoint, int Destination)
{
Route returnRoute = new Route();
returnRoute.steps = new List<int>();
bool locationReached = false;
int selectedNeighbour;
int distanceFromTarget;
int currentPoint = StartPoint; // set the current point to the start point
while (!locationReached)
{
selectedNeighbour = 0;
distanceFromTarget = 5000; // nominal amount guaranteed to be overwritten
var neighbours = locations.FirstOrDefault(l => l.LocationID == currentPoint).Neighbours;
for (int i = 0; i < neighbours.Length; i++)
{
// get the current neighbours, then check proximity
int currentNeighbour = neighbours[i];
int tempDistance = Math.Abs( currentNeighbour - Destination );
// if nearer than previous neighbour, set it as the chosen location
if ( tempDistance < distanceFromTarget )
{
distanceFromTarget = tempDistance;
selectedNeighbour = currentNeighbour;
// if the selected neighbour is the destination, we're done
if ( selectedNeighbour == Destination )
locationReached = true;
}
} // for
// add the selected neighbour if we found one
if ( selectedNeighbour != 0 )
{
currentPoint = selectedNeighbour;
returnRoute.steps.Add(selectedNeighbour);
}
else
{
Debug.Log ("No Route Found");
return returnRoute;
}
} // while
return returnRoute;
}
My question is regarding the loop of the neighbours (int[]) variable. How can this best be optimised? I've seen some use of linq and ordering, but also comments that this approach might be inefficient. I need efficiency over neatness here.
Many thanks.

Problems with C# lists, and ArgumentOutOfRangeException

I am in the process of making a farming/tower defense game and I am very new at programming. I seem to have a major problem with using Lists<> or arrays in XNA. I cannot get it to return the index that I want from the list.
The main question is inside my planting engine. I have successfully implemented a planting system that can generate a list of plants (spriteobjects) with varying properties and place them on the map. Now, I need a way to access a specific plant in the plant list based upon mouseclicking on that plant. I feel like I am very close, but I ended up with a ArgumentOutOfRangeException that I cannot solve. Here is a walkthrough of the code:
Initialization
public void Addplants()
{
switch (Mode)
{
case "Wotalemon":
NewPlant = new Plant(Texture, msRect);
NewPlant.AddAnimation("seed", 0, 16, 64, 64, 1, 0.1f);
NewPlant.AddAnimation("sprout", 64, 16, 64, 64, 1, 0.1f);
NewPlant.AddAnimation("wota", 128, 16, 64, 64, 1, 1.0f);
NewPlant.CurrentAnimation = "seed";
NewPlant.DrawOffset = new Vector2(32, 48);
NewPlant.Position = Position;
NewPlant.Type = "wotalemon";
NewPlant.Birthday = Days;
NewPlant.IsSelected = false;
plants.Add(NewPlant);
thisPlant = NewPlant;
//various plants after this
Update/Draw
I use some simple foreach loops to update and draw the plants, no problems here.
GetInfo (this method uses the spriteobject's hitbox property and a mouseRectangle)
public void GetInfo(Rectangle ms)
{
msRect = ms;
for (int i = 0; i < plants.Count; i++)
{
foreach (Plant NewPlant in plants)
{
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedIndex = i;
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
}
}
finally, here is the problem:
public void SelectPlant()
{
//if (SelectedIndex != null)
if (SelectedIndex > plants.Count | SelectedIndex < 0)
SelectedIndex = plants.Count;
SelectedPlant = plants[SelectedIndex];
}
The exception is thrown in this line:
SelectedPlant = plants[SelectedIndex];
The debugger shows the value as 0. I have tried various methods to try to prevent the index from being null. I feel like something in the Getinfo() method is key here. I am convinced that I am very close to success because the color test that I have inserted in there works perfectly. When I mouseover a plant, it turns black, when I remove the mouse, it returns to normal.
This is EXACTLY the type of behavior I want except that I want it to set selectedIndex to the index of the plant that I am mousing over. Any advice would be greatly appreciated.
Firstly make this a proper or || and check for >= plants.Count - remember that the list is indexed at 0. Then as suggested set it to count - 1:
if (SelectedIndex >= plants.Count || SelectedIndex < 0)
SelectedIndex = plants.Count - 1
I'll add this as a new answer since this is tackling a whole different issue. Taking a look at this code:
msRect = ms;
for (int i = 0; i < plants.Count; i++)
{
foreach (Plant NewPlant in plants) // <-- this is redundant
{
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedIndex = i;
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
}
You are looping through 'plants' twice inside each other! Once using an index (for (int i = 0 ...) and then inside that again using an iterator (foreach (Plant NewPlant ...).
Your options are to either change GetInfo to set the right index by using a single loop:
msRect = ms;
for (int i = 0; i < plants.Count; i++)
{
Plant NewPlant = plants[i];
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedIndex = i;
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
Or do the same thing and short circuit the need for SelectPlant() and SelectedIndex in the first place:
msRect = ms;
foreach (Plant NewPlant in plants) // no need for indexes
{
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedPlant = NewPlant; // this is everything you need
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
You do however need to be careful using a 'global' variable like SelectedPlant to capture this logic. You're better off changing the whole GetInfo method to return the selected plant, rather than having it modify SelectedPlant directly. That is, change the method signature to return Plant not void, and change SelectPlant = NewPlant in the code above to return NewPlant. Or for even more fun as a single line:
return plants.Where(p => p.BoundingBox.Intersects(ms))

Visual C# object array changes all elements in array instead of just one

I'm new to C# so I'm making a Snake Game to learn. I created an object of a snake which contains an array of objects called pieces. So the pieces make up the snake. I'm trying to change the first piece's x value by 1 in order move the first piece one unit to the right. The problem is that when I change the first piece's x value by 1, the second piece's x value also changes by 1. So myPiece[1].x = 6 and myPiece[2].x = 6 even though I only increased the first one's value. How can I make it so I can change the value of each individual piece without it changing the rest of the piece's values?
class theSnake
{
private int size;
private thePiece[] myPieces=new thePiece[50];
private int xDim;
private int yDim;
public theSnake(int pxDim,int pyDim)
{
size = 1;
xDim = pxDim;
yDim = pyDim;
for (int i = 1; i <= 49; i++)
{
myPieces[i] = new thePiece();
}
myPieces[1].setX(xDim/2); //sets the starting of the snake in the center of the field
myPieces[1].setY(yDim/2);
myPieces[1].setDir(3);
}
public void move()
{
//the pieces trade positions with the positions in front of it
//the pieces travel backwards instead of forwards so there is no gap created
for (int i = size; i >= 2; i--)
{
myPieces[i] = myPieces[i-1];
}
//moves leading snake based on direction given
switch (myPieces[1].getDir())
{
case 1:
myPieces[1].setY(myPieces[1].getY() + 1);
break;
case 2:
myPieces[1].setY(myPieces[1].getY() - 1);
break;
case 3:
myPieces[1].setX(myPieces[1].getX() + 1);
break;
case 4:
myPieces[1].setX(myPieces[1].getX() - 1);
break;
}
}
class thePiece
{
private int x;
private int y;
private int direction;
//north = 1 south = 2 east = 3 west =4
public thePiece()
{
x = 0;
y = 0;
direction = 1;
}
}
for (int i = size; i >= 2; i--)
{
myPieces[i] = myPieces[i-1];
}
because myPieces[2] point to myPieces[1], in an other word, myPieces[2] and myPieces[1] are the same object. the orignal myPieces[2] object now is referenced by myPieces[3].
if you want to assign values, you can use following code
for (int i = size; i >= 2; i--)
{
myPieces[i].x = myPieces[i-1].x;
myPieces[i].y = myPieces[i-1].y;
myPieces[i].direction = myPieces[i-1].direction;
}
Your issue is that you are not properly swapping the objects in the array:
Change the following:
for (int i = size; i >= 2; i--)
{
myPieces[i] = myPieces[i-1];
}
To something like the following (this may need minor tweaks if I didn't understand your logic correctly):
for (int i = size; i >= 2; i--)
{
// Save a reference to the piece that will be written over
var savePiece = myPieces[i];
// Move the previous piece
myPieces[i] = myPieces[i-1];
// Now move the saved piece to the previous position
myPieces[i-1] = savePiece;
}

Categories