Last active
September 26, 2024 18:15
-
-
Save peterthorsteinson/6e282d9cfb58bb500899d6ca4ed9f17d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://en.wikipedia.org/wiki/Tic-tac-toe and http://www.se16.info/hgb/tictactoe.htm | |
// If played properly, tic-tac-toe will end in a draw, making tic-tac-toe a futile game. | |
// Total number of X and O placements on a 3x3 grid = 9! = 362880, but many games end before completely filling in the grid. | |
// Also, many tic-tac-toe outcomes are logically equivalent in terms of reflection and rotation symmetries. | |
using System; | |
namespace TicTacToe | |
{ | |
class Program | |
{ | |
static void Main() | |
{ | |
while (true) // each iteration of this outer loop is a new game | |
{ | |
int i = 1; // center cell position in 0, 1, 2 columns | |
int j = 1; // center cell position in 0, 1, 2 rows | |
bool xIsNext = true; // true if next move is X, false if next move is O | |
string outcome = ""; // gets the string "X" if X wins, "O" if O wins, or "" for a draw | |
string[,] board = { { "", "", "" }, { "", "", "" }, { "", "", "" } }; | |
int moveCount = 0; // can never be more than 9 moves where each X or O placement is a single move | |
Console.Clear(); | |
WriteAt(0, 0, " | | "); | |
WriteAt(0, 1, "---+---+---"); | |
WriteAt(0, 2, " | | "); | |
WriteAt(0, 3, "---+---+---"); | |
WriteAt(0, 4, " | | "); | |
Console.SetCursorPosition(10, 10); | |
Console.WriteLine("Use arrow keys to move from cell to cell and hit enter to place a token."); | |
Console.CursorLeft = 1; | |
Console.CursorTop = 0; | |
Console.SetCursorPosition(1 + (4 * i), 2 * j); // offsets and multiliers to position in cell centers | |
while (true) // each iteration of this inner loop is the placement of an "X" or a "Y as a single move | |
{ | |
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey(true); // get a key stroke without echo to output | |
switch (consoleKeyInfo.Key) | |
{ | |
case ConsoleKey.RightArrow: | |
i = (i + 1) % 3; | |
Console.SetCursorPosition(1 + (4 * i), 2 * j); | |
break; | |
case ConsoleKey.LeftArrow: | |
i = (i + 2) % 3; | |
Console.SetCursorPosition(1 + (4 * i), 2 * j); | |
break; | |
case ConsoleKey.DownArrow: | |
j = (j + 1) % 3; | |
Console.SetCursorPosition(1 + (4 * i), 2 * j); | |
break; | |
case ConsoleKey.UpArrow: | |
j = (j + 2) % 3; | |
Console.SetCursorPosition(1 + (4 * i), 2 * j); | |
break; | |
case ConsoleKey.Enter: | |
if (board[i, j] != "") { Console.Beep(); break; } // cannot place X or O in cell that is already played | |
string token = xIsNext ? "X" : "O"; // select token to place in cell for this move | |
board[i, j] = token; | |
WriteAt(1 + (4 * i), 2 * j, token); | |
xIsNext = !xIsNext; // alternate X/O token for next move | |
moveCount++; // count number of completed moves so far | |
break; | |
} | |
outcome = WhoWon(board, moveCount); | |
if (outcome != "") break; | |
} | |
Console.SetCursorPosition(10, 10); | |
Console.WriteLine("Game Over. Winner: " + outcome + ". Hit q to quit, or hit any other key to play again."); | |
if (Console.ReadKey(true).Key == ConsoleKey.Q) break; else continue; | |
} | |
Console.Clear(); | |
} | |
protected static void WriteAt(int x, int y, string s) | |
{ | |
try | |
{ | |
Console.SetCursorPosition(x, y); | |
Console.Write(s); | |
} | |
catch (ArgumentOutOfRangeException e) | |
{ | |
Console.Clear(); | |
Console.WriteLine(e.Message); | |
} | |
} | |
protected static string WhoWon(string[,] board, int moveCount) | |
{ | |
// check to see if X won yet | |
if (board[0, 0] == "X" && board[0, 1] == "X" && board[0, 2] == "X" || | |
(board[1, 0] == "X" && board[1, 1] == "X" && board[1, 2] == "X") || | |
(board[2, 0] == "X" && board[2, 1] == "X" && board[2, 2] == "X") || | |
(board[0, 0] == "X" && board[1, 0] == "X" && board[2, 0] == "X") || | |
(board[0, 1] == "X" && board[1, 1] == "X" && board[2, 1] == "X") || | |
(board[0, 2] == "X" && board[1, 2] == "X" && board[2, 2] == "X") || | |
(board[0, 0] == "X" && board[1, 1] == "X" && board[2, 2] == "X") || | |
(board[0, 2] == "X" && board[1, 1] == "X" && board[2, 0] == "X")) return "X"; | |
// check to see if O won yet | |
if (board[0, 0] == "O" && board[0, 1] == "O" && board[0, 2] == "O" || | |
(board[1, 0] == "O" && board[1, 1] == "O" && board[1, 2] == "O") || | |
(board[2, 0] == "O" && board[2, 1] == "O" && board[2, 2] == "O") || | |
(board[0, 0] == "O" && board[1, 0] == "O" && board[2, 0] == "O") || | |
(board[0, 1] == "O" && board[1, 1] == "O" && board[2, 1] == "O") || | |
(board[0, 2] == "O" && board[1, 2] == "O" && board[2, 2] == "O") || | |
(board[0, 0] == "O" && board[1, 1] == "O" && board[2, 2] == "O") || | |
(board[0, 2] == "O" && board[1, 1] == "O" && board[2, 0] == "O")) return "O"; | |
// max number of completed moves is 9 | |
if (moveCount == 9) return "Draw"; | |
return ""; // game still in play (no winner yet, and ;ess than 9 moves have been completed | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment