Completed Tic Tac Toe - Critical Critiques and Advice
#1 Members - Reputation: 111
Posted 15 November 2012 - 05:32 PM
[source lang="csharp"]/** Tic Tac Toe - by Maurice Harris* Last Modified: 11/15/12*/using System;namespace TicTacToeGame{ class TicTacToe { static bool gameOver = false; // Draws a tic tac toe board static void DrawBoard(char[] board) { Console.WriteLine("\n\n " + board[6] + " | " + board[7] + " | " + board[8]); Console.WriteLine(" ---+---+---"); Console.WriteLine(" " + board[3] + " | " + board[4] + " | " + board[5]); Console.WriteLine(" ---+---+---"); Console.WriteLine(" " + board[0] + " | " + board[1] + " | " + board[2] + "\n\n"); } // Clears a tic tac toe board static void ClearBoard(char[] board) { // Loop through char array elements and set them equal to ' ' for (int i = 0; i < board.Length; i++) { board[i] = ' '; } } // Draws a tic tac toe board with numbers in the spaces to correspond with the numpad static void DrawExampleBoard() { Console.WriteLine("\n\n 7 | 8 | 9 "); Console.WriteLine(" ---+---+---"); Console.WriteLine(" 4 | 5 | 6 "); Console.WriteLine(" ---+---+---"); Console.WriteLine(" 1 | 2 | 3\n\n"); } // Checks the board to see if the space is taken up by an O or X static bool SpaceFree(char[] board, int move) { return board[move] == ' '; } // Marks spot on the tic tac toe board with a marker if the space is free static bool MakeMove(char[] board, char marker, int move) { if (SpaceFree(board, move)) { board[move] = marker; return true; } else { Console.WriteLine("\nThat spot is taken."); return false; } } // Take input from either the numpad or numerical keys 1-9 and mark the board static void TakeInput(char[] board, char marker) { // Keep track of whether or not the user has pressed a valid key for marking the board bool validKeyPressed = false; // Keep track of the key pressed by the user ConsoleKeyInfo keyPressed; // Do-While loop to catch valid input from the user do { keyPressed = Console.ReadKey(true); // If the key pressed is valid and the spot is unmarked, mark it, // Otherwise break the switch statement and take new key input switch (keyPressed.Key) { case ConsoleKey.NumPad1: case ConsoleKey.D1: if (MakeMove(board, marker, 0)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad2: case ConsoleKey.D2: if (MakeMove(board, marker, 1)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad3: case ConsoleKey.D3: if (MakeMove(board, marker, 2)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad4: case ConsoleKey.D4: if (MakeMove(board, marker, 3)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad5: case ConsoleKey.D5: if (MakeMove(board, marker, 4)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad6: case ConsoleKey.D6: if (MakeMove(board, marker, 5)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad7: case ConsoleKey.D7: if (MakeMove(board, marker, 6)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad8: case ConsoleKey.D8: if (MakeMove(board, marker, 7)) { validKeyPressed = true; break; } break; case ConsoleKey.NumPad9: case ConsoleKey.D9: if (MakeMove(board, marker, 8)) { validKeyPressed = true; break; } break; default: Console.WriteLine("\nPlease use your numpad or the keys 1-9 to choose a spot to mark."); break; } } while (!validKeyPressed); } // Check to see if the board has no unmarked spots left static bool BoardFull(char[] board) { for (int i = 0; i < board.Length; i++) { if (board[i] == ' ') { return false; } } return true; } // Check to see if someone has won or if there is a tie // Return a string to annouce the game's final state static string CheckWinner(char[] board, char marker) { // Horizontal Win if ((board[0] == marker) && (board[1] == marker) && (board[2] == marker)) { gameOver = true; return marker + " wins!\n"; } else if ((board[3] == marker) && (board[4] == marker) && (board[5] == marker)) { gameOver = true; return marker + " wins!\n"; } else if ((board[6] == marker) && (board[7] == marker) && (board[8] == marker)) { gameOver = true; return marker + " wins!\n"; } // Vertical Win else if ((board[0] == marker) && (board[3] == marker) && (board[6] == marker)) { gameOver = true; return marker + " wins!\n"; } else if ((board[1] == marker) && (board[4] == marker) && (board[7] == marker)) { gameOver = true; return marker + " wins!\n"; } else if ((board[2] == marker) && (board[5] == marker) && (board[8] == marker)) { gameOver = true; return marker + " wins!\n"; } // Diagonal Win else if ((board[0] == marker) && (board[4] == marker) && (board[8] == marker)) { gameOver = true; return marker + " wins!\n"; } else if ((board[2] == marker) && (board[4] == marker) && (board[6] == marker)) { gameOver = true; return marker + " wins!\n"; } // Tie Game else if (BoardFull(board)) { gameOver = true; return "No one wins, it's a tie!\n"; } return null; } // Introduce the game to users and explain how to play static void Intro() { Console.WriteLine("\n\n Welcome to Tic Tac Toe!\n\n"); Console.WriteLine(" Currently you can only play against another human player."); Console.WriteLine(" To pick a spot on the Tic Tac Toe board use the keypad or the numbers 1-9."); Console.WriteLine(" You must have num-lock on to be able to use the keypad for input."); Console.WriteLine(" The keypad positions correspond to the Tic Tac Toe board."); DrawExampleBoard(); Console.WriteLine(" Press any key to start the game!"); Console.ReadKey(true); Console.Clear(); } // The Tic Tac Toe Game's heart static void TicTacToeGame(char[] board) { int playerTurn = 1; string winner = ""; while (!gameOver) { // Player 1/O's if (playerTurn == 1) { Console.WriteLine("It is O's turn to move!"); TakeInput(board, 'O'); DrawBoard(board); winner = CheckWinner(board, 'O'); playerTurn = 2; } // Player 2/X's turn else { Console.WriteLine("It is X's turn to move!"); TakeInput(board, 'X'); DrawBoard(board); winner = CheckWinner(board, 'X'); playerTurn = 1; } } Console.WriteLine(winner); } static void Main() { // The Tic Tac Toe board char[] board = {' ',' ',' ',' ',' ',' ',' ',' ',' '}; // Used to keep track of whether a new game has started bool newGame = true; // Do-While loop that runs through the intro and a full game of human vs. human tic tac toe // The loop continues until the user responds with a n or no to another game of tic tac toe do { Intro(); DrawBoard(board); TicTacToeGame(board); Console.WriteLine("Would you like to play again? [Y]es/[N]o?\n"); string response = Console.ReadLine(); switch (response.ToLower()) { case "yes": case "y": gameOver = false; Console.Clear(); ClearBoard(board); break; case "no": case "n": newGame = false; Console.Clear(); ClearBoard(board); break; default: break; } } while (newGame == true); } }}[/source]
#2 Members - Reputation: 1538
Posted 15 November 2012 - 09:20 PM
Looking mostly good so far. (I don't like your formatting but that's a preference issue, lol.)
Will edit here after looking at the rest.
In the main fn, why do-while rather than just while? You set the condition prior to the loop. Also, it's not an issue in this case since the code is so short and clean, but in terms of design the 'play again' block could be segregated to its own function.
DrawExampleBoard() seems superfluous. All it does is write some lines and its only call is in the midst of a series of drawn lines. Do you intend to call it elsewhere in a later version?
You call DrawBoard() prior to calling TicTacToeGame(). Why not move it into the beginning of TicTacToeGame()? It seems more natural for it to be there.
I see main()'s board getting passed into a lot of member functions. Why not make it a member variable?
TakeInput() - huge switch statement in here. DRY. Convert the enum to your target value (It feels really gross doing this with a switch, but idk enough about C# console input to do it by character value.) and then run the code once on the derived value. If you want to change the action taken on the value later you won't need to change it nine times. Your code will also be smaller.
[source lang="csharp"]int slot = -1;switch(keyPressed.Key) { //... case ConsoleKey.NumPad9: case ConsoleKey.D9: slot = 8; break; default: Console.WriteLine("\nPlease use your numpad or the keys 1-9 to choose a spot to mark."); break;}if(slot != -1) { validKeyPressed = MakeMove(board, marker, slot);}[/source]
TakeInput() has another do-while that could be a while.
[source lang="csharp"] if(MakeMove(board, marker, 0)) { validKeyPressed = true; break; //this line is not necessary } break;[/source]
Still looking.
Going by function name, TakeInput() should not call MakeMove(). It should return the derived value and then the caller of TakeInput() should call MakeMove() with that value. This would technically be the better thing to do here, but in this case you could get away with just renaming TakeInput() to TakeTurn(), since that's what it's really doing here.
Did you not get a compiler warning for MakeMove()'s return paths? This is how to avoid it:
[source lang="csharp"] // Marks spot on the tic tac toe board with a marker if the space is free static bool MakeMove(char[] board, char marker, int move) { if(SpaceFree(board, move)) { board[move] = marker; return true; } Console.WriteLine("\nThat spot is taken."); return false; }[/source]
Try to find ways to make your data work for you, instead of you working for the data:
[source lang="csharp"] // The Tic Tac Toe Game's heart static void TicTacToeGame(char[] board) { char playerTurn = 'O'; string winner = ""; while(!gameOver) { Console.WriteLine("It is " + playerTurn + "'s turn to move!"); TakeInput(board, playerTurn); DrawBoard(board); winner = CheckWinner(board, playerTurn); playerTurn = (playerTurn == 'O') ? 'X' : 'O'; } Console.WriteLine(winner); }[/source]
This may save you some room:
[source lang="csharp"] static bool CheckWinSet(char board[], int a, int b, int c) { return (board[a] == board[b]) && (board[b] == board[c]); } static string CheckWinner(char[] board, char marker) { while(true) { //for breaking // Horizontal Win if(gameOver = CheckWinSet(board, 0, 1, 2)) {break;} if(gameOver = CheckWinSet(board, 3, 4, 5)) {break;} if(gameOver = CheckWinSet(board, 6, 7, 8)) {break;} // Vertical Win if(gameOver = CheckWinSet(board, 0, 3, 6)) {break;} if(gameOver = CheckWinSet(board, 1, 4, 7)) {break;} if(gameOver = CheckWinSet(board, 2, 5, 8)) {break;} // Diagonal Win if(gameOver = CheckWinSet(board, 0, 4, 8)) {break;} if(gameOver = CheckWinSet(board, 2, 4, 6)) {break;} break; } if(gameOver) { return marker + " wins!\n"; } // Tie Game if(BoardFull(board)) { gameOver = true; return "No one wins, it's a tie!\n"; } return null; }[/source]
You may be able to find a stdlib function that searches for a specific character in a string. I dunno if C# has it, but if so you can tack a zero on to the end of your board array and then search it for ' ' rather than using BoardFull().
Overall, this is pretty good. It's clean and easy to read and I was able to track the flow of the program with no difficulty. I think you're quite ready to move on to the next level of complexity. You may want to look into some articles about general program structure and etc, but really you did quite well here. I have no significant complaints. I know I said a lot, but I don't want you to think that your own version was 'wrong'. It's just that there's always a 'better' way. (I'm resisting the temptation to change CheckWinner() to a loop that runs through static int[3] arrays) I'm sure that there are far better ways than what I showed you as well. You'll naturally pick up better flow habits as you practice and see more code and come across interesting ideas.
Good job!
Edited by Khatharr, 15 November 2012 - 10:25 PM.
There are ten kinds of people in this world: those who understand binary and those who don't.
#3 Members - Reputation: 1297
Posted 15 November 2012 - 11:18 PM
How would you write it, if the board size can be configured to 4 or 5? Ironically, you should find that your code will get a lot shorter, cleaner and contain way fewer messy if-else and switch-case constructs.
Once that is working, how would you handle the win condition not being n in a row (where n equals the board size), but a value that can be configured independently? You should find this to be a very small adjustment to your existing code (okay, I'm lying, unless you didn't realize that only two diagonals need to be checked for n = board size).
What if the board doesn't have to be square? Again, this should end up being only a minor change.
#4 Members - Reputation: 463
Posted 16 November 2012 - 02:31 PM
I noticed this:
Which brings me to the issue that this whole program has only static methods. So the suggestion of adding a member variable wont work.I see main()'s board getting passed into a lot of member functions. Why not make it a member variable?
How about trying to create a class called Board and instantiate it? It wont make the source code shorter, but it will focus some code to specific place. It will increase the so called cohesion (http://en.wikipedia.org/wiki/Cohesion_%28computer_science%29) for different elements (or compononents/modules/concepts) of your program. Basically most of you operations of the board data would be abstracted away there.
The Board class could have methods such as:
Clear()
Draw()
IsElementFree() (SpaceFree)
MakeMove()
IsFull()
Also, you can add loops inside of your CheckWinner() method.
#5 Members - Reputation: 1538
Posted 16 November 2012 - 04:11 PM
Which brings me to the issue that this whole program has only static methods. So the suggestion of adding a member variable wont work.
I see main()'s board getting passed into a lot of member functions. Why not make it a member variable?
It seems to work okay for 'gameOver'.
Moving toward a more object-oriented approach would definitely be the next step, though. I agree with that.
There are ten kinds of people in this world: those who understand binary and those who don't.
#6 Members - Reputation: 111
Posted 16 November 2012 - 07:01 PM
Updated Source:
[source lang="csharp"]/** Tic Tac Toe - by Maurice Harris* Last Modified: 11/16/12*/using System;namespace TicTacToeGame{ class TicTacToe { // The Tic Tac Toe board static char[] board = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; // Used to keep track of whether the current game is over static bool gameOver = false; // Used to keep track of whether a new game has started static bool newGame = true; // Draws a tic tac toe board static void DrawBoard() { Console.WriteLine("\n\n " + board[6] + " | " + board[7] + " | " + board[8]); Console.WriteLine(" ---+---+---"); Console.WriteLine(" " + board[3] + " | " + board[4] + " | " + board[5]); Console.WriteLine(" ---+---+---"); Console.WriteLine(" " + board[0] + " | " + board[1] + " | " + board[2] + "\n\n"); } // Clears a tic tac toe board static void ClearBoard() { // Loop through char array elements and set them equal to ' ' for (int i = 0; i < board.Length; i++) { board[i] = ' '; } } // Checks the board to see if the space is taken up by an O or X static bool IsSpaceFree(int move) { return board[move] == ' '; } // Marks spot on the tic tac toe board with a marker if the space is free static bool MakeMove(char marker, int move) { if (IsSpaceFree(move)) { board[move] = marker; return true; } else { Console.WriteLine("\nThat spot is taken."); return false; } } // Take input from either the numpad or numerical keys 1-9 and mark the board static void TakeInput(char marker) { // Keep track of whether or not the user has pressed a valid key for marking the board bool validKeyPressed = false; // Keep track of the key pressed by the user ConsoleKeyInfo keyPressed; // The spot picked by the user int spot = -1; // While loop to catch valid input from the user while (!validKeyPressed) { keyPressed = Console.ReadKey(true); // If the key pressed is valid and the spot is unmarked, mark it, // Otherwise break the switch statement and take new key input switch (keyPressed.Key) { case ConsoleKey.NumPad1: case ConsoleKey.D1: spot = 0; break; case ConsoleKey.NumPad2: case ConsoleKey.D2: spot = 1; break; case ConsoleKey.NumPad3: case ConsoleKey.D3: spot = 2; break; case ConsoleKey.NumPad4: case ConsoleKey.D4: spot = 3; break; case ConsoleKey.NumPad5: case ConsoleKey.D5: spot = 4; break; case ConsoleKey.NumPad6: case ConsoleKey.D6: spot = 5; break; case ConsoleKey.NumPad7: case ConsoleKey.D7: spot = 6; break; case ConsoleKey.NumPad8: case ConsoleKey.D8: spot = 7; break; case ConsoleKey.NumPad9: case ConsoleKey.D9: spot = 8; break; default: Console.WriteLine("\nPlease use your numpad or the keys 1-9 to choose a spot to mark."); break; } if (spot != -1) { Console.Clear(); validKeyPressed = MakeMove(marker, spot); } } } // Check to see if the board has no unmarked spots left static bool IsBoardFull() { for (int i = 0; i < board.Length; i++) { if (board[i] == ' ') { return false; } } return true; } // Check a set of numbers static bool CheckWinSet(char marker, int a, int b, int c) { return ((board[a] == marker) && (board[b] == marker) && (board[c] == marker)); } // Check to see if someone has won or if there is a tie // Return a string to annouce the game's final state static string CheckWinner(char marker) { while(true) { // Horizontal Win if (gameOver = CheckWinSet(marker, 0, 1, 2)) { break; } if (gameOver = CheckWinSet(marker, 3, 4, 5)) { break; } if (gameOver = CheckWinSet(marker, 6, 7, 8)) { break; } // Vertical Win if (gameOver = CheckWinSet(marker, 0, 3, 6)) { break; } if (gameOver = CheckWinSet(marker, 1, 4, 7)) { break; } if (gameOver = CheckWinSet(marker, 2, 5, 8)) { break; } // Diagonal Win if (gameOver = CheckWinSet(marker, 0, 4, 8)) { break; } if (gameOver = CheckWinSet(marker, 2, 4, 6)) { break; } break; } if (gameOver) { return marker + " wins!\n"; } // Tie Game if (IsBoardFull()) { gameOver = true; return "No one wins, it's a tie!\n"; } return null; } // Introduce the game to users and explain how to play static void Intro() { Console.WriteLine("\n\n Welcome to Tic Tac Toe!\n\n"); Console.WriteLine(" Currently you can only play against another human player."); Console.WriteLine(" To pick a spot on the Tic Tac Toe board use the keypad or the numbers 1-9."); Console.WriteLine(" You must have num-lock on to be able to use the keypad for input."); Console.WriteLine(" The keypad positions correspond to the Tic Tac Toe board."); // Draws a tic tac toe board with numbers in the spaces to correspond with the numpad Console.WriteLine("\n\n 7 | 8 | 9 "); Console.WriteLine(" ---+---+---"); Console.WriteLine(" 4 | 5 | 6 "); Console.WriteLine(" ---+---+---"); Console.WriteLine(" 1 | 2 | 3\n\n"); Console.WriteLine(" Press any key to start the game!"); Console.ReadKey(true); Console.Clear(); } // The Tic Tac Toe Game's heart static void TicTacToeGame() { char playerTurn = 'O'; string winner = ""; Intro(); DrawBoard(); while (!gameOver) { Console.WriteLine("It is " + playerTurn + "'s turn to move!"); TakeInput(playerTurn); DrawBoard(); winner = CheckWinner(playerTurn); playerTurn = (playerTurn == 'O') ? 'X' : 'O'; } Console.WriteLine(winner); } static void PlayAgain() { Console.WriteLine("Would you like to play again? [Y]es/[N]o?\n"); string response = Console.ReadLine(); switch (response.ToLower()) { case "yes": case "y": gameOver = false; Console.Clear(); ClearBoard(); break; case "no": case "n": newGame = false; Console.Clear(); ClearBoard(); break; default: break; } } static void Main() { // While loop that runs through the intro and a full game of human vs. human tic tac toe // The loop continues until the user responds with a n or no to another game of tic tac toe while (newGame) { TicTacToeGame(); PlayAgain(); } } }}[/source]
#7 Members - Reputation: 1538
Posted 16 November 2012 - 07:41 PM
The text formatting may give you a little bit of a challenge, but his suggestion will lead you into the realm of object-based encapsulation, which will let you have re-usable, adjustable parts like he's suggesting.
There are ten kinds of people in this world: those who understand binary and those who don't.
#9 Members - Reputation: 1297
Posted 17 November 2012 - 12:16 AM
For a weird comparison, think of the difference between "calculating" and actual "math". Math isn't about calculating the result of 2+2, but is more often dealing in abstractions and finding generic solutions to problems. For example n+n = n*n. You can now go and "hard code" it for all numbers from 0 to 1000000 and see which one works (basically the equivalent to hard coding all possible win conditions for tic tac toe), or you can apply math (in programming: come up with an algorithm and apply it):
(n+n)/n = n
n/n + n/n = n
1 + 1 = 0
n = 2
In the same way, when you write code and find yourself doing something really tedious (like writing down all winning combinations) and especially when you start copy/pasting things all over the place, it is time to stop, take a step back and try to understand the pattern or system behind the problem you're solving. That's completely independent of any programming language. The actual "coding" is usually the easy part, where you just need to translate the solution you came up with into your language of choice.
Back to topic:
You already know how to use loops, so in pseudo code, you can start by not saying "if it is this, this, this, this, .... or this state, the player wins, but instead "if in any row or column or diagonal, the same symbol appears 3 times in a row...". Most people end up hard coding it for Tic Tac Toe, because it's quick and easy and unfortunately the board is so small that it's a feasible solution and a generic approach might look like overkill.
So think ahead. There are lots of games where gems, symbols or whatever must be placed in a row to score points. Those grids are usually large enough that hard coding every possible occurrence of 3 in a row/column/diagonal would be pretty insane (and lead to murder, if someone decides to change the number of row or columns on short notice). Point is: if you solve it generically for Tic Tac Toe, you will have a reusable piece of code that will work just as well for all kinds of games or situations where you need to find chains of length n in a grid of size x*y.
Also, whenever you look at a problem and think "the solution is going to be really complicated", find ways to break it down into manageable steps. For example, don't try to handle chains in rows, columns and diagonals all at once. Solve it step by step.
One first step might actually be to write a helper function that will turn x/y coordinates into an array index (and maybe the other way round), so you won't get additional headache from your board being represented by a 1 dimensional array.
#10 Members - Reputation: 119
Posted 17 November 2012 - 10:07 AM
keyPressed = Console.ReadKey(true);
switch (keyPressed.Key)
{
case ConsoleKey.NumPad1:
case ConsoleKey.D1:
// etc...
}
Can be shortened if you test ConsoleKeyInfo.KeyChar instead:
keyPressed = Console.ReadKey(true);
switch (keyPressed.KeyChar)
{
case '1':
// etc...
}
#11 Members - Reputation: 111
Posted 19 November 2012 - 04:55 AM
I've changed the board from a 1D char array to a 2D int array so I could better visualize logic:
[source lang="csharp"]using System;namespace TicTacToeTests{ class Program { const int BOARD_WIDTH = 9; const int BOARD_HEIGHT = 6; static int turnCount = 0; // Is going to be used to determine when the game is at a tie static int[,] board = new int[BOARD_WIDTH, BOARD_HEIGHT]; static void Move(int x, int y, int player) { // Number of spots in a row to win int n = 4; // Check to see if the spot is empty if(board[x,y] == 0) { board[x,y] = player; } turnCount++; int i = 0; int xMatch = 0; // Check Column while (i < (BOARD_WIDTH)) { if (board[i, y] != player) { xMatch = 0; } else { xMatch++; if (xMatch >= n) { Console.WriteLine("\nPlayer " + player + " wins!"); break; } } i++; } int j = 0; int yMatch = 0; // Check Row while (j < (BOARD_HEIGHT)) { if (board[x, j] != player) { yMatch = 0; } else { yMatch++; if (yMatch >= n) { Console.WriteLine("\nPlayer " + player + " wins!"); break; } } j++; } } static void Main(string[] args) { board[2, 4] = 1; board[2, 3] = 1; Move(2, 2, 1); Move(2, 5, 1); } }}[/source]
#12 Members - Reputation: 1538
Posted 19 November 2012 - 06:39 PM
Small tip:
keyPressed = Console.ReadKey(true); switch (keyPressed.Key) { case ConsoleKey.NumPad1: case ConsoleKey.D1: // etc... }
Can be shortened if you test ConsoleKeyInfo.KeyChar instead:keyPressed = Console.ReadKey(true); switch (keyPressed.KeyChar) { case '1': // etc... }
Nice. That's what I was hoping someone would mention. (I don't use C#, but I knew it was there somewhere.)
Once you have the char you can just convert it to an int and have the value mathematically. (If it's ASCII or Unicode then just sub 0x30 from it and cast it to int.) After that just check the range and you have your number with far less code.
@Trienco - I know it's not something that's derived from OOP, I just figured that OOP seems to be the next step for him and it will move him into that paradigm.
Also, I realized last night that I posted something wrong earlier:
[source lang="csharp"]//this is not rightstatic bool CheckWinSet(char board[], int a, int b, int c) { return (board[a] == board[b]) && (board[b] == board[c]);}[/source]
But looking above it seems that you caught and corrected it.
Looking at your most recent post, it looks like you've almost already got a 'Board' or 'Game' class trying to climb out of that. Why not try to make it one?
The class could:
- Accept and process a request to place a player's mark in a specific location
- Check for win/tie
- Draw the board
- Eventually be configurable for different board sizes, more than 2 players?, etc
Edited by Khatharr, 19 November 2012 - 06:56 PM.
There are ten kinds of people in this world: those who understand binary and those who don't.






