Please explain me behaviour of C#. Object from reference - c#

I have method with one argument which is instance of my created class - Chessfield which contain three tables - one of integers and two of bools.
In the method I have also List of Chessfield which is the return object of my method.
I am modifying chessfield (so the object from reference) and add it on list List.Add(Chessfield) several times (one time after each change).
In the end return object (so list contain several object of Chessfield) all instances are the same unrespecting my changes !
I have read similar topic and try to put 'ref' before argument and the place where I proceed this method.
Without success also I tried to create instance of Chessfield inside the method and assign to it Chessfield object from reference, then making changes on internal created object.
How I can solve it ? In the end I need to receive list of objects which each is a little bit modified from original one (from reference).
Have a nice day !!
p.s. If the code will be helpful then I cut and paste general idea code.
EDIT:
Joel undrestand me Good ! The difference is that inside object are tables and it makes the problem more complex, because I do few changes in these tables in compare to this original object. To be more clear I paste my code:
public class Chessfield
{
public int[] pieces = new int[64];
public bool[] blacks = new bool[64];
public bool[] whites = new bool[64];
public Chessfield(int[] pieces, bool[] blacks, bool[] whites)
{
this.pieces = pieces;
this.blacks = blacks;
this.whites = whites;
}
public Chessfield()
{
}
}
And method look like this:
static public List<Chessfield> MakeAllMovesForWhites(Chessfield chessfieldModel)
{
List<Chessfield> listOfPossibleMoves = new List<Chessfield>(); // list containing chessfields with changed position of figures
int indexOfCurrentPosition = 0; //start with field 0 (most top left)
foreach (bool singleEnemyChecker in chessfieldModel.whites) //iterate all fields, table of whites contain information if white field stand on the field (true, otherwise false),
{
if (singleEnemyChecker == true) //so algorithm will proceed only fields with white figure
{
int kindOfPiece = chessfieldModel.pieces[indexOfCurrentPosition]; // (table pieces contain information which kind of figure stand on particular field 0 -> empty, 1 -> soldier, 2-> tower, 3 -> horse etc...
switch (kindOfPiece)// (based on figure at field it is going to predict all possible moves
{
case 2: // tower case
if (indexOfCurrentPosition % 8 != 0) // check if the field is not most left, otherwise leave
{
int localIndexIterator = indexOfCurrentPosition; //localIndex iterate all possible moves in left direction
while (localIndexIterator % 8 != 0) // checking if tower is standing on the most left field
{
localIndexIterator = localIndexIterator - 1; //iterate all possible moves of tower for left direction
if (chessfieldModel.pieces[localIndexIterator] == 0) //if there are no figures on checking field proceed:
{
chessfieldModel.pieces[indexOfCurrentPosition] = 0; // erase tower from original position
chessfieldModel.whites[indexOfCurrentPosition] = false; // and mark that white tower is not standing there anymore
chessfieldModel.pieces[localIndexIterator] = 2; // put tower on new place
chessfieldModel.whites[localIndexIterator] = true; // and mark that on new place there is white figure
listOfPossibleMoves.Add(chessfieldModel); // here I add changed object of chessfield to list
chessfieldModel.pieces[indexOfCurrentPosition] = 2; // here I come back to original chessfield
chessfieldModel.whites[indexOfCurrentPosition] = true;
chessfieldModel.pieces[localIndexIterator] = 0;
chessfieldModel.whites[localIndexIterator] = false;
}
else //if there is figure at checking field
break; //leave this case
}
}
if (indexOfCurrentPosition % 8 != 7) // right direction case
{
// here is similar code to the sample above
}
if (indexOfCurrentPosition / 8 != 0) //top direction case
{
// here is similar code to the sample above
}
if (indexOfCurrentPosition / 8 != 7) //bottom direction case
{
// here is similar code to the sample above
}
break;
// here are another figures horse and so on...
}
}
indexOfCurrentPosition++; // go to next field...
}
return listOfPossibleMoves; //return list of changed chessfields
}
and here I call method
Logic.MakeAllMovesForWhites(currentChessfield);
I understand what is the problem. And Joel - you are explaining very good ! (y) Thank you.
My first attemp to solve it was (before I ask here):
Chessfield abc = new Chessfield();
abc = chessfieldModel;
abc.pieces[indexOfCurrentPosition] = 0;
abc.whites[indexOfCurrentPosition] = true;
abc.pieces[localIndexIterator] = 2;
abc.whites[localIndexIterator] = false;
listOfPossibleMoves.Add(abc);
Fail. I tried this in every case (create for every figure and every direction). By the way there are 33 different cases how figure can move in chess, so I had this piece of code above in this 33 places (but sometimes I put different things to tables..). But figure like tower can move left for 1,2,3,4,5,6,7 fields if there are not pieces on the left.. and this is problem that I must to create always new instance and I do not know how, because I must to create unique instance, change it a bit, and add to list.. always unique, but in different cases.
Also I have tried your solution Joel, but the problem is that I need to do some changes to original chessfield (4 rows always, but different changes for different figures).
But I tried to create a new instance, add it to list, and then change it while is already on list. Doesn't work and logic is not proper even then.
listOfPossibleMoves.Add(new Chessfield() { pieces = chessfieldModel.pieces, blacks = chessfieldModel.blacks, whites = chessfieldModel.whites });
listOfPossibleMoves[listOfPossibleMoves.Count - 1].pieces[indexOfCurrentPosition] = 0;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].whites[indexOfCurrentPosition] = false;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].pieces[localIndexIterator] = 2;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].whites[localIndexIterator] = true;
EDIT: So maybe coming back to my first method, but how I can create unique name for objects creating in the same place ? May you recommend some technique or what I can do in this situation ?
Thanks Joel and all :)
Have a nice day (or night) everybody !

