Tic Tac Toe

  • (2 Pages)
  • +
  • 1
  • 2

15 Replies - 2717 Views - Last Post: 19 September 2012 - 03:36 PM Rate Topic: -----

#1 rookie0Ken  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 06-August 12

Tic Tac Toe

Posted 16 September 2012 - 11:46 PM

Just finished writing a tic tac toe game,however i feel that the code is a bit too long. the other thing is am stuck because i cant seem to figure out how to determine a draw in the GameStatus method.The way i have used to determine the draw enters an infinite recursion. The PrintBoard method also prints the loser as the winner. Any assistance will be much appreciated. Here is the code i have so far
 class TicTacToe
    {
        private char[,] board = new char[3, 3];
        private bool playerWin = false;
        private char player = 'X';
        enum STATUS {  DRAW = 9 }
        private int counter;

        public TicTacToe()
        {
            ResetBoad();
        }


        public void ResetBoad()
        {
            for (int i = 0; i < board.GetLength(0); i++)
                for (int j = 0; j < board.GetLength(1); j++)
                    board[i, j] = ' ';
        }

        public void PrintBoard()
        {
            string output=null;
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                    output += board[i, j] + " \t";
                output += "\n\n";
            }
            if (playerWin == true)
                output += "\n\nPlayer " + player + " Wins the Game";// prints the player who lost the game
            else
            {
                if (counter == (int)STATUS.DRAW)
                    output += "\n\nThe Game Is a Draw";
            }
            Console.WriteLine(output);
        }

        private bool GameStatus(char player)
        {
            if (board[0, 0] == board[0, 1] && (board[0, 0] == board[0, 2] && board[0, 0] != ' '))
                return true;
            if (board[1, 0] == board[1, 1] && (board[1, 0] == board[1, 2] && board[1, 0] != ' '))
                return true;
            if (board[2, 0] == board[2, 1] && (board[2, 0] == board[2, 2] && board[2, 0] != ' '))
                return true;
            if (board[0, 0] == board[1, 0] && (board[0, 0] == board[2, 0] && board[0, 0] != ' '))
                return true;
            if (board[0, 1] == board[1, 1] && (board[0, 0] == board[2, 1] && board[0, 1] != ' '))
                return true;
            if (board[0, 2] == board[1, 2] && (board[0, 2] == board[2, 2] && board[0, 2] != ' '))
                return true;
            if (board[0, 0] == board[1, 1] && (board[0, 0] == board[2, 2] && board[0, 0] != ' '))
                return true;
            if (board[0, 2] == board[1, 1] && (board[0, 2] == board[2, 0] && board[0, 2] != ' '))
                return true;

            return false;
        }

        private char ChangePlayer()
        {
            return player = (player == 'X') ? 'O' : 'X';
        }
        public void PlayGame( int row, int col)
        {
            if (counter <= (int)STATUS.DRAW)// draw enters an infinite recursion
            {
                if (playerWin == true)
                {
                    PrintBoard();
                }
                else
                {
                    Console.Write("Enter Row Number: ");
                    row = Int32.Parse(Console.ReadLine());
                    Console.Write("Enter Col Number: ");
                    col = Int32.Parse(Console.ReadLine());
                    if (board[row, col] == ' ')
                    {
                        board[row, col] = player;
                        player = ChangePlayer();
                        counter++;
                    }
                    playerWin = GameStatus(player);
                    PrintBoard();
                    PlayGame(row, col);
                }
            }
            PrintBoard();
        }
    }

This post has been edited by JackOfAllTrades: 17 September 2012 - 02:57 AM
Reason for edit:: Fixed code tags.


Is This A Good Question/Topic? 0
  • +

Replies To: Tic Tac Toe

#2 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5832
  • View blog
  • Posts: 12,686
  • Joined: 16-October 07

Re: Tic Tac Toe

Posted 17 September 2012 - 07:12 AM

You never initalize player. Ok, you do on object creation. What if you want to play again?

There is no point in PlayGame taking row and col parameters. Wait... you're calling yourself too? No, don't do that.

The STATUS enum has only one value and using it as an int misses the point. Reasonably, you'd want something like PLAYING, X_WIN, O_WIN, DRAW.

Your GameStatus takes player and then ignores it. You probably want:
if (board[0, 0] == player && board[0, 0] == board[0, 1] && (board[0, 0] == board[0, 2] )) { return true; }



Hope this helps.

This post has been edited by baavgai: 17 September 2012 - 07:12 AM

Was This Post Helpful? 0
  • +
  • -

#3 rookie0Ken  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 06-August 12

Re: Tic Tac Toe

Posted 17 September 2012 - 11:41 PM

View Postbaavgai, on 17 September 2012 - 07:12 AM, said:

