How to let a stack store coordinates on a board - c#

I was writing a stack that can store row and column which a user inputs through textboxes on windows forms. However when I use the code I added when you press a button it doesn't work.
Stack mystack = new Stack();
Stack.Push(Row,Column);
The error I get is "No overload for method push takes 2 arguments". How can I correct my code so it adds the row and column to the stack everytime the user presses the button.

A Stack stores a list of objects, not a list of pairs of objects. You can only add one object at a time. If you want to store a row and column as a single value then you need to use a type that can store those two values. You could define your own type but you may as well just use the existing Point type. You should also use a generic Stack<T>, just as you would use a List<T> rather than an ArrayList.
var points = new Stack<Point>();
points.Push(new Point(column, row));
Note the order of the column and row values, because the first value should be the X (horizontal) value and the second should be the Y (vertical) value.
When you Pop, you'll get a Point value and you can then get the X and Y values from that.

You can have a class called coordinate as follows:
public class coordinate
{
public coordinate(double _x, double _y)
{
this.x = _x;
this.y = _y;
}
public double x;
public double y;
}
And define the stack as below:
Stack<coordinate> mystack = new Stack<coordinate>();
mystack.Push( new coordinate(1,1));

Related

c#: Dictionary TryGetValue creating instance instead of getting reference

I'm a total noob with c#, and cannot figure out why the same method works in different ways. I'm making a simple spreadsheet application, and am using a Dictionary of cells, where the key is a string name and the value is a Cell object:
public struct Cell
{
private string Name { get; }
public Object Content { get; set; }
public Cell(string n, Object o)
{
Name = n;
Content = o;
}
}
Now, I'll need to be able to easily add/change the contents of the cell, so I've been doing this:
Dictionary<string, Cell> cells = new Dictionary<string, Cell>();
// Assign new cell to 5.0 & print
cells.Add("a1", new Cell("a1", 5.0));
Console.WriteLine(cells["a1"].Content); // Writes 5
// Assign cell to new content & print
cells.TryGetValue("a1", out Cell value);
value.Content = 10.0;
Console.WriteLine(cells["a1"].Content); // Writes 5
Console.ReadKey();
Of course, the dictionary creates the new cell just fine, but when I use TryGetValue, the new content for the cell doesn't make it to the actual object I'm trying to get. I was expecting the second print to be 10. In debug, it seems like it instantiates a new Cell instead of getting the reference of the cell at hand.
I've used a Dictionary before, and I've used TryGetValue to change properties of the existing object. So here's two questions: What am I doing wrong in this case, and what factors determine if the method returns a reference or not?
Cell is a struct. It is not recommended that you use a struct for objects that can be modified. I think you just found out why.
When TryGetValue returns the struct, it copies it into a value, which is a different struct than the one in the Dictionary.
Imagine if you replaced struct by int - another value type - would you expect assigning to the int from TryGetValue to change the Dictionary entry int?
If other constraints require you use a struct, you will need to update the cells Dictionary with the new struct, just as you would with any other value type:
Dictionary<string, Cell> cells = new Dictionary<string, Cell>();
// Assign new cell to 5.0 & print
cells.Add("a1", new Cell("a1", 5.0));
Console.WriteLine(cells["a1"].Content); // Writes 5
// Assign cell to new content & print
cells.TryGetValue("a1", out Cell value);
value.Content = 10.0;
cells["a1"] = value; // update cells Dictionary
Console.WriteLine(cells["a1"].Content); // Writes 5
Console.ReadKey();
You need to make your struct Cell into a class Cell.
That's because struct is a value type and it's content can't be changed by reference.
If you want to go in detail, you can read about difference of value and reference types here.

Serializing a dictionary in C#

