diff --git a/Controllers/PrintController.cs b/Controllers/PrintController.cs new file mode 100644 index 00000000..12cc2022 --- /dev/null +++ b/Controllers/PrintController.cs @@ -0,0 +1,87 @@ +using Spectre.Console; + +namespace mathGame.qua9k.Controllers; + +internal static class PrintController +{ + internal static void Welcome() + { + AnsiConsole.Clear(); + + AnsiConsole.MarkupLine( + """ + [blue]***********************************************[/] + [blue]*** Welcome to the Tiny Math Game ***[/] + [blue]***********************************************[/] + + What would you like to do? + + [green]p: play game[/] + [red]x: exit game[/] + [yellow]h: view history[/] + + """ + ); + AnsiConsole.Write("Please make a choice: "); + } + + internal static void PresentRules(int winningScore, int losingScore) + { + AnsiConsole.Clear(); + AnsiConsole.MarkupLine( + $""" + [yellow]********************************************[/] + [yellow]***** Tiny Math Game Rules *****[/] + [yellow]********************************************[/] + + - Answer [green]correctly[/] and earn 1 point. + - Answer [red]incorrectly[/] and lose 1 point. + - To win, reach {winningScore} points. + - You will lose if you reach {losingScore} points. + + """ + ); + Pause(); + } + + internal static void Pause() + { + AnsiConsole.Markup("[blue]Press any key to continue.[/] "); + Console.ReadKey(); + } + + internal static void PrintHistory(List<(string Result, string PlayTime)> history) + { + if (history.Count < 1) + { + AnsiConsole.MarkupLine("You haven't played any games!"); + Pause(); + return; + } + + AnsiConsole.Clear(); + AnsiConsole.MarkupLine( + """ + [yellow]*********************************************[/] + [yellow]********** Play History ***********[/] + [yellow]*********************************************[/] + + """ + ); + + var table = new Table(); + + table.AddColumn("[blue]Game[/]"); + table.AddColumn("[blue]Result[/]"); + table.AddColumn("[blue]Play Time (Seconds)[/]"); + + for (int i = 0; i < history.Count; i += 1) + { + table.AddRow($"{i + 1}", $"{history[i].Result}", $"{history[i].PlayTime}"); + } + + AnsiConsole.Write(table); + AnsiConsole.Write(""); + Pause(); + } +} diff --git a/Enums.cs b/Enums.cs new file mode 100644 index 00000000..13cfb977 --- /dev/null +++ b/Enums.cs @@ -0,0 +1,10 @@ +namespace mathGame.qua9k; + +internal enum Operator +{ + Add, + Subtract, + Multiply, + Divide, + Random, +} diff --git a/Models/Game.cs b/Models/Game.cs new file mode 100644 index 00000000..c4924c5c --- /dev/null +++ b/Models/Game.cs @@ -0,0 +1,172 @@ +using System.Diagnostics; +using mathGame.qua9k.Controllers; +using Spectre.Console; + +namespace mathGame.qua9k.Models; + +internal class Game +{ + readonly List<(string Result, string PlayTime)> history = []; + + readonly Dictionary operatorMap = new() + { + { Operator.Add, "+" }, + { Operator.Subtract, "-" }, + { Operator.Divide, "/" }, + { Operator.Multiply, "*" }, + { Operator.Random, "?" }, + }; + + internal void Initialize() + { + bool keepPlaying = true; + + while (keepPlaying) + { + PrintController.Welcome(); + + string? playerInput = Console.ReadLine(); + + switch (playerInput!.ToLower()) + { + case "p": + Play(); + break; + case "x": + keepPlaying = false; + break; + case "h": + PrintController.PrintHistory(history); + break; + default: + break; + } + } + + AnsiConsole.WriteLine("Thank you for playing. Goodbye!"); + } + + internal void Play(int winningScore = 5, int losingScore = -3) + { + var stopwatch = Stopwatch.StartNew(); + int playerScore = 0; + + PrintController.PresentRules(winningScore, losingScore); + + while (true) + { + AnsiConsole.Clear(); + + var choice = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("Please choose one:") + .AddChoices(Enum.GetValues()) + ); + + int operand1 = Random.Shared.Next(0, 100); + int operand2 = Random.Shared.Next(0, 100); + + if (choice == Operator.Random) + { + choice = GetRandomOperator(choice); + } + + if (choice == Operator.Divide) + { + while (operand1 <= operand2 || operand1 % operand2 != 0) + { + operand1 = Random.Shared.Next(0, 100); + operand2 = Random.Shared.Next(1, 100); + } + } + + string question = $"{operand1} {operatorMap[choice]} {operand2} = "; + + AnsiConsole.Write(question); + + string? playerAnswer = Console.ReadLine(); + + while (!int.TryParse(playerAnswer, out int _)) + { + AnsiConsole.WriteLine($"Your answer was not understood. Please try again."); + PrintController.Pause(); + AnsiConsole.Clear(); + AnsiConsole.Write(question); + playerAnswer = Console.ReadLine(); + } + + if (Convert.ToInt32(playerAnswer) == CalculateAnswer(choice, operand1, operand2)) + { + playerScore += 1; + AnsiConsole.MarkupLine($"[green]Correct![/]"); + } + else + { + playerScore -= 1; + AnsiConsole.MarkupLine($"[yellow]Incorrect...[/]"); + } + + AnsiConsole.WriteLine($"Your score: {playerScore}"); + PrintController.Pause(); + + bool playerWon = playerScore >= winningScore; + bool playerLost = playerScore <= losingScore; + bool isGameOver = playerWon || playerLost; + + if (isGameOver) + { + stopwatch.Stop(); + + (string Result, string PlayTime) t = ( + "", + Convert.ToString(stopwatch.ElapsedMilliseconds / 1000) + ); + + if (playerWon) + { + t.Result = "Won"; + AnsiConsole.Clear(); + AnsiConsole.MarkupLine($"[green]Congratulations. You won![/]"); + } + + if (playerLost) + { + t.Result = "Loss"; + AnsiConsole.Clear(); + AnsiConsole.MarkupLine($"[red]You lost... :([/]"); + } + + history.Add(t); + + PrintController.Pause(); + + break; + } + } + } + + internal static int CalculateAnswer(Operator op, int operand1, int operand2) + { + return op switch + { + Operator.Add => operand1 + operand2, + Operator.Subtract => operand1 - operand2, + Operator.Divide => operand1 / operand2, + Operator.Multiply => operand1 * operand2, + _ => 0, + }; + } + + internal static Operator GetRandomOperator(Operator choice) + { + Random random = new(); + + while (choice == Operator.Random) + { + int i = random.Next(0, Enum.GetNames().Length); + choice = (Operator)i; + } + + return choice; + } +} diff --git a/Program.cs b/Program.cs new file mode 100644 index 00000000..be440338 --- /dev/null +++ b/Program.cs @@ -0,0 +1,4 @@ +using mathGame.qua9k.Models; + +Game game = new(); +game.Initialize(); diff --git a/README.md b/README.md new file mode 100644 index 00000000..971fb0d0 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# MathGame + +A tiny, basic math console game. diff --git a/mathGame.qua9k.csproj b/mathGame.qua9k.csproj new file mode 100644 index 00000000..aa8486be --- /dev/null +++ b/mathGame.qua9k.csproj @@ -0,0 +1,14 @@ + + + + Exe + net10.0 + enable + enable + + + + + + +