1
\$\begingroup\$

I have been studying C#, and I am trying to model the Tic Tac Toe game. Is my program reasonable or is there anything I need to improve?

 enum Result
{
    None,
    Win,
    Draw
}

public class TicTacToe
{
    static char[] board = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
    char player = 'O';
    Result result = Result.None;

    public void PlayGame()
    {
        Intro();
        do
        {
            Console.Clear();
            Console.WriteLine("Player 1 : O Player 2 : X");
            DrawBoard();
            Console.WriteLine($"\nPlayer {player}'s Turn \nPlease Enter the empty number");

            label:
            int choice = 0;

            while (!int.TryParse(Console.ReadLine(), out choice))
            {
                Console.WriteLine("Enter the num please");
            }
            if (choice >= 10)
            {
                Console.WriteLine("Please enter btw 1 - 9");
                goto label;
            }

            if (board[choice] != 'X' && board[choice] != 'O')
            {
                board[choice] = player;
                ChangeTurn();
            }

            CheckWin();
        } while (result != Result.Draw && result != Result.Win);

        Console.Clear();
        DrawBoard();
        GameResult();
        Console.ReadKey();

    }

    void ChangeTurn()
    {
      if (player == 'X')
          player = 'O';
      else if (player == 'O')
          player = 'X';
    }
    void GameResult()
    {
        if (result == Result.Win)
        {
            ChangeTurn();
            Console.WriteLine("Player {0} has won", player);
        }
        else if(result == Result.Draw)
        {
            Console.WriteLine("Draw");
        }
        Console.ReadLine();
    }
    void Intro()
    {
        Console.WriteLine("Welcome to TieTacToe");
        Console.WriteLine("Press any Key to continue");
        Console.ReadKey();
        Console.Clear();
    }
    void DrawBoard()
    {
        int x = 1;
        Console.WriteLine();
        for (int row = 0; row < 3; row++)
        {
            Console.Write("| ");
            for (int col = 0; col < 3; col++)
            {
                Console.Write(board[x]);
                Console.Write(" | ");
                x++;
            }
            Console.WriteLine();
        }
    } 
    void CheckWin()
    {
        // horzontial
        if (board[1] == board[2] && board[2] == board[3])
        {
            result = Result.Win;
        }
        else if (board[4] == board[5] && board[5] == board[6])
        {
            result = Result.Win;
        }
        else if (board[7] == board[8] && board[8] == board[9])
        {
            result = Result.Win;
        }
        // vertical
        else if (board[1] == board[4] && board[4] == board[7])
        {
            result = Result.Win;
        }
        else if (board[2] == board[5] && board[5] == board[8])
        {
            result = Result.Win;
        }
        else if (board[3] == board[6] && board[6] == board[9])
        {
            result = Result.Win;
        }
        // X
        else if (board[1] == board[5] && board[5] == board[9])
        {
            result = Result.Win;
        }
        else if (board[3] == board[5] && board[5] == board[7])
        {
            result = Result.Win;
        }
        else if (board[1] != '1' && board[2] != '2' && board[3] != '3' && board[4] != '4' && board[5] != '5' && board[6] != '6' && board[7] != '7' && board[8] != '8' && board[9] != '9')
        {
            result = Result.Draw;
        }
        else
        {
            result = Result.None;
        }
    }
}
\$\endgroup\$
3
\$\begingroup\$

If you want to be completely safe, I would also check the 'choice' to make sure that it was not a negative number.

Goto's should be avoided. You can easily refactor your code to use a while loop and break.

In your function GameResult(), I would use a switch statement instead of the if chain.

I am also thinking that CheckWin() might be a bit too cumbersome with all of the if statements and the checking of the individual cells. I might keep a "shadow board" behind the scenes, where a cell is 1 if it is an X and -1 if it is an O. Some simple addition and a test to see if the Math.Abs(sum) == 3 is an easy way to test for a win. For example:

if (Math.Abs(board[1] + board[2] + board[3]) == 3)
  result = Result.Win;

You can even refactor what I wrote above by keeping a list of the triplets to check.

Good luck with your studies of C#.

\$\endgroup\$
4
  • \$\begingroup\$ thank you for your helpful comments. One thing, I understand that CheckWin()is repeated too much with if statements. How can I keep "shadow board". If its not too much asking, could you show me? \$\endgroup\$ Oct 12 '18 at 4:57
  • \$\begingroup\$ The "shadow board" would be the exact same thing as your variable 'board', but it would just contain 3 values ... -1 for the letter O, 0 if the box has not been filled out, and 1 for the letter X. static int[] shadowBoard = new int[10]; When the user fills in the X or O, you also fill in the shadowBoard with the appropriate numeric value. board[choice] = player; shadowBoard[choice] = player == 'X' ? 1 : -1; \$\endgroup\$
    – Marc Adler
    Oct 12 '18 at 16:38
  • \$\begingroup\$ Can someone please help me with the formatting for my comment above? I tried indenting by 4 spaces, but I cannot get the text to show up as code. \$\endgroup\$
    – Marc Adler
    Oct 12 '18 at 16:39
  • \$\begingroup\$ thank you vert much. I will try to reprogram it based on your advice. \$\endgroup\$ Oct 13 '18 at 13:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.