List elements are dependant from each other - c#

For some reason, elements in my list(Maps = new List<CollisionTiles>[]) are dependant from each other. This list contains information about collision tiles in my game. The problem is, when I set list elements in Map list to Maps[Something], Maps list is changing too, whenever I do anything with Map after assignation.
if (mapClass.Maps[3].Count != 0)
{
mapClass.ClearMap(); // CollisionTiles.Clear(); BackGroundTiles.Clear();
mapClass.CollisionTiles = mapClass.Maps[3];
mapClass.BackgroudTiles = mapClass.SpriteMaps[3];
}
if (mapClass.Maps[3].Count == 0)
{
mapClass.GenerateCustomMap(64, 10, 8, 3, false);
}

Really difficult to say from the code you've posted but based on your description you might be copying a "reference" to a collection when you intended to copy the collection itself.
For example, let's say to have a list called a and you try to make a another list called b like this:
var a = new List<string>();
var b = a;
What the above code is actually doing is making a and b a "reference" to the same list.
In other words, if you then did something like this:
b.Add("item");
Now both of the "lists" called a and b will have the same items in them. That's because they are not actually different lists, they are the same list with two "pointers".
There's a couple of different ways you can correctly copy of a list in C#. One way is to pass the list into the constructor like this:
var a = new List<string>();
a.Add("item");
var b = new List<string>(a);
This will give you two separate lists with that both have an item in them. However, now when you modify either of those lists they won't change together.
A popular (more modern) alternative approach for the code above can be done by using System.Linq namespace.
var a = new List<string>();
a.Add("item");
var b = a.ToList();
I hope that helps.

You are setting mapClass.CollisionTiles to reference to the original List.
Therefore, any modifications to the mapClass.CollisionTiles changes the original List as well. The same goes for BackgroundTiles.
To correct this, create new List objects when assigning them to the mapClass:
if (mapClass.Maps[3].Count != 0)
{
mapClass.ClearMap(); // CollisionTiles.Clear(); BackGroundTiles.Clear();
mapClass.CollisionTiles = new List<CollisionTiles>(mapClass.Maps[3]);
mapClass.BackgroudTiles = new List<BackgroudTiles>(mapClass.SpriteMaps[3]);
}
else // this is the only other option from the above if
{
mapClass.GenerateCustomMap(64, 10, 8, 3, false);
}
Please note, I have left the misspelling of BackgroudTiles, please correct as necessary.

Related

Declare Instance of Class with Dynamic Name

So I have created a Class called SnakeItem, I want to create a new instance of the snake item when the snake grows, they follow a naming convention of snake_Piece_[NUMBER]. There is already snake_Piece_0 and I want to declare a new instance in the code. I'm not sure how to put it...
SnakeItem snake_Piece_0;
public game_Window()
{
InitializeComponent();
snake_Piece_0 = new SnakeItem(Resource1.Black, 0, 0);
}
Then in this function, I want to create it. (after snake_length++:) I need to name to increment so it follows the snake_length Variable. i.e. if snake_length = 1 then it will create a piece with the name snake_Piece_1.
private void fruit_Collision()
{
if (snake_Piece_0.Top == Fruit_Item.Top && snake_Piece_0.Left == Fruit_Item.Left)
{
snake_Length++;
}
}
I'm not sure what I can say if it's not possible I would have to declare all 400 snake pieces beforehand which is what I'm trying to avoid.
This is a common thing that beginners do - trying to dynamically create new variables with new names. I tried to do this too, until I learned about Lists.
Lists are objects that can store a variable number of objects. Here is how you can create an empty list of SnakeItem:
List<SnakeItem> snakeItems = new List<SnakeItem>();
You can add, access, and delete items in the list. Here are some examples:
snakeItems.Add(new SnakeItem(Resource1.Black, 0, 0)); // add a new item to the list
snakeItems[0] // access the first item in the list. 0 is the first, 1 is the second, etc.
snakeItems.RemoveAt(0) // remove the first item of the list
Basically, whenever you want to create a new "variable name", just Add a new item to the list:
if (snakeItems[0].Top == Fruit_Item.Top && snakeItems[0].Left == Fruit_Item.Left)
{
snakeItems.Add(...);
}
As you can see, snake_Length is not needed any more! You can access how many snake items there are using .Count. Replace all the snake_Length with snakeItems.Count.
Learn more about lists here.

C# List RemoveAt(0)