It would really help to see code in the question, but it sounds like you're doing something like this:
public class ChessField
{
public bool b1;
public bool b2;
public int i1;
}
public List<ChessField> Method(ChessField c)
{
var result = new List<ChessField>();
for (int i = 0;i<3;i++)
{
c.i1 = i;
result.Add(c);
}
return result;
}
Here's the problem: you are adding the same object to the list. result[0] refers to the same object instance as result[1] refers to the same object instance as result[2] refers to the same object instance as c. Changing a property in c changes it everywhere else in this code, because they all are variables for the same object in memory. If you need the objects to be different, you must do something to create new object instances, like this:
public List<ChessField> Method(ChessField c)
{
var result = new List<ChessField>();
for (int i = 0;i<3;i++)
{
result.Add(new ChessField() {b1 = c.b1, b2 = c.b2, i1 = i});
}
return result;
}
or my preferred style would do this:
public IEnumerable<ChessField> Method(ChessField c)
{
return Enumerable.Range(0, 3)
.Select(i => new ChessField() {b1 = c.b1, b2 = c.b2, i1 = i});
}

Related

Backtracking algorithm - trying to find a better solution

I’d like to ask for a little bit of help with a project I’m currently working on, where I’m supposed to create a sort of “organizing program” using backtracking.
The story is, I have a given number of animals, each with their own type, habitat, and size as attributes. I’m also given a list of integers, which includes all the possible cage sizes these animals can be placed into. Of each cage size, I can create an infinite number of actual cages. Two (or more) animals can be kept in the same cage for as long as the sum of their size is less than or equal to that of the size of the cage, and they are either the same type (mammals for example) or share the same habitat (e.g. land).
My algorithm is supposed to sort them into cages so that at the end, I get a list of cages with all animals placed and using the fewest possible cages.
To illustrate, let’s say we have 3 animals, two cats (mammal, land, 3) and a vulture (bird, air, 4), and our possible cage sizes have been given as 3, 5, 7. Obviously, just by looking at this example, we can see that while the cats can be in the same cage, the vulture will inevitably land in its own, so the fewest possible cages to use is obviously going to be 2. This can either be {7: cat, cat; 5: vulture} or {7: cat, cat; 7: vulture}.
The way I had initially though of setting up my backtrack algorithm through recursion was the following:
N: total number of animals (in the above example, this would be 3
M: a list of numbers that can be used to create our cages (again, this would be three)
R: I was thinking of creating a list empty cages here, using the sizes that were given, but for now I just straight up used the integers
E: the current cycle’s solution
OPT: the best possible scenario so far, whenever a cycle’s E contains fewer cages than the OPT, that gets saved as the new OPT.
two levels of check
f1: to check if the given animal can fit in the given cage, if it is empty
f2: to check if the given animal could fit in any of the previous cages, given that there is still enough room and that it can be placed in the same cage with all other animals.
This way, the algorithm would first take an animal, and go through all available cage sizes, checking first if they can fit by themselves, and if yes, it’ll also check whether it could be placed in a previous cage. If it can’t, it’ll create a new cage and add the animal, then add the cage to E, but if it can be placed into a previous cage, it will do as much.
Obviously, this isn’t working just quite right. I asked my TA for some help, and he suggested I instead consider the following:
N: number of animals
M: N minus level, meaning that as I move more and more inward, I would have eliminated the need to place a certain number of animals. So for example, on the first level, I still need to place 3 animals, while on the second level only 2, and on the final level only 1.
R: Animals in cages (? I didn’t quite understand what he meant here, and his deeper explanations were of no help either)
E: list of cages, same as above
f1: to check whether the animal could be placed in the given cage, and whether it can be kept together with all other animals already in it
f2: to check whether it could have been placed in any of the other cages we put together
Now, as I said, I currently can’t fully grasp his solution, and although mine does work to a certain extent it does have its flaws (for example, it only checks for the first possible cage an animal could be placed into, without checking all other possibilities).
I’m gonna copy my code here, which currently looks like this, but honestly I’m more looking for some help in finding (and/or comprehending) a better solution.
Sorry this got so long-winded, I might be overthinking/overexplaining this but I'm feeling pretty desperate at this stage haha. Any help would be GREATLY appreciated!
public virtual void Trial(int level, ref CageList<Cage> E, ref CageList<Cage> OPT, ref bool found)
{
int i = -1;
while (i < M[level]-1)
{
i++;
ListObj<int> R_obj = R.FindIndex(i);
if (f1(szint, R_obj))
{
int k = 0;
if (E.head == null)
{
AddFirsttoE(level, R_obj, ref E);
}
else
{
while (k < E.Count() && !f2(level, E.FindIndex(k), k, ref E, R_obj))
{
k++;
}
}
if (level == N - 1)
{
if(!found || E.Count() < OPT.Count())
{
OPT = E;
}
found = true;
}
else
{
Trial(level + 1, ref E, ref OPT, ref found);
}
}
freeE(level, ref E);
}
}
while my two other functions are:
public override bool f1(int level, ListObj<int> obj)
{
bool ret = false;
ListaObj<Animal> test = Animals.FindIndex(level);
if (((int)test.Content.Size).CompareTo(obj.Content) <= 0)
{
ret = true;
}
return ret;
}
public override bool f2(int level, ListObj<Cage> obj, int level2, ref CageList<Cage> E, ListObj<int> empty_size)
{
bool ret = false;
ListObj<Animal> test = Animals.FindIndex(level);
bool can_keep_together = true;
if (((int)test.Content.Size).CompareTo(obj.Content.CageSize) <= 0)
{
AnimalList<Animal> caged = obj.Content.Animals;
ListObj<Animal> p = caged.head;
while (p != null && can_keep_together)
{
if (!p.Content.CanKeepTogether(test.Content))
{
can_keep_together = false;
}
p = p.Next;
}
if (can_keep_together)
{
ret = true;
obj.Content.Animals.Add(test.Content);
obj.Content.CageSize -= (int)test.Content.Size;
}
}
else if (level2 == E.Count() - 1)
{
ret = true;
AnimalList<Animal> new_animal_list = new AnimalList<Animal>();
new_animal_list.Add(test.Content);
Cage new_cage = new Cage(empty_size.Content, new_animal_list);
new_cage.CageSize -= (int)test.Content.Méret;
E.Add(new_cage);
}
if (!can_keep_together && level2 == E.Count()-1)
{
ret = true;
AnimalList<Animal> new_animal_list = new AnimalList<Animal>();
new_animal_list.Add(test.Content);
Cage new_cage = new Cage(empty_size.Content, new_animal_list);
new_cage.CageSize -= (int)test.Content.Méret;
E.Add(new_cage);
}
return ret;
}

Convert user entered string into an object in c#

I have a battleship like terminal game, the user enters a coordinate like e2, and the program checks one of the instance variables of my object Box, it checks whether hasShip is true, if its true then it will make the coordinate e2 false, and give the output "Ship destroyed"
The problem is that all my objects are called a1,a2,a3,a4,a5,b1,b2 and so on.
I have created 25 instances of the Box class. All names as such.
Once the program gets input, either e4 ,e5 etc. I want to convert that string into an object.
For example( I want to do something like this )
target = Console.ReadLine();
target.hasShip == true;
I want to convert target into an object, then use target to use the methods of the Box class.
Because the other approach requires me to make loads of if statements, which isn't clean code, doesn't look good, and is a waste if you ask me.
Thanks in advance,
New Answer: use an Array
I am slow. I did not pay attention that you are making a battleship-like game, and that we know that the "boxes" make a rectangle. We can store this efficiently in an array.
Why I did not catch up to this fact earlier? I guess I need to wake up properly.
So, use an array:
var board = new Box[5, 5];
Now, to populate it, we can do a double for loop:
for(var indexRow = 0; indexRow < 5; indexRow++)
{
for(var indexCol = 0; indexCol < 5; indexCol++)
{
board[indexRow, indexCol] = new Box();
}
}
Note: pay attention that the indexes go from 0 to 4. For a total of 5 values: {0, 1, 2, 3, 5}.
And to query from it, we will need the indexes...
Addendum on populating the array
In comments, OP has said that each Box has an id and the ship positions are picked at random.
We can give the id in the loop:
for(var indexRow = 0; indexRow < 5; indexRow++)
{
for(var indexCol = 0; indexCol < 5; indexCol++)
{
var box = new Box();
box.vhID = (((char)(((int)'a') + indexRow))).ToString() + ((char)(((int)'1') + indexCol)).ToString();
board[indexRow, indexCol] = box;
}
}
What I am doing here is constructing the id from the indexes. Basically taking the value of 'a' and adding the indexRow will give us 'a' when indexRow is 0, 'b' when it is 1 and so on. Similarly, we get the digit that represents the column.
Note: We convert the char to int, do the addition, then convert back to char... and then from char to string. Once we have string, we can concatenate them.
I do not think we need this id. But, hey, you can do it like this.
OP also mentions that he will pick 4 ship positions at random. Fair enough:
var random = new Random();
for (var ships = 0; ships < 4; ships++)
{
board[random.Next(0, 4), random.Next(0, 4)].hasShip = true;
}
Since the user inputs an string, I suggest to create a function to convert it to the index pair:
var input = Console.ReadLine();
if (TryGetCoordinates(input, out int irow, out int icol))
{
var target = board[irow, icol];
}
else
{
Console.WriteLine("The cell {0} does not exist.", input);
}
// ...
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
// ...
}
Start by validating null:
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
indexRow = -1;
indexCol = -1;
if (cell == null)
{
return false;
}
// ...
}
Note: Feel free to use Trim, ToUpper or ToUpperInvariant.
We know that must be a letter followed by a digit, we can validate the length:
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
indexRow = -1;
indexCol = -1;
if (cell == null)
{
return false;
}
if (cell.Length != 2)
{
return false;
}
// ...
}
We extract the characters and from them the coordinates. Noting that the first one is a letter, and the other a digit. We can also validate they are withing bounds.
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
indexRow = -1;
indexCol = -1;
if (cell == null)
{
return false;
}
if (cell.Length != 2)
{
return false;
}
indexRow = (int)cell[0] - (int)'a';
indexCol = (int)cell[1] - (int)'1';
return indexRow < 5 && indexRow >= 0 && indexCol < 5 && indexCol >= 0;
}
And of course, you can do a loop of the validation similar to what was explained in the old answer.
Note: the issue with value types I describe in the old answer still applies with the array.
Old Answer: Use a Dictionary
I believe you do not want to convert the string to an object (the string is an object by the way), you want to pick the Box object you previously created based on the string. And you want to do it without using if statements. What you need is a dictionary.
So, you would have Dictionary<string, Box> meaning that it is a dictionary that you can query by string and stores Box.
Addendums:
In this case, string is the key type, by which we will access the dictionary. When we add an object to the dictionary we identify it with a key, and when we retrieve it, we also use the key. The key does not have to be string, you can choose a different type. string is convenient in this case because it is what you get from Console.ReadLine().
You can create the dictionary to store whatever type you need. If you do not need Box, you can create a dictionary that stores something else.
Creating and populating the Dictionary
Then, you add to the Dictionary all your Box objects, like this:
var dict = new Dictionary<string, Box>();
// ...
dict.Add("a1", CreateBoxA1());
Where CreateBoxA1 represents whatever means you have to create the object. No, you do not need to create a method for each Box... you can do it like this:
dict.Add("a1", new Box());
Or whatever. I do not know how you create them, so consider that a placeholder, ok? ok.
Querying and retrieving values from the Dictionary
Once you have all your Box instances in your dictionary, you can get the one you need using the string:
Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
var target = dict[name];
Addendum: The value you get from dict[name] is the value that you added to the dictionary with that key. So, if the user typed "a1" it dict[name] will be the value that we added with "a1" (dict.Add("a1", new Box());). Again, if what you need is not Box you can create a dictionary to store a different type.
Input validation
You can also use the Dictionary to validate if the string corresponds to a Box that exists, for example:
Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
if (dict.KeyExists(name))
{
var target = dict[name];
// ...
}
else
{
Console.WriteLine("The Box {0} does not exist", name);
}
It goes without saying, but... you can make a loop based on that, for example:
Box target = null;
while(true)
{
Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
if (dict.KeyExists(name))
{
target = dict[name];
break;
}
Console.WriteLine("The Box {0} does not exist", name);
}
Also, it goes without saying, but... you can add your own validations and sanitation steps. For example using ToUpper, ToUpperInvariant or Trim. And I would remind you that changing strings to lower or upper case is culture sensitive.
See also: Best Practices for Using Strings in .NET.
Editing an removing objects from the dictionary
Once you have the object you retrieved from the Dictionary...
var target = dict[name];
We can use it, and even modify it:
var target = dict[name];
if (target.hasShip) // no need for "== true" if hasShip bool
{
target.hasShip = false;
Console.WriteLine("Ship Destroyed");
}
An special note must be done if Box is value type. For a custom type that means that it is not a class but a struct. The problem with value types is that they are copied on assignment, meaning that when you do var target = dict[name]; with a value type, you get a copy. You must then update the dictionary once you manipulated it:
var target = dict[name];
if (target.hasShip) // no need for "== true" if hasShip bool
{
target.hasShip = false;
dict[name] = target;
Console.WriteLine("Ship Destroyed");
}
Note: As I said above, this is only needed for value types.
And you can even remove the Box from the dictionary if that is necesary:
dict.Remove(name);

C# - Object variable assignment failing

I'm having some trouble understanding why my variable has a null value.
Here's my class constructor:
private GraphNode current;
private GraphNode goal;
private GraphNode start;
private List<GraphNode> path;
private List<GraphNode> origin;
public Graph()
{
current = new GraphNode(0, 0);
goal = new GraphNode(0, 0);
start = new GraphNode(0, 0);
path = new List<GraphNode>();
origin = new List<GraphNode>();
}
Defenition of method SetPathing:
public void SetPathing(int mouseX, int mouseY)
{
if (Contains((int)mouseX / 32, (int)mouseY / 32))
{
goal = GetNode((int)mouseX / 32, (int)mouseY / 32);
current = goal;
path.Add(current);
while ((current.X != start.X) && (current.X != start.X))
{
current = origin.Where(keyValuePair => (keyValuePair.Key.X == current.X) && (keyValuePair.Key.X == current.Y)).Select(keyValuePair => keyValuePair.Value).LastOrDefault();
path.Add(current);
}
}
}
When I break on the start of the while-loop in SetPathing I see the following info in the locals screen:
current null PathFinding.GraphNode
goal {PathFinding.GraphNode} PathFinding.GraphNode
X 0 int
x 0 int
Y 5 int
y 5 int
How is that possible after having clearly assigned the reference value of goal to current?
I'm probably missing something stupid here, but I haven't found it after looking for two hours. No asynchronous going on here.
EDIT: Didn't want to be overtly verbose with my initial question, here's some extra details, my apologies. Here are the details of Contains, GetNode and GetNodeIndex. Nothing fancy, I'm an amateur.
public int GetNodeIndex(int x, int y)
{
// Find the node index in the list based on x and y
// Return -1 if not found
return nodes.FindIndex(n => (n.X == x) && (n.Y == y));
}
public GraphNode GetNode(int x, int y)
{
// Find the node in the list based on x and y
// Return null if not in list
int nodeIndex = GetNodeIndex(x, y);
if (nodeIndex != -1)
{
return nodes[nodeIndex];
}
return null;
}
public bool Contains(int x, int y)
{
// Check if the returned value is not -1
if (GetNodeIndex(x, y) != -1)
{
return true;
}
}
The usecase is litterally just along the lines of the following:
using System;
namespace Graphs
{
class Program
{
static void Main()
{
Graph graph = new Graph(20, 20);
graph.SetPathing(Mouse.GetState().X, Mouse.GetState().Y);
}
}
}
Let's dissect your code here.
goal = GetNode((int)mouseX / 32, (int)mouseY / 32);
Here, you've set the variable goal to point to a GraphNode object. So, for the sake of simplicity, we'll call it A. At this point your values look like this:
goal -> A
current -> null
Next, you do this:
current = goal;
And now, your values look like this:
goal -> A
current -> A
Later during your while loop, you call this:
current = origin.Where(keyValuePair => (keyValuePair.Key.X == current.X) && (keyValuePair.Key.X == current.Y)).Select(keyValuePair => keyValuePair.Value).LastOrDefault();
For the sake of simplicity, we'll call the result of this where clause B. So, now your values look like this:
goal -> A
current -> B
All that you have done here is change current to point to a new value.
You showed the code for the default Graph constructor,
public Graph()
not the one being used.
Graph graph = new Graph(20, 20);
Is there any difference between them?
Also, are you sure your code is in sync with the assembly? i.e. from your description it seems your break point is on this line
while ((current.X != start.X) && (current.X != start.X))
Are you sure when you were debugging, it was indeed executing only upto here when the debugger stopped, or it could have already executed the filtering code two lines down?
I'm not sure how this is possible, but the answer appears to be that this is in fact not the first iteration of the While-loop.
I had my break point set to the loop, and the results I posted above were from the first hit of that break point. However, after adding a variable that acted as an iteration counter it turned out this was in fact NOT the first iteration, but the third one. Following this discovery I went on to improve the code in the while loop to prevent current being set to null.
I'm not sure how this could happen. I'm using Visual Studio 2013 Express for Desktop. Never encountered anything like this before.

