Gewoo
Gewoo

Reputation: 457

List changes when I assign it to a variable c#

I came across a problem. I am trying to make a tic tac toe game where you can play against an ai. But it does not really care in this problem. The board is a 2D list witch looks like this:

[0, 1, 0]
[1, 2, 0]
[0, 2, 0]

0 is an empty spot
1 is player one (circle)
2 is player two (cross)

But I have a problem I need to iterate thru all the spots so I made this for loop.

List<List<int>> boardTry;
List<List<int>> board = new List<List<int>> { new List<int> { 0, 0, 0 }, new List<int> { 0, 0, 0, }, new List<int> { 0, 0, 0 } };

for (int rowNum = 0; rowNum < 3; rowNum ++)
            {
                for (int colNum = 0; colNum < 3; colNum++)
                {
                    // Check if spot is empty
                    if (board[rowNum][colNum] == 0)
                    {
                        boardTry = board;
                        showBoard(board);

                        boardTry[rowNum][colNum] = 2;
                    }
                }
            }

I created a method called showBoard to see how the list looked like.

void showBoard(List<List<int>> board)
        {
            StringBuilder sb = new StringBuilder();

            foreach (List<int> row in board)
            {
                sb.Append("[");
                foreach(int col in row)
                {
                    sb.Append(col.ToString() + " ");
                }
                sb.Append("]");
            }

            MessageBox.Show(sb.ToString(0, 8) + "\n" + sb.ToString(8, 8) + "\n" + sb.ToString(16, 8));

        }

But the problem is when I run this code is that the board list is changing with the boardTry. So each time I assign boardTry to board, board is getting equal to boardTry.

This is what I see when I run this code. enter image description here

Upvotes: 0

Views: 85

Answers (2)

user6438653
user6438653

Reputation:

Try this tic tac toe control (you can modify it):

using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;

public class TicTacToe : Panel
{
    public TicTacToe()
    {
        // You can change these properties.
        this.Size = new Size(281, 360);
        this.BackColor = Color.White;

        // Add the labels.
        this.Controls.AddRange(new Control[] { wins, losses, turn });

        // To generate random numbers for the A.I
        Random opponentPlay = new Random();

        // A.I turn
        opponentDelay.Tick += delegate
        {
            opponentDelay.Interval = 20;
            Point opponentPos = new Point(opponentPlay.Next(0, 3), opponentPlay.Next(0, 3));
            if (board[opponentPos.X][opponentPos.Y].Text.Length == 0)
            {
                board[opponentPos.X][opponentPos.Y].Text = "X";
                opponentDelay.Interval = 500;
                opponentDelay.Stop();
                UpdateGame();
            }
        };

        // Setup board.
        for (int x = 0; x < board.Count; x++)
        {
            for (int y = 0; y < board.Count; y++)
            {
                board[x][y].Location = new Point(4 + (x * 92), 4 + (y * 92));
                // Add player turn event.
                board[x][y].Click += delegate (object sender, EventArgs e)
                {
                    if (turn.Name == "1")
                    {
                        if (((Button)sender).Text.Length == 0)
                        {
                            ((Button)sender).Text = "0";
                            UpdateGame();
                        }
                    }
                };

                this.Controls.Add(board[x][y]);
            }
        }
    }

