[C#] Console Based Game - TicTacToe

AceInfinity

Emeritus, Contributor
Joined
Feb 21, 2012
Posts
1,728
Location
Canada
So, there haven't been a whole bunch of console based games released from what I seen, so I thought it would be cool to demonstrate what you can do with console applications in that regard on a very simple level. You can probably get into ASCII art and all that fancy stuff to make your own cutscenes for a more advanced storyline game and all of that, with colors perhaps too... But I decided to stick with a game that everybody should know, Tic-Tac-Toe.

In addition to that, I'm not very good at ASCII art, so I didn't even attempt that lol.

Image preview:
fbOKBCD.png


And here is a video preview of the game:

And the source code:
Code:
[PLAIN]const int xOrig = 2;
const int yOrig = 4;

const int xStep = 4;
const int yStep = 2;

static int[] pos = new int[2];
static Player[,] board = new Player[3, 3];
static Player winner = Player.None;

enum Player
{
	None = 0,
	P1,
	P2
}

static void Main(string[] args)
{
	Console.CursorSize = 100;
	ConsoleKey playAgain = ConsoleKey.Y;
	while (playAgain == ConsoleKey.Y)
	{
		Player currentPlayer = Player.P1;
		while (!GameOver())
		{
			GetUserMove(currentPlayer);
			currentPlayer = currentPlayer == Player.P1 ? Player.P2 : Player.P1;
		}

		DisplayBoard(Player.None);
		Console.SetCursorPosition(0, 13);

		if (winner == Player.None)
		{
			Console.WriteLine("It was a draw...");
		}
		else
		{
			Console.WriteLine("The winner is: Player {0}", winner == Player.P1 ? '1' : '2');
		}

		ResetGame();
		Console.WriteLine("Play Again? [Y/N]\n");
		playAgain = Console.ReadKey().Key;
	}
}

static void GetUserMove(Player currentPlayer)
{
	bool validMove = false;
	while (!validMove)
	{
		DisplayBoard(currentPlayer);
		Console.CursorLeft += 2;
		Console.CursorTop -= 8;

		pos[0] = Console.CursorLeft;
		pos[1] = Console.CursorTop;

		ConsoleKey conKey = ConsoleKey.NoName;
		while ((conKey = Console.ReadKey().Key) != ConsoleKey.Enter)
		{
			DisplayBoard(currentPlayer);
			switch (conKey)
			{
				case ConsoleKey.UpArrow:
					if (pos[1] == 8 || pos[1] == 6) pos[1] -= 2;
					break;
				case ConsoleKey.DownArrow:
					if (pos[1] < 8) pos[1] += 2;
					break;
				case ConsoleKey.LeftArrow:
					if (pos[0] > 2) pos[0] -= 4;
					break;
				case ConsoleKey.RightArrow:
					if (pos[0] < 10) pos[0] += 4;
					break;
			}

			Console.SetCursorPosition(pos[0], pos[1]);
		}

		int x = (pos[1] - yOrig) / yStep;
		int y = (pos[0] - xOrig) / xStep;
		if (board[x, y] == Player.None)
		{
			board[x, y] = currentPlayer;
			validMove = true;
		}
		else
		{
			Console.Clear();
			Console.WriteLine("That spot already has a marker! Please place your marker elsewhere...");
			Console.WriteLine("(Press any key to continue...)");
			Console.ReadKey();
		}
	}
}

static void DisplayBoard(Player currentPlayer)
{
	Console.Clear();
	DisplayInstructions();
	Console.WriteLine("-------------");
	for (int row = 0; row < 3; row++)
	{
		char[] arr = new char[3];
		for (int col = 0; col < 3; col++)
		{
			if (board[row, col] == Player.None)
			{
				arr[col] = ' ';
			}
			else
			{
				arr[col] = board[row, col] == Player.P1 ? 'X' : 'O';
			}
		}
		Console.WriteLine("| {0} |", string.Join(" | ", arr));
		Console.WriteLine("-------------");
	}
	Console.WriteLine("\nPlayer {0}'s Turn...", currentPlayer == Player.P1 ? '1' : '2');
}

static bool GameOver()
{
	// Reading order
	bool boardComplete = true;
	for (int row = 0; row < 3; row++)
	{
		for (int col = 0; col < 3; col++)
		{
			Player player = Player.None;
			if ((player = board[row, col]) != Player.None)
			{
				// Check row
				{
					for (int i = 0; i < 3; i++)
					{
						if (board[row, i] != player)
						{
							break;
						}
						else if (i == 2)
						{
							winner = player;
							return true;
						}
					}
				}

				// Check column
				{
					for (int i = 0; i < 3; i++)
					{
						if (board[i, col] != player)
						{
							break;
						}
						else if (i == 2)
						{

							winner = player;
							return true;
						}
					}
				}

				// Determines whether we should check the diagonals
				if ((row == 1 && col == 1) || (col != 1 && row != 1))
				{
					for (int i = 0; i < 3; i++)
					{
						if (board[i, i] != player)
						{
							break;
						}
						else if (i == 2)
						{
							winner = player;
							return true;
						}
					}

					for (int i = 2, j = 0; j < 3; i--, j++)
					{
						if (board[i, j] != player)
						{
							break;
						}
						else if (j == 2)
						{
							winner = player;
							return true;
						}
					}
				}
			}
			else
			{
				boardComplete = false;
			}
		}
	}

	if (boardComplete)
	{
		return true;
	}
	return false;
}

static void ResetGame()
{
	board = new Player[3, 3];
	winner = Player.None;
}

static void DisplayInstructions()
{
	Console.WriteLine("Note: Use the arrow keys to navigate.\n(Press enter when you want to place your marker.)\n");
}[/PLAIN]

Note: All the console position values are hardcoded in there (the origin and the winner display anyways). The rest is calculated by displacement's from the origin at "(0,0)" on the grid, which is more like (2, 4) I believe in the console buffer-wise.
 
I like making this game in code. :grin1: I think I've only managed it in Python so far, I should make one in C++.

I like the use of Arrow keys to control, my versions always use the basic "enter a number". You could divide GetUserMove into two functions and have an AI function - I found trying to add decent AI to console games a mixture of fun and extreme frustration. Think I might have had a thread here on one, could never work out how I made the AI work.
 
I like making this game in code. :grin1: I think I've only managed it in Python so far, I should make one in C++.

I like the use of Arrow keys to control, my versions always use the basic "enter a number". You could divide GetUserMove into two functions and have an AI function - I found trying to add decent AI to console games a mixture of fun and extreme frustration. Think I might have had a thread here on one, could never work out how I made the AI work.

I actually don't find AI that difficult, the logic just comes naturally to me when I brainstorm how to do things automatically. After all AI is my name :lol:.
 
It was trying to do multiple levels of checking for a win that got to me. I understand the principle of it, but working out how to make a decent recursive function for checking whether each possible move would win was a challenge. I couldn't get it to work successfully recursively.

Very basic stuff really, but a struggle when you're first learning.
 
You would just check if there's 2 of the same marker in the current row or column then place in the existing one. Otherwise, play roulette with some common strategies of winning, like forming a triangle of markers on 3 corners while the middle is still open. (In hope to catch a win/win situation where they can't block 2 moves that would allow you to win.) It's harder to explain, but much easier when you form a system of linear equations for the grid. I think this is where my matrix class programming would be useful, more likely the linear algebra concepts behind it though... Sorry it's early in my timezone right now.
 
I remember trying to make it fairly advanced (for a simple game anyway). First, the computer would check if there was an immediate winning move it could make. Then, it would simulate the moves in each possible position - for every open space on the board, it would play there and simulate the players turn in each possible location checking for a win for either player. It was meant to keep doing that recursively until it found the fastest possible wining moves, or could always force a draw. I think I also included a list of "default" good moves as well, but it was mainly a programming challenge I was trying.
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top