XNA game items drag and drop — how to implement object exchange?

I'm making an inventory system and I'm stuck at the part where the items should be moved from cell to cell by simple drag'n'dropping.
There is an Item[,] Inventory array which holds the items, object fromCell, toCell which should hold the references to cells to operate with when mouse button is released, but when I try doing this:
object temp = toCell;
toCell = fromCell;
fromCell = temp;
...the game is only swapping object references and not the actual objects. How do I make this work?
UPD: Thanks to Bartosz I figured this out. Turns out you can safely use a reference to array of objects and change it with saved indices of objects you wish to swap.
Code can be like this:
object fromArray, toArray;
int fromX, fromY, toX, toY;
// this is where game things happen
void SwapMethod()
{
object temp = ((object[,])toArray)[toX, toY];
((object[,])toArray)[toX, toY] = ((object[,])fromArray)[fromX, fromY];
((object[,])fromArray)[fromX, fromY] = temp;
}
How about this?
internal static void Swap<T>(ref T one, ref T two)
{
T temp = two;
two = one;
one = temp;
}
And all your swapping becomes this.
Swap(Inventory[fromCell], Inventory[toCell]);
Also, you can add the extension for the arrays (if more confortable).
public static void Swap(this Array a, int indexOne, int indexTwo)
{
if (a == null)
throw new NullReferenceException(...);
if (indexOne < 0 | indexOne >= a.Length)
throw new ArgumentOutOfRangeException(...);
if (indexTwo < 0 | indexTwo >= a.Length)
throw new ArgumentOutOfRangeException(...);
Swap(a[indexOne], a[indexTwo]);
}
To use it like so:
Inventory.Swap(fromCell, toCell);
Why not using indexes to your Inventory array: int fromCell, toCell.
var temp = Inventory[toCell];
Inventory[toCell] = fromCell;
Inventory[fromCell] = temp;
You're modeling inventory as 2D array of slots, so it seems fairly safe to use indexes to access it.