I have a class named serializableVector2:
[Serializable]
class serializableVector2
{
public float x, y;
public serializableVector2(int x, int y)
{
this.x = x;
this.y = y;
}
}
and I have a struct named savedMapTile:
[Serializable]
struct savedMapTile
{
public oreInstance ore;
public int backgroundTileId;
public int playerId;
public tree tree;
}
and I have a dictionary using these two classes:
[SerializeField]
Dictionary<serializableVector2, savedMapTile> savedTiles;
I am trying to load this dictionary modify it, and then save it again all using serialization.
I am deserializing the dictionary like so:
FileStream f = File.Open(saveFileName, FileMode.Open);
BinaryFormatter b = new BinaryFormatter();
savedTiles = (Dictionary<serializableVector2, savedMapTile>)b.Deserialize(f);
f.Close();
and I am serializing it like so:
FileStream f = File.Open(saveFileName, FileMode.Create);
BinaryFormatter b = new BinaryFormatter();
b.Serialize(f, savedTiles);
f.Close();
However, when I try to access an element in the dictionary that I know should exist I get the following error:
System.Collections.Generic.KeyNotFoundException: The given key was not
present in the dictionary.
I get this error from running this code:
id = (savedTiles[new serializableVector2(-19,13)].backgroundTileId);
What I find really strange is that I am able to print out the entirety of the dictionaries keys and its values as well. This is where I am getting the values -19 and 13 for the Vector2. I print the keys and values like so:
for (int i = 0; i < 100; i++ )
{
UnityEngine.Debug.Log(vv[i].x +" "+vv[i].y);
UnityEngine.Debug.Log(x[i].backgroundTileId);
}
At this point I'm really stumped, I have no clue what is going on. I can see the file being saved in windows explorer, I can access keys and values in the dictionary, but I cant seem to use it properly. It is also important to note that when I use the .Contains() method on the dictionary in a similar way to how I am trying to access a value, it always returns false.
This is for a Unity 5 project, using C# in visual studio running on windows 8.1.
Change your serializableVector2 from a class to a struct and you should be able to find things in your dictionary. Someone may correct me if I have this wrong, but to the best of my knowledge the Dictionary is going to call GetHashCode on the key and use that code to store the item in the dictionary. If you create two instances of your class with the same x and y coordinates and call GetHashCode you will see that two instances yield different hash codes. If you change it to a struct than they will produce the same hash code. I believe this is what is causing you to get the "Key not found" issues. On a somewhat related note, it does seem strange that the constructor takes int for the x and y and then stores them as floats. You may want to consider changing the constructor to take float.
[Serializable]
struct serializableVector2
{
public float x, y;
public serializableVector2(float x, float y)
{
this.x = x;
this.y = y;
}
}
You have two issues:
Your dictionary key serializableVector2 is a class relying on the default equality and hashing methods. The defaults use reference equality such that only variables pointing to the same object will be equal and return the same hash.
If that were not the case you would still be relying on floating point equality. Unless your serialised can guarantee precise storage and retrieval of floating point values the deserialised serializableVector2 may NOT be equal to the original.
Suggested solution:
Override GetHashCode and Equals for your serializableVector2 class. When performing comparisons and hashing round your floats to within 32-bit floating point precision of your expected range of values. You can rely on 6+ significant digits of precision (within the same range) so if your world is += 1000 units I believe you can safely round to 3 decimal points.
Example for GetHashCode (without testing):
public override int GetHashCode() {
return Math.Round(x,3).GetHashCode() ^ Math.Round(y,3).GetHashCode();
}

Is the order of member initializers in an object initializer deterministic? [duplicate]

