anderson14
anderson14

Reputation: 23

Retrieving and changing value in a multidimensional List

I'm trying to make a torpedo game in C# for homework. In this game I need a two dimensional array. It's size should be changeable at runtime so as far as I know I can't use a simple array. That's why I'm trying to use List<List<bool>> for this purpose.

I've tried to put everything in relation with the map to a class. This is the class I've made so far:

class Map {
    // Map properties
    public int Width;
    public int Height;
    public int Ships;

    // A clear map
    public List<List<bool>> ShipPos = new List<List<bool>>();

    // Constructor (width, height, num. of ships)
    public Map(int w, int h, int num) {
        Width = w; Height = h; Ships = num;
        List<bool> row = new List<bool>();
        for (int i = 0; i < w; i++) row.Add(false);
        for (int i = 0; i < h; i++) ShipPos.Add(row);
    }

    // Method for generating ships for the computer
    public void ComputerShips(ref Random r) {
        for (int i = 0; i < Ships; i++) {
            int x, y; bool reserved;
            do {
                x = r.Next(0, Width);
                y = r.Next(0, Height);
                reserved = ShipPos[x][y];
            } while (reserved);
            ShipPos[x][y] = true;
        }
    }
}

The problem seems to be in method ComputerShips(ref Random r) with the line ShipPos[x][y] = true. The expected behavior would be to set for example 6 random positions to true in the 2 dimensional array. But instead I get 6 random values from a row set to true, and all the rows become the same.

An example output: I expect something like this in a 8x8 map with 5 ships (0 = false, 1 = true):

0 0 0 0 0 0 0 0
0 1 0 0 0 0 1 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 1 0 0
0 0 0 0 0 0 0 0

But something like this happens:

0 1 1 0 1 1 1 0
0 1 1 0 1 1 1 0
0 1 1 0 1 1 1 0
0 1 1 0 1 1 1 0
0 1 1 0 1 1 1 0
0 1 1 0 1 1 1 0
0 1 1 0 1 1 1 0
0 1 1 0 1 1 1 0

Maybe I've spent too much time searching for the answer, but no success so far. I know (I think I know) how to get and set the value in a normal array. I would do something like array[i,j] to get, and array[i,j] = x to set the value of a 2 dimensional array element. In List<List<T>> I can do list[i][j] to get the value, and this seemed to work so far. But list[i][j] = x didn't work as I expected.

The question is: how could I set an element to true without changing the whole column? Maybe it's trivial but I'm fairly new to C# and google hasn't answered my question so far.

Sorry for writing an essay, I just tried to give enough details. I hope I didn't forget something important. I use Visual C# 2010 Express and Windows 7 (x64) if that counts.

Upvotes: 1

Views: 905

Answers (1)

Guffa
Guffa

Reputation: 700830

The problem is in your constructor.

You are creating a row, and then you are adding that row several times. That means that all rows are actually the same row.

You need to create a new list for each row:

public Map(int w, int h, int num) {
  Width = w; Height = h; Ships = num;
  for (int i = 0; i < h; i++) {
    List<bool> row = new List<bool>();
    for (int i = 0; i < w; i++) row.Add(false);
    ShipPos.Add(row);
  }
}

Side note: You don't need ref on the parameter to the ComputerShips method. You might use it to try to make the code faster, but it will actually make it somewhat slower, as there is another redirection for each access of the parameter.

Don't use ref or out parameters unless you actually need to change the variable sent in as parameter inside the method.

Upvotes: 2

Related Questions