The STATUS enum has only one value and using it as an int misses the point. Reasonably, you'd want something like PLAYING, X_WIN, O_WIN, DRAW.


View Postbaavgai, on 17 September 2012 - 07:12 AM, said:

The STATUS enum has only one value and using it as an int misses the point. Reasonably, you'd want something like PLAYING, X_WIN, O_WIN, DRAW.


Is there a way to track the draw without using the counter?
and if I initialize the enum values as u have suggested does it mean that my Gamestatus method will have to check for win scenarios for both X and O or can i just leave i as it is?
Was This Post Helpful? 0
  • +
  • -

#4 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5832
  • View blog
  • Posts: 12,686
  • Joined: 16-October 07

Re: Tic Tac Toe

Posted 18 September 2012 - 05:20 AM

View Postrookie0Ken, on 18 September 2012 - 02:41 AM, said:

Is there a way to track the draw without using the counter?


Sure. You could just check your entire board for any empty positions. However, don't think counter, think turn. Knowing the turn is particularly useful, because you can tell which player is currently playing from it. And, when you hit the turn number when the board is full, you know you're done.


View Postrookie0Ken, on 18 September 2012 - 02:41 AM, said:

it mean that my Gamestatus method will have to check for win scenarios for both X and O or can i just leave i as it is?


Yes, if there was no win last time and there is a win now, then the current player won.

To give an idea, this is the kind of framework I'd use if I was doing this project.
 
class TicTacToe  {
	public enum StatusType { Playing, WinX, WinO, Draw, NoGames }
	private enum CellType { Empty, PlayerX, PlayerY };
	private CellType [] board;
	private int turn;
	private StatusType status;

	public TicTacToe() {
		board = new CellType[9];
		status = StatusType.NoGames;
	}


	private void InitGame() { /* your code here */ }

	public void PrintBoard() { /* your code here */ }
	
	private bool IsWin(CellType player) { /* your code here */ }
	
	private bool IsEmpty(int row, int col) { /* your code here */ }
	
	// returns false if cell not empty
	private bool SetPlayer(int row, int col, CellType player) { /* your code here */ }
	
	private int GetIntFromUser(string prompt) { /* your code here */ }
	
