6

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; }
    }
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • 3
    Your diagonals have a bug, you're checking for `0 == 4 == 8`, but also `2 == 4 == 8(instead of 6)` – Nolonar Mar 07 '13 at 09:21
  • 2
    If you want to exercise i would consider trying to implement all of your game logic separate from your UI. You could create classes for the game itself, the players, each winning rule, etc. You could then play around with the AI and stuff much more easily. Just a suggestion, though... – Jobo Mar 07 '13 at 09:34
  • I would vote up Jobo's comment if I could. If you create a class which handles the game, you can put it inside different UI's e.g. one for computer vs. computer, or a different one for player vs player or player vs computer. – SteveP Mar 08 '13 at 09:04

4 Answers4

3
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.

SteveP
  • 18,840
  • 9
  • 47
  • 60
  • Yes, also if you check every time a symbol is placed, you only have to check the lines from the last placed symbol. – MrFox Mar 07 '13 at 09:27
  • @SteveP - I am pretty new at this, as this is a beginner exercise recommended by the book I am reading to try. If you can further help me understand as far as checking after each statement, it would be greatly appreciated. I understand what you're getting at, just having issues putting it together... Thank you. – TomandGeriatric Mar 08 '13 at 06:30
  • basically, to simulate a real game, you take the current position, apply a players move to it, and then check to see if that move won the game. You can optimise the winning check as any winning row must include the move which was just made. – SteveP Mar 08 '13 at 09:01
  • I've been staring at this for hours, sad, I know. I give up. – TomandGeriatric Mar 09 '13 at 05:57
2

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.

MrFox
  • 4,852
  • 7
  • 45
  • 81
1

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;
        }
Foemilod
  • 125
  • 1
  • 2
  • 12
0

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!

Thomas
  • 5,603
  • 5
  • 32
  • 48