    // Check game for wins, losses, and draws.
    public void UpdateGame()
    {   
        // Check if player won.
        if (board[0][0].Text == "0" && board[1][0].Text == "0" && board[2][0].Text == "0")
            EndGame(0);
        else if (board[0][1].Text == "0" && board[1][1].Text == "0" && board[2][1].Text == "0")
            EndGame(0);
        else if (board[0][2].Text == "0" && board[1][2].Text == "0" && board[2][2].Text == "0")
            EndGame(0);
        else if (board[0][0].Text == "0" && board[0][1].Text == "0" && board[0][2].Text == "0")
            EndGame(0);
        else if (board[1][0].Text == "0" && board[1][1].Text == "0" && board[1][2].Text == "0")
            EndGame(0);
        else if (board[2][0].Text == "0" && board[2][1].Text == "0" && board[2][2].Text == "0")
            EndGame(0);
        else if (board[0][0].Text == "0" && board[1][1].Text == "0" && board[2][2].Text == "0")
            EndGame(0);
        else if (board[0][2].Text == "0" && board[1][1].Text == "0" && board[2][0].Text == "0")
            EndGame(0);

        // Check if opponent won.
        if (board[0][0].Text == "X" && board[1][0].Text == "X" && board[2][0].Text == "X")
            EndGame(1);
        else if (board[0][1].Text == "X" && board[1][1].Text == "X" && board[2][1].Text == "X")
            EndGame(1);
        else if (board[0][2].Text == "X" && board[1][2].Text == "X" && board[2][2].Text == "X")
            EndGame(1);
        else if (board[0][0].Text == "X" && board[0][1].Text == "X" && board[0][2].Text == "X")
            EndGame(1);
        else if (board[1][0].Text == "X" && board[1][1].Text == "X" && board[1][2].Text == "X")
            EndGame(1);
        else if (board[2][0].Text == "X" && board[2][1].Text == "X" && board[2][2].Text == "X")
            EndGame(1);
        else if (board[0][0].Text == "X" && board[1][1].Text == "X" && board[2][2].Text == "X")
            EndGame(1);
        else if (board[0][2].Text == "X" && board[1][1].Text == "X" && board[2][0].Text == "X")
            EndGame(1);

        // Check if nobody won.
        if (board[0][0].Text != "" && board[0][1].Text != "" && board[0][2].Text != "" && board[1][0].Text != "" && board[1][1].Text != "" && board[1][2].Text != "" && board[2][0].Text != "" && board[2][1].Text != "" && board[2][2].Text != "")
            EndGame(2);

        // Change turn.
        if (turn.Name == "2")
        {
            turn.Name = "1";
            turn.Text = "Your turn";
        }
        else
        {
            turn.Name = "2";
            turn.Text = "Opponents turn";
            opponentDelay.Start();
        }
    }

    // End game (or end round).
    public void EndGame(int win)
    {   
        if (win == 0)
        {
            MessageBox.Show("You Win!", "Tic Tac Toe");
            wins.Name = (Convert.ToInt32(wins.Name) + 1).ToString();
            wins.Text = "Wins: " + wins.Name;
        }
        else if (win == 1)
        {
            MessageBox.Show("Sorry but you lost, better luck next time...", "Tic Tac Toe");
            losses.Name = (Convert.ToInt32(losses.Name) + 1).ToString();
            losses.Text = "Losses: " + losses.Name;
        }
        else
        {
            MessageBox.Show("Draw! No one won...", "Tic Tac Toe");
        }

        // Reset board.
        for (int x = 0; x < board.Count; x++)
        {
            for (int y = 0; y < board.Count; y++)
            {
                board[x][y].Text = "";
            }
        }

        // Set the turn.
        turn.Name = "2";
    }

    // Variables
    public Label wins = new Label() { Text = "Wins: 0", Name = "0", Location = new Point(30, 310), AutoSize = false, Size = new Size(54, 17)  };
    public Label losses = new Label() { Text = "Losses: 0", Name = "0", Location = new Point(95, 310), AutoSize = false, Size = new Size(66, 17)  };
    public Label turn = new Label() { Text = "Your turn", Name = "1", Location = new Point(175, 310) };
    public Timer opponentDelay = new Timer() { Interval = 500 };

    // Instead of buttons and int lists, where you have to add click event and get button index to change int list and button text, just use a button list and click evnt which read the button text and changes it.
    public List<List<Button>> board = new List<List<Button>>
    {
        new List<Button>
        {
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) },
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) },
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) }
        },
        new List<Button>
        {
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) },
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) },
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) }
        },
        new List<Button>
        {
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) },
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) },
            new Button() { Text = "", Font = new Font(SystemFonts.DefaultFont.Name, 26f, FontStyle.Bold), UseVisualStyleBackColor = true, TabStop = false, Size = new Size(90, 90) }
        }
    };
}

Usage:

TicTacToe TicTacToeGame = new TicTacToe();
...Controls.Add(TicTacToeGame);

What it looks like:

enter image description here

Upvotes: 0

Scott Hannen
Scott Hannen

Reputation: 29207

When you do this:

boardTry = board;

It doesn't create a new list. boardTry and board are now both variables referring to the same list. So any changes made to boardTry are also made to board.

Here's a very recent question and answer that discuss pretty much the same question and how to work around it. The short version is that you don't want to just assign the existing list to a new variable. You want to create a new list which is a copy of the existing list.

Here's an example of a function that copies an existing board into a new one. This is a little verbose:

List<List<int>> CopyBoard(List<List<int>> original)
{
    var copied = new List<List<int>>();
    foreach (var innerList in original)
    {
        copied.Add(new List<int>(innerList));
    }
    return copied;
}

Here's the same thing as a LINQ expression. We do this because if we take the original function and cram into one line that's slightly harder to read then we feel good about ourselves.

List<List<int>> CopyBoard(List<List<int>> original)
{
    return new List<List<int>>(original.Select(innerList=> innerList.ToList()));
}

Upvotes: 4

Related Questions