KeyNotFound Exception in Dictionary(of T)

I'm about ready to bang my head against the wall
I have a class called Map which has a dictionary called tiles.
class Map
{
public Dictionary<Location, Tile> tiles = new Dictionary<Location, Tile>();
public Size mapSize;
public Map(Size size)
{
this.mapSize = size;
}
//etc...
I fill this dictionary temporarily to test some things..
public void FillTemp(Dictionary<int, Item> itemInfo)
{
Random r = new Random();
for(int i =0; i < mapSize.Width; i++)
{
for(int j=0; j<mapSize.Height; j++)
{
Location temp = new Location(i, j, 0);
int rint = r.Next(0, (itemInfo.Count - 1));
Tile t = new Tile(new Item(rint, rint));
tiles[temp] = t;
}
}
}
and in my main program code
Map m = new Map(10, 10);
m.FillTemp(iInfo);
Tile t = m.GetTile(new Location(2, 2, 0)); //The problem line
now, if I add a breakpoint in my code, I can clearly see that my instance (m) of the map class is filled with pairs via the function above, but when I try to access a value with the GetTile function:
public Tile GetTile(Location location)
{
if(this.tiles.ContainsKey(location))
{
return this.tiles[location];
}
else
{
return null;
}
}
it ALWAYS returns null. Again, if I view inside the Map object and find the Location key where x=2,y=2,z=0 , I clearly see the value being a Tile that FillTemp generated..
Why is it doing this? I've had no problems with a Dictionary such as this so far. I have no idea why it's returning null. and again, when debugging, I can CLEARLY see that the Map instance contains the Location key it says it does not...
very frustrating.
Any clues? Need any more info?
Help would be greatly appreciated :)
You don't show what 'Location' is but this is normal behavior if it is a class: objects are tested for Equality by comparing the references. So different instances of Location will always be unequal, even if their content is the same.
The quickest fix is to override Equals() and GetHashCode() for the Location class. And then it is a good idea to (re)design it as an immutable class (or maybe immutable struct).
Henk is correct; when you test to see if two objects are equal in .Net, you're actually asking if "reference x is pointing to the same object as reference y".
So, by default:
Location a = new Location(2, 2, 0);
Location b = new Location(2, 2, 0);
Location c = a;
bool notEqual = ( a == b ); // false
bool equal = ( a == c ); // true
To get around this, you need to override the equality methods for your Location object to compare the values for equality - the body of your Equals method, for example, might end us as something like:
return (this.x == that.x && this.y == that.y && this.z == that.z);
Thank you everyone! I really appreciate it!
I made Location into a value type and now it's working just fine.
I'm sorry for not posting the whole code, but I didn't feel it was necessary and assumed that the reader could assume that location was a simple class with x,y,z int values.
I learned many new things because of all of you and my understanding of this (generally) wonderful language is greater because of it :o)
Take care,

Categories

Resources