	public void PlayGame() {
		InitGame()
		while(status==StatusType.Playing) {
			CellType player = (this.turn % 2==0) ? CellType.PlayerX : CellType.PlayerO;
			
			PrintBoard();
			int row = GetIntFromUser("Enter Row Number: ");
			int col = GetIntFromUser("Enter Col Number: ");
			if (SetPlayer(row, col, player)) {
				if (IsWin(player)) {
					status = (player==CellType.PlayerX) ? StatusType.WinX : StatusType.WinO;
				} else {
					turn++;
					if (turn==9) { status = StatusType.Draw; }
				}
			} else {
				Console.WriteLine("Invalid Request");
			}
		}
		// print something about final status
		PrintBoard();
	}



Hope this helps.
Was This Post Helpful? 1
  • +
  • -

#5 rookie0Ken  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 06-August 12

Re: Tic Tac Toe

Posted 19 September 2012 - 12:04 AM

Thanks I have a general idea on how to go about it now. Maybe its because i am not to familiar with using the enum type. I am trying to tutor myself in c# and good software development and am alot rough round the edges.

Quote

You never initalize player. Ok, you do on object creation. What if you want to play again?

I am currently studying a book where the self evaluation exercise was to create a class for the game which would be instantiated in another class.Am very new to programming and would much appreciate any help.
Let me try and redo the game and will get back to you.
Thanks alot
Was This Post Helpful? 0
  • +
  • -

#6 rookie0Ken  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 06-August 12

Re: Tic Tac Toe

Posted 19 September 2012 - 03:07 AM

Thanks baavgai, using ur guideline i have coded the game successfully. I think am starting to get the concept of using enums, but not completely, i'll keep practicing. I want to code a computer AI to compete with the player.Will code it and post it in this thread and maybe if you dont mind you will give me guidance and tips to make the code more efficient.
Was This Post Helpful? 0
  • +
  • -

#7 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5832
  • View blog
  • Posts: 12,686
  • Joined: 16-October 07

Re: Tic Tac Toe

Posted 19 September 2012 - 04:23 AM

Don't get hung up on enums. I only started because you did. ;)

Essentially, an enum is a way of guaranteeing that a passed value is within a set range.

Consider:
void SetValue(int n) {
	if (n==1) { // something
	} else if (n==2) { // something
	} else if (n==3) { // something
	} else {
		// oops, n is only supposed to be 1,2, or 3
	}
}



And me, as the user of SetValue, may not know exactly what I'm allowed to give you.

Enter the enum:
private enum ValueType { Larry, Moe, Curly }
void SetValue(ValueType n) {
	if (n==ValueType.Larry) { // something
	} else if (n==ValueType.Moe) { // something
	} else {
		// n must equal Curly
		// there is not other choice
	}
}



And when you're coding in Visual Studio, you can just type "ValueType." and intellisence will give you a valid list. Even better, it will fail at compile time, rather than runtime, if an invalid value attempts to be passed.

You need never use enums. However, they are very useful in some situations for controlling the chaos of organizing code.
Was This Post Helpful? 1
  • +
  • -

#8 rookie0Ken  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 06-August 12

Re: Tic Tac Toe

Posted 19 September 2012 - 07:57 AM

here is the AI code i have so far. Ideally the AI should prevent a player from winning in one player mode, but what i have just plays random moves till its in a position to win. Any suggestions?
 private void ComputerAI(CellType player) {
            Random move =new Random();
            int cell=move.Next(9);
            
            if ((board[0] == player && board[0] == board[1]) || (board[6] == player && board[6] == board[4]) || (board[8] == player && board[8] == board[5]))
                board[2] = CellType.PlayerO;

            else if ((board[0] == player && board[0] == board[2]) || (board[7] == player && board[7] == board[4]))
                board[1] = CellType.PlayerO;

            else if ((board[1] == player && board[1] == board[2]) || (board[4] == player && board[4] == board[8]) || (board[3] == player && board[3] == board[6]))
                board[0] = CellType.PlayerO;

            else if ((board[0] == player && board[0] == board[6]) || (board[6] == player && board[4] == board[5]))
                board[3] = CellType.PlayerO;

            else if ((board[0] == player && board[0] == board[8]) || (board[6] == player && board[6] == board[2]) || (board[1] == player && board[1] == board[7]) || (board[3] == player && board[3] == board[5]))
                board[4] = CellType.PlayerO;

            else if ((board[2] == player && board[2] == board[8]) || (board[3] == player && board[3] == board[4]))
                board[5] = CellType.PlayerO;

            else if ((board[0] == player && board[0] == board[3]) || (board[2] == player && board[2] == board[4]) || (board[7] == player && board[7] == board[8]))
                board[6] = CellType.PlayerO;

            else if ((board[6] == player && board[6] == board[8]) || (board[1] == player && board[1] == board[4]))
                board[7] = CellType.PlayerO;

            else if ((board[0] == player && board[0] == board[4]) || (board[2] == player && board[2] == board[5]) || (board[6] == player && board[6] == board[7]))
                board[8] = CellType.PlayerO;
            else
                    board[cell] = CellType.PlayerO;
           
        }


thanks again for the brief tutorial on enums. Now i know when to use enums.
Was This Post Helpful? 0
  • +
  • -

#9 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 3576
  • View blog
  • Posts: 11,125
  • Joined: 05-May 12

Re: Tic Tac Toe

Posted 19 September 2012 - 08:52 AM

Your lines 5-30 are all the defensive moves. You should have additional code that has the preferred moves. eg. If the center is available, take the spot. If a corner is available take that spot.

Your code is very dense and hard to read with your chain of if statement conditions. If you could replace:
if ((board[0] == player && board[0] == board[1]) || (board[6] == player && board[6] == board[4]) || (board[8] == player && board[8] == board[5]))


with
// Defending top right corner
if ((board[0] == player && board[0] == board[1]) ||    // check top row 
    (board[6] == player && board[6] == board[4]) ||    // check diagonal
    (board[8] == player && board[8] == board[5]))      // check right column


You will help make the code a little bit more readable.

But even better would be:
if (IsUpperRightCornerVulnerable(board, player))
:
bool IsUpperRightCornerVulnerable(Player player)
{
    return AreTwoOccupiedByPlayer(player, 0, 1) ||
           AreTwoOccupiedByPlayer(player, 6, 4) ||
           AreTwoOccupiedByPlayer(player, 8, 5);
}

bool AreTwoOccupiedByPlayer(Player player, int cell1, int cell2)
{
    return board[cell1] == player && board[cell2] == player;
}




You have a lot of hardcoded magic numbers. Add on top of that the magic numbers represent a grid like:
0 1 2
3 4 5
6 7 8


And it becomes very hard to visualize what is happening. I suggest a two dimensional array to help with the code clarity so that even if you stick with hard coded magic numbers, it'll be a bit easier to visualize where in the grid the location is at.
Was This Post Helpful? 1
  • +
  • -

#10 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5832
  • View blog
  • Posts: 12,686
  • Joined: 16-October 07

Re: Tic Tac Toe

Posted 19 September 2012 - 09:29 AM

You're pretty much ignoring player, in that it's assumed PlayerX.

A lot of visual noise there. Whenever you seem the same thing repeating, make code to limit the mess to one place.

e.g.
private void AiTest(CellType player, int p1, int p2) {
	return board[p1] == player && board[p1] == board[p2];
}

private void ComputerAI(CellType player) {
	Random move =new Random(); // problem, you don't want a new Random object ever single time.
	int cell=move.Next(9); // problem, you want to find an empty

	if (AiTest(player, 0, 1) || AiTest(player, 6, 4) || AiTest(player, 8, 5) {



That said, you're working too hard and not enough.

You want code to find a wining move for either player. This is why IsWin with a player parameter is useful.
private int GetWinningMove(CellType player) {
	for(int i=0; i<board.length; i++) {
		if (board[i]==Empty) {
			board[i]=player; // pretend to move
			bool bestMove = IsWin(player);
			board[i]=Empty; // restore state
			if (bestMove) { return i; }
		}
	}
	return -1;
}

private void ComputerAI() {
	int move = GetWinningMove(PlayerO);
	if (move==-1) {
		move = GetWinningMove(PlayerX);
	}
	if (move==-1) {
		move = GetRandomMove();
	}
	board[move] = CellType.PlayerO;
}



I probably gave too much on that one... Oh well, hope it helps.

This post has been edited by baavgai: 19 September 2012 - 09:30 AM

Was This Post Helpful? 2
  • +
  • -

#11 rookie0Ken  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 06-August 12

Re: Tic Tac Toe

Posted 19 September 2012 - 11:21 AM

in my edited code i changed the methods that are taking row and col as arguments to take just a number (from 1 to 9) being the cell location one being the top right most cell.
sorry for the visual noise, still very new at this.

private void ComputerAI(CellType player) {// takes player type to determine comp move
            Random move =new Random();
            int cell=move.Next(9);
            
             //can act as both a defensive and offensive move
            if ((board[0] == player && board[0] == board[1]) ||
                (board[6] == player && board[6] == board[4]) || 
                (board[8] == player && board[8] == board[5]))
                board[2] = CellType.PlayerO;



i was thinking if the AI can pass player as a method then if any player has one move to win the AI can either play to win or play to prevent win
Was This Post Helpful? 0
  • +
  • -

#12 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5832
  • View blog
  • Posts: 12,686
  • Joined: 16-October 07

Re: Tic Tac Toe

Posted 19 September 2012 - 11:26 AM

View Postrookie0Ken, on 19 September 2012 - 02:21 PM, said:

then if any player has one move to win the AI can either play to win or play to prevent win


This is basically what I showed above. First, you test all available positions and see if playing there results in a win for the computer. If does, you're done. Then, you do the same for the player. If you find a winning player move, you play there. If neither of these two cases exist, you pick an available spot at random.
Was This Post Helpful? 0
  • +
  • -

#13 h4nnib4l  Icon User is offline

  • The Noid
  • member icon

Reputation: 1181
  • View blog
  • Posts: 1,675
  • Joined: 24-August 11

Re: Tic Tac Toe

Posted 19 September 2012 - 11:52 AM

If you want to make your AI a little more "advanced", you can teach it strategy. There is a finite number of move combinations between player and AI, and for many of them, there is an "ideal" next move that is most likely to set you up for a win (or to not lost at least). To employ this, your AI would explicitly make certain moves based on the player's chosen move (or at least allow the AI to pick from a more constrained set of moves/strategies if multiple paths can be taken). I realize that this is going a little overboard, but I really enjoyed that part of this project when I was in school (although I did end up spending a ridiculous amount of time playing tic tac toe against myself :D ).
Was This Post Helpful? 1
  • +
  • -

#14 rookie0Ken  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 06-August 12

Re: Tic Tac Toe

Posted 19 September 2012 - 11:53 AM

ooh silly me i see how you use the IsWin method to check for a winning move and using a dummy move.Thats pretty good, very little code, very efficient.

Thanks alot guys, if i had guys like you to mentor and tutor me, i cant see any reason why i cant be the best.

Thanks alot again.
Was This Post Helpful? 0
  • +
  • -

#15 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2263
  • View blog
  • Posts: 9,467
  • Joined: 29-May 08

Re: Tic Tac Toe

Posted 19 September 2012 - 01:48 PM

View Postbaavgai, on 19 September 2012 - 12:23 PM, said:

Enter the enum:
private enum ValueType { Larry, Moe, Curly }
void SetValue(ValueType n) {
	if (n==ValueType.Larry) { // something
	} else if (n==ValueType.Moe) { // something
	} else {
		// n must equal Curly
		// there is not other choice
	}
}



Not True, n can be any value of the underlying type. Tutorial

You really should check to see if it a member of the enum set.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2