I have a list and want to iterate smoothly through it while removing one element after another. I thought I could do it like this:
List<Point> open = new List<Point>();
...
while (!(open == null))
{
Point p = open.RemoveAt(0);
...
However, it is not quite working how I would like it to, starting with "Cannot implicitly convert type 'void' to 'Point'". But shouldn't the call of RemoveAt give the point to P before removing it/making it void?
List.RemoveAt does not return item which you are removing. Also list will not become null when you'll remove all items. It will become empty, i.e. with Count equal to 0. I would suggest you to use Queue<T> instead of List<T>. Thus you will be able to remove fist added item and get it at same time:
Queue<Point> open = new Queue<Point>();
while(open.Count > 0)
{
var point = open.Dequeue();
// ...
}
If you want to use list, and remove first items, then you should retrieve item by index, and only then remove it from list:
List<Point> open = new List<Point>();
while (open.Count > 0) // or open.Any()
{
Point p = open[0];
open.RemoveAt(0);
// ...
}
No, it does not. It does not return anything, as per the specification. Try using a Queue<Point> instead. Also, removing the first item in a List<T> does force a copy of the array-contents as far as I know (If somebody knows, please add relevant reference), so always avoid removing the first element in list and try to always find the best data structure to solve your particular issue!
Example:
var open = new Queue<Point>();
// ... Fill it
// Any() is in general faster than Count() for checking that collection has data
// It is a good practice to use it in general, although Count (the property) is as fast
// but not all enumerables has that one
while (open.Any()) {
Point p = open.Dequeue();
// ... Do stuff
}

nested hashset of lists?

I'm working on one of the project Euler problems, and I wanted to take the approach of creating a list of values, and adding the list to a Hashset, this way I could evaluate in constant time if the list already exists in the hashset, with the end goal to count the number of lists in the hashset for my end result.
The problem I'm having is when I create a list in this manner.
HashSet<List<int>> finalList = new HashSet<List<int>>();
List<int> candidate = new List<int>();
candidate.Add(5);
finalList.Add(candidate);
if (finalList.Contains(candidate) == false) finalList.Add(candidate);
candidate.Clear();
//try next value
Obviously the finalList[0] item is cleared when I clear the candidate and is not giving me the desired result. Is it possible to have a hashset of lists(of integers) like this? How would I ensure a new list is instantiated each time and added as a new item to the hashset, perhaps say in a for loop testing many values and possible list combinations?
Why don't you use a value which is unique for each list as a key or identifier? You could create a HashSet for your keys which will unlock your lists.
You can use a Dictionary instead. The only thing is you have to test to see if the Dictionary already has the list. This is easy to do, by creating a simple class that supports this need.
class TheSimpleListManager
{
private Dictionary<String, List<Int32>> Lists = new Dictionary<String, List<Int32>>();
public void AddList(String key, List<Int32> list)
{
if(!Lists.ContainsKey(key))
{
Lists.Add(key, list);
}
else
{
// list already exists....
}
}
}
This is just a quick sample of an approach.
To fix your clear issue: Since its an object reference, you would have to create a new List and add it to the HashSet.
You can create the new List by passing the old one into its constructor.
HashSet<List<int>> finalList = new HashSet<List<int>>();
List<int> candidate = new List<int>();
candidate.Add(5);
var newList = new List<int>(candidate);
finalList.Add(newList);
if (finalList.Contains(newList) == false) //Not required for HashSet
finalList.Add(newList);
candidate.Clear();
NOTE: HashSet internally does a contains before adding items. In otherwords, here even if you execute finalList.Add(newList); n times, it would add newList only once. Therefore it is not necessary to do a contains check.

How to properly replace objects in an array - C#

I am trying to remove an object from an array and fill the slot with an object of the same type but with 0s for all the properties. But when I do this the values do not clear for some reason when I recalculate the array values.
Here is how I am clearing an object out and inserting a blank one in its place.
public void clearOutBox(int arraySlot)
{
itemsInbuildArray.Remove(itemsArray[arraySlot]);
itemsInbuildArray.Insert(arraySlot, blank);
itemInBuildPictureArray[arraySlot].ImageLocation = null;
statCalculation();
}
//one of the lines from the statCalculation method.
statsHealth.Text = (Convert.ToString(itemsInbuildArray.Sum(hp => hp.Health)));
public partial class Form1 : Form
{
List<Item> itemsArray = new List<Item>();
List<PictureBox> itemInBuildPictureArray = new List<PictureBox>();
List<ToolTip> itemInBuildTooltipArray = new List<ToolTip>();
List<Item> itemsInbuildArray = new List<Item>();
Item blank = new Item(); // this is one of several objects created here
}
I initialize the array with 6 of these blank items in it and there are no problems replacing a blank item with one with values but removing it is whats causing me issues.
Please excuse the more than likely noobish ways I'm doing this, I am just starting C# and doing this project as a learning experience. Any input is appreciated!
Why not just index it directly:
int index = 5;
array[index] = new Foobar(); // whatever your class is
That is going to change whatever is referenced in the 6th slot in your array.
I would avoid using a single reference called "blank" and putting it into multiple array slots unless you know you will never modify them. If they are reference types then modifying one of them would modify them all.

Way to fill List<> with elements

I have in my code
List<BookedReelsState> retVal = new List<BookedReelsState>(somesize);
Match later in the code if some condition works I need to fill this entire List with same value.
Of course I can do it via foreach loop and set values , Is there more elegant way to do so ?
I just to learn something new here .
retVal.AddRange(Enumerable.Repeat(value, somesize));
retVal.ForEach(b => b.changedProp = newValue);
Two things here.
Firstly List<T>(int capacity) does not create a List with capacity items in it already. It just reserves memory for them. So the list in the example above will have it's length equals to 0.
But if you have a list and want to set each element of it, you can do it like this:
retVal.ForEach( rv => rv = desiredValue );
Where desiredValue is the value you want to set for each element.
I also find it strange that you want to fill every single element of a list with the same value. If all elements are the same the list serves no purpose, but I guess that you might need to fill with some default value up front, and then change some of them later on.
If you have an IEnumerable then you can use List.AddRange.
Example:
var list = new List<BookedReelsState>(20);
var someEnumerable = new []
{
new BookedReelsState(1),
new BookedReelsState(2),
new BookedReelsState(2)
};
list.AddRange(someEnumerable);

Categories

Resources