Does the order in which I set properties using the object initializer syntax get executed in the exact same order?
For instance if I do this:
var s = new Person { FirstName = "Micah",
LastName = "Martin",
IsLoaded = true
}
will each property get set in the same order?
Yes.
Apologies for getting interrupted (I have to actually do some work every so often). The spec doesn't explicitly say it, but it makes it pretty clear IMO in section 7.6.10.2:
An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas.
(Note the word "sequence" here, rather than "set". I personally think that's significant, as a sequence is ordered.)
The following class represents a point with two coordinates:
public class Point
{
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
An instance of Point can be created and initialized as follows:
Point a = new Point { X = 0, Y = 1 };
which has the same effect as
Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;
where __a is an otherwise invisible and inaccessible temporary variable.
EDIT: I've had a response from Mads Torgersen, who has basically said that anything which can be done now will preserve the order. There may be some oddities in future where the order is not preserved in weird cases where you're doing something other than setting a property/field, but that will depend on where the language goes.
It's worth pointing out that there are actually lots of steps going on here - there's the order of execution of the evaluation of the arguments (i.e. the RHS bits) and the order of execution of the assignments. For example, if you have:
new Foo
{
A = X,
B = Y
}
all the following orders are possible while still maintaining the order of the actual property execution (A and B):
Evaluate X, assign to A, evaluate Y, assign to B
Evaluate X, evaluate Y, assign to A, assign to B
Evaluate Y, evaluate X, assign to A, assign to B
I believe the first option is the one actually taken, but this was just to demonstrate that there's more to it than meets the eye.
I would also be very wary of actually writing code which depends on this...

object initializer execution order [duplicate]

Does the order in which I set properties using the object initializer syntax get executed in the exact same order?
For instance if I do this:
var s = new Person { FirstName = "Micah",
LastName = "Martin",
IsLoaded = true
}
will each property get set in the same order?
Yes.
Apologies for getting interrupted (I have to actually do some work every so often). The spec doesn't explicitly say it, but it makes it pretty clear IMO in section 7.6.10.2:
An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas.
(Note the word "sequence" here, rather than "set". I personally think that's significant, as a sequence is ordered.)
The following class represents a point with two coordinates:
public class Point
{
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
An instance of Point can be created and initialized as follows:
Point a = new Point { X = 0, Y = 1 };
which has the same effect as
Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;
where __a is an otherwise invisible and inaccessible temporary variable.
EDIT: I've had a response from Mads Torgersen, who has basically said that anything which can be done now will preserve the order. There may be some oddities in future where the order is not preserved in weird cases where you're doing something other than setting a property/field, but that will depend on where the language goes.
It's worth pointing out that there are actually lots of steps going on here - there's the order of execution of the evaluation of the arguments (i.e. the RHS bits) and the order of execution of the assignments. For example, if you have:
new Foo
{
A = X,
B = Y
}
all the following orders are possible while still maintaining the order of the actual property execution (A and B):
Evaluate X, assign to A, evaluate Y, assign to B
Evaluate X, evaluate Y, assign to A, assign to B
Evaluate Y, evaluate X, assign to A, assign to B
I believe the first option is the one actually taken, but this was just to demonstrate that there's more to it than meets the eye.
I would also be very wary of actually writing code which depends on this...

Add ints to listview for sorting

I have a listview and I am trying to sort it based on a column. I have the columnclick event etc working, and it sorts, but I have the following problem:
I can't seem to add items to the listview as integers. This is a problem as if I have a column of ints that I had to use ToString() on, the sort puts 10 ahead of 2.
Does anyone know how I can add items as int's so that the sort has the desired functionality. Also, not all columns are int, there are some string columns and I'd like the sort to work on those too.
For reference, I used the following tutorial for the sort code: http://support.microsoft.com/kb/319401
Cheers
You can create a sorter class that implements IComparer and assign it to the ListViewItemSorter property of the ListView.
IComparer has a method Compare. Two ListViewItem instances are passed to that method. You need to read the column value, then parse it to int and return the correct comparison result (int based instead of string based).
You can create your own ListViewItem class that creates the string value for the column but also holds the original int value to avoid the int.Parse call in the comparer.
Untested example:
public class MyItemComparer : IComparer
{
public int Compare(object x, object y)
{
ListViewItem xItem = (ListViewItem)x;
ListViewItem yItem = (ListViewItem)y;
int a = int.Parse(xItem.SubItems[0]);
int b = int.Parse(yItem.SubItems[0]);
return a.CompareTo(b);
}
}
You can detect if the selected column has numbers.
Write this in the compare function
int intX = 0, intY = 0;
if(int.TryParse(listviewX.SubItems[ColumnToSort].Text, out intX)
&& int.TryParse(listviewY.SubItems[ColumnToSort].Text, out intY))
{
return intX.CompareTo(inty);
}
Maybe is problem if some column contains numbers and text.

Categories