Reputation: 457
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.
Upvotes: 0
Views: 85
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:
Upvotes: 0
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