Reputation: 63
This is a tic tac toe generator. Computer vs. Computer only, a little different than the usual Player vs. Computer. I have most of my code written for this, but the issue I am having is sometimes when I generate the game, the whole board fills up and there will be a line of X's and a line of O's and it will come up as a tie. Sometimes there is two lines of X's or two lines of O's generated, and the game doesn't stop after the first line with 3 in a row...any insights? Thank you.
namespace TicTacToe
{
public partial class Form1 : Form
{
private Random rn = new Random();
const int SIZE = 9;
char[] cell = new char[SIZE];
char firstPlayer = ' ', secondPlayer = ' ';
private void button1_Click(object sender, EventArgs e)
{
//Clear the labels and starting values
for (int i = 0; i < SIZE; i++)
{
cell[i] = ' ';
}
label10.Text = "";
//Pick X or O to go first
switch (rn.Next(2))
{
case 0: firstPlayer = 'O'; secondPlayer = 'X'; break;
case 1: firstPlayer = 'X'; secondPlayer = 'O'; break;
}
//Get five non-repeating numbers from 0 to 8
int[] positions = new int[5];
positions[0] = rn.Next(9);
for (int i = 1; i < 5; i++)
{
int temp = rn.Next(9);
for (int j = 0; j < i; j++)
{
if (temp == positions[j])
{
i--;
break;
}
else
{
positions[i] = temp;
}
}
}
//Set each position found to have first players letter
for (int i = 0; i < 5; i++)
{
cell[positions[i]] = firstPlayer;
}
for (int i = 0; i < SIZE; i++)
{
if (cell[i] != firstPlayer)
{
cell[i] = secondPlayer;
}
}
//Place cell values into the labels
label1.Text = cell[0].ToString();
label2.Text = cell[1].ToString();
label3.Text = cell[2].ToString();
label4.Text = cell[3].ToString();
label5.Text = cell[4].ToString();
label6.Text = cell[5].ToString();
label7.Text = cell[6].ToString();
label8.Text = cell[7].ToString();
label9.Text = cell[8].ToString();
//Check for a winner
switch(checkWinner())
{
case 'T' : label10.Text = "It's a tie!"; break;
case 'O' : label10.Text = "O Wins!"; break;
case 'X' : label10.Text = "X Wins!"; break;
default: label10.Text = "This will never appear"; break;
}
}
private char checkWinner()
{
//return either 'T' for tie, 'O' for O wins, and 'X' for X wins
char winner = ' ';
int winning_line = 0;
//check for a row win
if(cell[0].Equals(cell[1]) && cell[0].Equals(cell[2]))
{
winning_line++;
winner = cell[0];
}
if (cell[3].Equals(cell[4]) && cell[3].Equals(cell[5]))
{
winning_line++;
winner = cell[3];
}
if (cell[6].Equals(cell[7]) && cell[6].Equals(cell[8]))
{
winning_line++;
winner = cell[6];
}
//check for column wins
if (cell[0].Equals(cell[3]) && cell[0].Equals(cell[6]))
{
winning_line++;
winner = cell[0];
}
if (cell[1].Equals(cell[4]) && cell[1].Equals(cell[7]))
{
winning_line++;
winner = cell[1];
}
if (cell[2].Equals(cell[5]) && cell[2].Equals(cell[8]))
{
winning_line++;
winner = cell[2];
}
//check for diagonal winner
if (cell[0].Equals(cell[4]) && cell[0].Equals(cell[8]))
{
winning_line++;
winner = cell[0];
}
if (cell[2].Equals(cell[4]) && cell[2].Equals(cell[8]))
{
winning_line++;
winner = cell[2];
}
if (winning_line == 0 || winning_line > 1)
winner = 'T';
return winner;
}
public int i { get; set; }
}
}
Upvotes: 6
Views: 9739
Reputation: 125
This works: You need to get rid of the...
if (winning_line == 0 || winning_line > 1)
replace that line of code with these three piece of code:
if (winnerX == " X ")
{
theWinner = winnerX;
}
if (winnerO == " O ")
{
theWinner = winnerO;
}
if(winnerX == " X " && winnerO == " O ")
{
winnerT = " T ";
theWinner = winnerT;
}
So what I did was change a couple things. I didn't use the "winning_line++;" bit of code. instead I did something like this for each of the if statement checks.
if (cell[2, 0].Equals(cell[1, 1]) && cell[2, 0].Equals(cell[0, 2]))
{
if (cell[2, 0] == 0)
{
winnerX = " X ";
}
else if (cell[2, 0] == 1)
{
winnerO = " O ";
}
}
So I have 4 strings that I'm using, one to keep track if X is has a winning line, same for O. I then have the winnerT string for keeping track of the Tie. its only used in place of where your old tie check if statement was.
You will also need to change your switch statement too if you decide to use strings instead of integers i.e
switch (checkWinner())
{
case " X ":
textBox1.Text = "X Wins!";
break;
case " O ":
textBox1.Text = "O Wins!";
break;
case " T ":
textBox1.Text = "It's a tie!";
break;
}
Upvotes: 1
Reputation: 5106
The second diagonal winner check should be 6 instead of 8.
You are currently checking:
X O O
O X O
O O X
and:
O O X
O X O
O O X
Obviously the last x should be to the left.
Additionaly as others have posted. Making two lines should not result in a tie. One player could even make two lines alone, causing a tie.
Change the function to return a result right away when it finds a winning row and check for it after every move.
Upvotes: 2
Reputation: 5911
Hi think you should have a function that given a grid and a new pawn tell you if the game is over. Then if the game is finished, you know that the winner is the last pawn played.
I think the Open source project MikMak of Marthyi has a perfect implementation of that, see
bool IsFinished(Grid currentState, Pawn newPawn)
in:
https://github.com/Marthyi/MikMak/blob/master/MikMakSolution/Morpion/MorpionManager.cs
Good luck!
Upvotes: 0
Reputation: 19093
if (winning_line == 0 || winning_line > 1)
If there are two lines, it will r port a tie. If you want to stop when a line is made, you needto check for a winner after each move, not after the entire board has been filled.
Upvotes: 3