Advertisement
mquinlan

TicTacToe

Aug 3rd, 2024 (edited)
298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.31 KB | Gaming | 0 0
  1. internal enum GameStatus
  2. {
  3.     OnGoing,
  4.     Tied,
  5.     XWin,
  6.     OWin
  7. }
  8.  
  9. internal static class Program
  10. {
  11.     private static void Main()
  12.     {
  13.         Console.WriteLine("---------------------");
  14.         Console.WriteLine("Welcome to TicTacToe:");
  15.         Console.WriteLine("---------------------");
  16.         Console.WriteLine();
  17.         Console.WriteLine("The rules are as follows: ");
  18.         Console.WriteLine(
  19.             "1. To make a move Type \"T\" for TOP, \"B\" for BOTTOM, \"M\" for MIDDLE, \"L\" for LEFT and \"R\" for RIGHT");
  20.         Console.WriteLine("2. Combine the letters to reach the corners: TR (top right), BL (bottom left)");
  21.         Console.WriteLine("3. The rest of the game will play out as a normal TicTacToe game, but the ai is random :P");
  22.         Console.WriteLine();
  23.  
  24.         bool playAgain;
  25.         do
  26.         {
  27.             PlayGame();
  28.             Console.WriteLine("Do you want to continue playing? (Y/N)");
  29.             var answer = Console.ReadLine()?.ToUpper() ?? "N";
  30.             playAgain = answer == "Y";
  31.         } while (playAgain);
  32.     }
  33.  
  34.     private static void PlayGame()
  35.     {
  36.         char[,] playingField =
  37.         {
  38.             { ' ', ' ', ' ' },
  39.             { ' ', ' ', ' ' },
  40.             { ' ', ' ', ' ' },
  41.         };
  42.        
  43.         while (true)
  44.         {
  45.             PrintPlayingField(playingField);
  46.             MakeHumanMove(playingField);
  47.             var gameStatus = GetGameStatus(playingField);
  48.             if (gameStatus is not GameStatus.OnGoing)
  49.             {
  50.                 ReportGameStatus(gameStatus);
  51.                 return;
  52.             }
  53.  
  54.             MakeComputerMove(playingField);
  55.             gameStatus = GetGameStatus(playingField);
  56.             if (gameStatus is not GameStatus.OnGoing)
  57.             {
  58.                 ReportGameStatus(gameStatus);
  59.                 return;
  60.             }
  61.             Console.WriteLine();
  62.         }
  63.  
  64.         void ReportGameStatus(GameStatus gameStatus)
  65.         {
  66.             Console.WriteLine(gameStatus switch
  67.             {
  68.                 GameStatus.Tied => "GAME IS TIED!",
  69.                 GameStatus.XWin => "YOU WIN!",
  70.                 GameStatus.OWin => "YOU LOSE!",
  71.                 _ => throw new ArgumentOutOfRangeException()
  72.             });
  73.         }
  74.     }
  75.  
  76.     private static void MakeComputerMove(char[,] playingField)
  77.     {
  78.         var bestScore = int.MinValue;
  79.         var bestMove = (-1, -1);
  80.  
  81.         for (var row = 0; row < playingField.GetLength(0); row++)
  82.         {
  83.             for (var col = 0; col < playingField.GetLength(1); col++)
  84.             {
  85.                 if (playingField[row, col] is ' ')
  86.                 {
  87.                     playingField[row, col] = 'O';
  88.                     var score = Minimax(false, playingField);
  89.                     playingField[row, col] = ' ';
  90.                     if (score > bestScore)
  91.                     {
  92.                         bestScore = score;
  93.                         bestMove = (row, col);
  94.                     }
  95.                 }
  96.             }
  97.         }
  98.  
  99.         playingField[bestMove.Item1, bestMove.Item2] = 'O';
  100.     }
  101.  
  102.     private static int Minimax(bool isMaximizing, char[,] playingField)
  103.     {
  104.         var gameStatus = GetGameStatus(playingField);
  105.         if (gameStatus is GameStatus.Tied) return 0;
  106.         if (gameStatus is not GameStatus.OnGoing) return isMaximizing ? -1 : 1;
  107.  
  108.         if (isMaximizing)
  109.         {
  110.             var bestScore = int.MinValue;
  111.             for (var row = 0; row < playingField.GetLength(0); row++)
  112.             {
  113.                 for (var col = 0; col < playingField.GetLength(1); col++)
  114.                 {
  115.                     if (playingField[row, col] is ' ')
  116.                     {
  117.                         playingField[row, col] = 'O';
  118.                         var score = Minimax(false, playingField);
  119.                         playingField[row, col] = ' ';
  120.                         bestScore = Math.Max(bestScore, score);
  121.                     }
  122.                 }
  123.             }
  124.             return bestScore;
  125.         }
  126.         else
  127.         {
  128.             var bestScore = int.MaxValue;
  129.             for (var row = 0; row < playingField.GetLength(0); row++)
  130.             {
  131.                 for (var col = 0; col < playingField.GetLength(1); col++)
  132.                 {
  133.                     if (playingField[row, col] is ' ')
  134.                     {
  135.                         playingField[row, col] = 'X';
  136.                         var score = Minimax(true, playingField);
  137.                         playingField[row, col] = ' ';
  138.                         bestScore = Math.Min(bestScore, score);
  139.                     }
  140.                 }
  141.             }
  142.             return bestScore;
  143.         }
  144.     }
  145.  
  146.     private static void MakeHumanMove(char[,] playingField)
  147.     {
  148.         Console.WriteLine();
  149.         while (true)
  150.         {
  151.             Console.Write("Make a move!: ");
  152.             var playerMove = Console.ReadLine()?.Trim().ToUpper() ?? string.Empty;
  153.             if (playerMove.Length is 1) playerMove += " ";
  154.             var (row, col) = playerMove switch
  155.             {
  156.                 "TL" => (0, 0),
  157.                 "T " => (0, 1),
  158.                 "TR" => (0, 2),
  159.                 "L " => (1, 0),
  160.                 "M " => (1, 1),
  161.                 "R " => (1, 2),
  162.                 "BL" => (2, 0),
  163.                 "B " => (2, 1),
  164.                 "BR" => (2, 2),
  165.                 _ => (-1, -1)
  166.             };
  167.             if (row is -1 || playingField[row, col] is not ' ')
  168.             {
  169.                 Console.WriteLine("You blew that one, meathead!");
  170.                 continue;
  171.             }
  172.  
  173.             playingField[row, col] = 'X';
  174.             return;
  175.         }
  176.     }
  177.  
  178.     private static GameStatus GetGameStatus(char[,] playingField)
  179.     {
  180.         if (IsSame((0, 0), (0, 1), (0, 2))) return GetWinStatus(playingField[0, 0]);
  181.         if (IsSame((1, 0), (1, 1), (1, 2))) return GetWinStatus(playingField[1, 0]);
  182.         if (IsSame((2, 0), (2, 1), (2, 2))) return GetWinStatus(playingField[2, 0]);
  183.         if (IsSame((0, 0), (1, 0), (2, 0))) return GetWinStatus(playingField[0, 0]);
  184.         if (IsSame((0, 1), (1, 1), (2, 1))) return GetWinStatus(playingField[0, 1]);
  185.         if (IsSame((0, 2), (1, 2), (2, 2))) return GetWinStatus(playingField[0, 2]);
  186.         if (IsSame((0, 0), (1, 1), (2, 2))) return GetWinStatus(playingField[0, 0]);
  187.         if (IsSame((0, 2), (1, 1), (2, 0))) return GetWinStatus(playingField[0, 2]);
  188.  
  189.         return AnyEmptySquares() ? GameStatus.OnGoing : GameStatus.Tied;
  190.  
  191.         bool IsSame((int row, int col) a, (int row, int col) b, (int row, int col) c) =>
  192.             playingField[a.row, a.col] is not ' '
  193.             && playingField[a.row, a.col] == playingField[b.row, b.col]
  194.             && playingField[b.row, b.col] == playingField[c.row, c.col];
  195.  
  196.         GameStatus GetWinStatus(char player) => player is 'X' ? GameStatus.XWin : GameStatus.OWin;
  197.  
  198.         bool AnyEmptySquares()
  199.         {
  200.             for (var row = 0; row < playingField.GetLength(0); row++)
  201.             {
  202.                 for (var col = 0; col < playingField.GetLength(1); col++)
  203.                 {
  204.                     if (playingField[row, col] is ' ') return true;
  205.                 }
  206.             }
  207.  
  208.             return false;
  209.         }
  210.     }
  211.  
  212.     private static void PrintPlayingField(char[,] playingField)
  213.     {
  214.         for (var row = 0; row < playingField.GetLength(0); row++)
  215.         {
  216.             for (var col = 0; col < playingField.GetLength(1); col++)
  217.             {
  218.                 Console.Write(GetDisplay(playingField[row, col], row, col));
  219.                 Console.Write(' ');
  220.             }
  221.  
  222.             Console.WriteLine();
  223.         }
  224.  
  225.         string GetDisplay(char ch, int row, int col)
  226.         {
  227.             return ch switch
  228.             {
  229.                 'X' => "*X",
  230.                 'O' => "*O",
  231.                 _ => (row, col) switch
  232.                 {
  233.                     (0, 0) => "TL",
  234.                     (0, 1) => "T ",
  235.                     (0, 2) => "TR",
  236.                     (1, 0) => "L ",
  237.                     (1, 1) => "M ",
  238.                     (1, 2) => "R ",
  239.                     (2, 0) => "BL",
  240.                     (2, 1) => "B ",
  241.                     (2, 2) => "BR",
  242.                     _ => throw new ArgumentOutOfRangeException()
  243.                 }
  244.             };
  245.         }
  246.     }
  247. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement