Jump to content

  • Log In with Google      Sign In   
  • Create Account

Completed Tic Tac Toe - Critical Critiques and Advice


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 Maurice Harris   Members   -  Reputation: 126

Like
0Likes
Like

Posted 15 November 2012 - 05:32 PM

Hello, my name is Maurice Harris and recently while learning my first language(C#) I have completed my first game, Tic Tac Toe. I am here before you all asking for critique and advice on my design of the game Tic Tac Toe. Although I am relieved to have finally completed my first game I feel as though it could use serious improvement design-wise and would like helpful advice on how to improve not only my game but also my programming skills so I can become a much better programmer and avoid the headaches I faced making what I thought would be a simple game to create. So without further ado I present my version of the classic Tic Tac Toe.

[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]

Sponsor:

#2 Khatharr   Crossbones+   -  Reputation: 3040

Like
2Likes
Like

Posted 15 November 2012 - 09:20 PM

SpaceFree() could be IsSpaceFree(), for more clarity that it's checking rather than freeing.

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! Posted Image

Edited by Khatharr, 15 November 2012 - 10:25 PM.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#3 Trienco   Crossbones+   -  Reputation: 2224

Like
4Likes
Like

Posted 15 November 2012 - 11:18 PM

I think you will get the most in terms of learning experience and better design by not assuming a fixed board size and hard coding every possible win condition. After all, the real core of programming isn't knowing language X or memorizing whole libraries, but about problem solving.

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.
f@dzhttp://festini.device-zero.de

#4 Codarki   Members   -  Reputation: 462

Like
1Likes
Like

Posted 16 November 2012 - 02:31 PM

First, that is pretty well done, very easy to read.

I noticed this:

I see main()'s board getting passed into a lot of member functions. Why not make it a member variable?

Which brings me to the issue that this whole program has only static methods. So the suggestion of adding a member variable wont work.

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 Khatharr   Crossbones+   -  Reputation: 3040

Like
1Likes
Like

Posted 16 November 2012 - 04:11 PM


I see main()'s board getting passed into a lot of member functions. Why not make it a member variable?

Which brings me to the issue that this whole program has only static methods. So the suggestion of adding a member variable wont work.


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.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#6 Maurice Harris   Members   -  Reputation: 126

Like
0Likes
Like

Posted 16 November 2012 - 07:01 PM

I made the suggestions you gave to me and my program feels and looks less bloated. I feel once I get further along in reading The C# Yellow Book by Robert Miles, I'll be able to improve upon my design little by little until I'm satisfied. I just recently got to the 4th chapter of the book and it's starting to talk about objects and how to represent them so hopefully I'll be able to come back very soon and further improve the design of this and future projects. Trienco, I've been thinking about what you said about having a board that's 4x4, 5x5, or any random 2 values and I'm having trouble thinking about how I could handle this without thinking myself into a corner.

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 Khatharr   Crossbones+   -  Reputation: 3040

Like
1Likes
Like

Posted 16 November 2012 - 07:41 PM

Once you're comfortable with OOP you should see some ways to do things like that.

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.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#8 Maurice Harris   Members   -  Reputation: 126

Like
0Likes
Like

Posted 16 November 2012 - 07:45 PM

Great, I'll go back to reading for now. Thank you all for giving me advice and help, I hope to share better projects in the future.

#9 Trienco   Crossbones+   -  Reputation: 2224

Like
0Likes
Like

Posted 17 November 2012 - 12:16 AM

I wouldn't actually focus on OOP for the things I described. Those are simply applications of loops.

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.
f@dzhttp://festini.device-zero.de

#10 YellPika   Members   -  Reputation: 142

Like
1Likes
Like

Posted 17 November 2012 - 10:07 AM

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


#11 Maurice Harris   Members   -  Reputation: 126

Like
0Likes
Like

Posted 19 November 2012 - 04:55 AM

I figured out how to generalize my win checking like you said Trienco. Lately I've been trying to make it work so if for example I had a 9x6 board it would check for n in a row every time someone made a move, however I find that I end up repeating myself, my code becomes bloated, and I haven't figured out how to check for diagonal wins where x != y.

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 Khatharr   Crossbones+   -  Reputation: 3040

Like
0Likes
Like

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. Posted Image

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.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS