diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..2efc0762
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "dotnet.defaultSolution": "MathGame.sln"
+}
\ No newline at end of file
diff --git a/MathGame.sln b/MathGame.sln
new file mode 100644
index 00000000..6bc6d048
--- /dev/null
+++ b/MathGame.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MathGame.vitorvelozo", "MathGame.vitorvelozo\MathGame.vitorvelozo.csproj", "{285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Debug|x64.Build.0 = Debug|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Debug|x86.Build.0 = Debug|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Release|x64.ActiveCfg = Release|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Release|x64.Build.0 = Release|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Release|x86.ActiveCfg = Release|Any CPU
+ {285CA9B0-CBE7-49C5-840F-AA8F7EAD0CD8}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/MathGame.vitorvelozo/MathGame.vitorvelozo.csproj b/MathGame.vitorvelozo/MathGame.vitorvelozo.csproj
new file mode 100644
index 00000000..452a0af1
--- /dev/null
+++ b/MathGame.vitorvelozo/MathGame.vitorvelozo.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/MathGame.vitorvelozo/Program.cs b/MathGame.vitorvelozo/Program.cs
new file mode 100644
index 00000000..5faa2a04
--- /dev/null
+++ b/MathGame.vitorvelozo/Program.cs
@@ -0,0 +1,49 @@
+using CodeReviews.Console.MathGame.Controllers;
+using CodeReviews.Console.MathGame.Models;
+using CodeReviews.Console.MathGame.Views;
+
+Game RunGame()
+{
+ GameDifficulty difficulty = MainMenu.GetDifficulty();
+ bool randomMode = MainMenu.GetRandomMode();
+
+ Game game = new Game(difficulty, randomMode: randomMode);
+
+ for (int i = 0; i < game.GameLength; i++)
+ {
+ QuestionGenerator randomGenerator;
+ if (!randomMode)
+ {
+ randomGenerator = new QuestionGenerator(difficulty, QuestionMenu.GetOperation()
+ );
+ } else
+ {
+ randomGenerator = new QuestionGenerator(difficulty);
+ }
+ Question question = randomGenerator.GenerateQuestion();
+ game.Questions.Add(question);
+
+ question.StartTime = TimeOnly.FromDateTime(DateTime.Now);
+ question.ProvidedAnswer = QuestionMenu.GetQuestionAnswer(question);
+ question.FinishTime = TimeOnly.FromDateTime(DateTime.Now);
+ game.PlayerScore += QuestionEvaluator.Evaluate(question);
+ }
+ return game;
+}
+
+void Main()
+{
+ MainMenu.DisplayWelcome();
+ MathSet mathSet = new MathSet();
+
+ bool keepPlaying;
+ do
+ {
+ mathSet.AddGame(RunGame());
+ keepPlaying = GameMenu.Display(mathSet);
+ } while (keepPlaying);
+
+ ResultScreen.Display(mathSet);
+}
+
+Main();
diff --git a/MathGame.vitorvelozo/controllers/Evaluation.cs b/MathGame.vitorvelozo/controllers/Evaluation.cs
new file mode 100644
index 00000000..1bd1b474
--- /dev/null
+++ b/MathGame.vitorvelozo/controllers/Evaluation.cs
@@ -0,0 +1,41 @@
+using CodeReviews.Console.MathGame.Models;
+
+namespace CodeReviews.Console.MathGame.Controllers;
+
+public static class QuestionEvaluator
+{
+ private static int CalculateResult(int firstNumber, int secondNumber, MathOperation operation)
+ {
+ int result;
+ switch (operation)
+ {
+ case MathOperation.Addition:
+ result = firstNumber + secondNumber;
+ break;
+ case MathOperation.Subtraction:
+ result = firstNumber - secondNumber;
+ break;
+ case MathOperation.Multiplication:
+ result = firstNumber * secondNumber;
+ break;
+ case MathOperation.Division:
+ result = firstNumber / secondNumber;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(operation), operation, null);
+ }
+ return result;
+ }
+
+ public static int Evaluate(Question question)
+ {
+ question.Result = CalculateResult(question.FirstNumber, question.SecondNumber, question.Operation);
+ int answer;
+ if (int.TryParse(question.ProvidedAnswer, out answer))
+ {
+ question.IsAnswerCorrect = answer == question.Result;
+ return 1;
+ }
+ return 0;
+ }
+}
diff --git a/MathGame.vitorvelozo/controllers/QuestionGeneration.cs b/MathGame.vitorvelozo/controllers/QuestionGeneration.cs
new file mode 100644
index 00000000..609c01cb
--- /dev/null
+++ b/MathGame.vitorvelozo/controllers/QuestionGeneration.cs
@@ -0,0 +1,78 @@
+using CodeReviews.Console.MathGame.Models;
+
+namespace CodeReviews.Console.MathGame.Controllers;
+
+public class QuestionGenerator
+{
+ public int FirstNumber { get; init; }
+ public int SecondNumber { get; set; }
+ public GameDifficulty GameDifficulty {get; set;}
+ public MathOperation Operation { get; init; }
+ private int GeneratedNumberCeiling
+ {
+ get
+ {
+ if (GameDifficulty == GameDifficulty.Easy)
+ {
+ return 11;
+ }
+ else if (GameDifficulty == GameDifficulty.Normal)
+ {
+ return 51;
+ }
+ return 101;
+ }
+ }
+
+ private static readonly Array OperationsList = Enum.GetValues(typeof(MathOperation));
+
+ public QuestionGenerator(GameDifficulty difficulty)
+ {
+ int randomIndex = Random.Shared.Next(OperationsList.Length);
+ Operation = (MathOperation)OperationsList.GetValue(randomIndex)!;
+
+ GameDifficulty = difficulty;
+ FirstNumber = Random.Shared.Next(1, GeneratedNumberCeiling);
+ SecondNumber = GenerateSecondNumber();
+ }
+
+ public QuestionGenerator(GameDifficulty difficulty, MathOperation operation)
+ {
+ Operation = operation;
+
+ GameDifficulty = difficulty;
+ FirstNumber = Random.Shared.Next(1, GeneratedNumberCeiling);
+ SecondNumber = GenerateSecondNumber();
+ }
+
+ private int[] GetIntDivisors()
+ {
+ int[] divisors = Enumerable.Range(1, FirstNumber)
+ .Where(d => FirstNumber % d == 0)
+ .ToArray();
+ return divisors;
+ }
+
+ private int GenerateSecondNumber()
+ {
+ switch (Operation)
+ {
+ case MathOperation.Subtraction:
+ SecondNumber = Random.Shared.Next(1, FirstNumber);
+ break;
+ case MathOperation.Division:
+ int[] divisors = GetIntDivisors();
+ SecondNumber = divisors[Random.Shared.Next(divisors.Length)];
+ break;
+ default:
+ SecondNumber = Random.Shared.Next(1, GeneratedNumberCeiling);
+ break;
+ }
+ return SecondNumber;
+ }
+
+ public Question GenerateQuestion()
+ {
+ return new Question(FirstNumber, SecondNumber, Operation);
+ }
+}
diff --git a/MathGame.vitorvelozo/models/MathGame.cs b/MathGame.vitorvelozo/models/MathGame.cs
new file mode 100644
index 00000000..c02ddfc4
--- /dev/null
+++ b/MathGame.vitorvelozo/models/MathGame.cs
@@ -0,0 +1,24 @@
+namespace CodeReviews.Console.MathGame.Models;
+
+public enum GameDifficulty : int
+{
+ Easy = 0,
+ Normal = 1,
+ Hard = 2,
+}
+public class Game(GameDifficulty difficulty = GameDifficulty.Normal, int length = 5, bool randomMode = true)
+{
+ public List Questions { get; set; } = [];
+ public int PlayerScore { get; set; } = 0;
+ public int GameLength { get; } = length;
+ public GameDifficulty Difficulty { get; } = difficulty;
+ public bool IsRandomMode { get; } = randomMode;
+ public TimeSpan Duration
+ {
+ get
+ {
+ long totalTicks = Questions.Sum(question => question.Duration.Ticks);
+ return TimeSpan.FromTicks(totalTicks);
+ }
+ }
+}
diff --git a/MathGame.vitorvelozo/models/MathQuestion.cs b/MathGame.vitorvelozo/models/MathQuestion.cs
new file mode 100644
index 00000000..6ce5ad47
--- /dev/null
+++ b/MathGame.vitorvelozo/models/MathQuestion.cs
@@ -0,0 +1,36 @@
+namespace CodeReviews.Console.MathGame.Models;
+
+public enum MathOperation : ushort
+{
+ Multiplication = '*',
+ Division = '/',
+ Addition = '+',
+ Subtraction = '-',
+}
+
+public class Question
+{
+ public int FirstNumber { get; }
+ public int SecondNumber { get; }
+ public MathOperation Operation { get; }
+ public int Result { get; set; }
+ public string? ProvidedAnswer { get; set; }
+ public bool IsAnswerCorrect { get; set; } = false;
+ public TimeOnly StartTime {get; set; }
+ public TimeOnly FinishTime {get; set; }
+ public TimeSpan Duration
+ {
+ get
+ {
+ return FinishTime - StartTime;
+ }
+ }
+
+
+ public Question(int firstNumber, int secondNumber, MathOperation operation)
+ {
+ FirstNumber = firstNumber;
+ SecondNumber = secondNumber;
+ Operation = operation;
+ }
+}
diff --git a/MathGame.vitorvelozo/models/MathSet.cs b/MathGame.vitorvelozo/models/MathSet.cs
new file mode 100644
index 00000000..b6f6cbfd
--- /dev/null
+++ b/MathGame.vitorvelozo/models/MathSet.cs
@@ -0,0 +1,36 @@
+namespace CodeReviews.Console.MathGame.Models;
+
+public class MathSet
+{
+ public List Games { get; set; } = [];
+
+ public int totalPoints
+ {
+ get
+ {
+ return Games.Sum(game => game.PlayerScore);
+ }
+ }
+
+ public int totalQuestions
+ {
+ get
+ {
+ return Games.Sum(game => game.GameLength);
+ }
+ }
+
+ public TimeSpan Duration
+ {
+ get
+ {
+ long totalTicks = Games.Sum(game => game.Duration.Ticks);
+ return TimeSpan.FromTicks(totalTicks);
+ }
+ }
+
+ public void AddGame(Game game)
+ {
+ Games.Add(game);
+ }
+}
diff --git a/MathGame.vitorvelozo/views/GameScreen.cs b/MathGame.vitorvelozo/views/GameScreen.cs
new file mode 100644
index 00000000..0a619894
--- /dev/null
+++ b/MathGame.vitorvelozo/views/GameScreen.cs
@@ -0,0 +1,43 @@
+using CodeReviews.Console.MathGame.Models;
+using Spectre.Console;
+
+namespace CodeReviews.Console.MathGame.Views;
+
+public static class GameMenu
+{
+ private static MenuChoices GetOperation()
+ {
+ return AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Select an operation")
+ .AddChoices(Enum.GetValues())
+ );
+ }
+
+ public static bool Display(MathSet mathSet)
+ {
+ bool keepPlaying = false;
+ MenuChoices operation;
+ do
+ {
+ operation = GetOperation();
+ switch (operation)
+ {
+ case MenuChoices.NewGame:
+ keepPlaying = true;
+ break;
+ case MenuChoices.ShowHistory:
+ ResultScreen.Display(mathSet);
+ break;
+ }
+ } while (operation == MenuChoices.ShowHistory);
+ return keepPlaying;
+ }
+
+ private enum MenuChoices
+ {
+ NewGame,
+ ShowHistory,
+ ExitProgram,
+ }
+}
\ No newline at end of file
diff --git a/MathGame.vitorvelozo/views/QuestionScreen.cs b/MathGame.vitorvelozo/views/QuestionScreen.cs
new file mode 100644
index 00000000..9d071d26
--- /dev/null
+++ b/MathGame.vitorvelozo/views/QuestionScreen.cs
@@ -0,0 +1,33 @@
+
+using CodeReviews.Console.MathGame.Models;
+using Spectre.Console;
+
+namespace CodeReviews.Console.MathGame.Views;
+
+public static class QuestionMenu
+{
+ public static MathOperation GetOperation()
+ {
+ return AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Select an operation")
+ .AddChoices(Enum.GetValues())
+ );
+ }
+
+ public static string? GetQuestionAnswer(Question question)
+ {
+ AnsiConsole.Markup($"{question.FirstNumber} {GetOperationSymbol(question.Operation)} {question.SecondNumber} = ");
+ return System.Console.ReadLine();
+ }
+
+ private static char GetOperationSymbol(MathOperation operation) =>
+ operation switch
+ {
+ MathOperation.Addition => '+',
+ MathOperation.Subtraction => '-',
+ MathOperation.Multiplication => '*',
+ MathOperation.Division => '/',
+ _ => '?'
+ };
+}
diff --git a/MathGame.vitorvelozo/views/ResultScreen.cs b/MathGame.vitorvelozo/views/ResultScreen.cs
new file mode 100644
index 00000000..d9b0997d
--- /dev/null
+++ b/MathGame.vitorvelozo/views/ResultScreen.cs
@@ -0,0 +1,38 @@
+using CodeReviews.Console.MathGame.Models;
+using Spectre.Console;
+
+namespace CodeReviews.Console.MathGame.Views;
+
+public static class ResultScreen
+{
+ public static void Display(MathSet mathSet)
+ {
+ System.Console.Clear();
+ for (int i = 0; i < mathSet.Games.Count; i++)
+ {
+ Game game = mathSet.Games[i];
+ Table table = new Table()
+ .Border(TableBorder.Rounded)
+ .Title($"Game {i + 1} ({Markup.Escape(game.Difficulty.ToString())}) | Score: {game.PlayerScore}/{game.GameLength}")
+ .AddColumn("Question")
+ .AddColumn("Answer")
+ .AddColumn("Result");
+
+ foreach (Question question in game.Questions)
+ {
+ string result = question.IsAnswerCorrect ? "[green]✔ Correct[/]" : "[red]✘ Incorrect[/]";
+ table.AddRow(
+ Markup.Escape(question.Result.ToString()),
+ Markup.Escape(question.ProvidedAnswer.ToString()),
+ result);
+ }
+
+ AnsiConsole.Write(table);
+ }
+
+ string durationFormatted = mathSet.Duration.ToString(@"mm'm 'ss's'");
+ AnsiConsole.Write(new Panel($"[bold]{mathSet.totalPoints}/{mathSet.totalQuestions}[/] in {durationFormatted}")
+ .Header("SET RESULT", Justify.Center)
+ .Border(BoxBorder.Double));
+ }
+}
diff --git a/MathGame.vitorvelozo/views/StartScreen.cs b/MathGame.vitorvelozo/views/StartScreen.cs
new file mode 100644
index 00000000..f24dc7e8
--- /dev/null
+++ b/MathGame.vitorvelozo/views/StartScreen.cs
@@ -0,0 +1,28 @@
+using CodeReviews.Console.MathGame.Models;
+using Spectre.Console;
+
+namespace CodeReviews.Console.MathGame.Views;
+
+public static class MainMenu
+{
+ public static void DisplayWelcome()
+ {
+ AnsiConsole.MarkupLine("Hello! Welcome to the [cyan]math game[/]!");
+ }
+
+ public static GameDifficulty GetDifficulty()
+ {
+ return AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Select a [red]difficulty[/]")
+ .AddChoices(Enum.GetValues())
+ );
+ }
+
+ public static bool GetRandomMode()
+ {
+ bool randomMode = AnsiConsole.Confirm("Do you prefer to [red]manually select[/] operations?");
+ System.Console.Clear();
+ return !randomMode;
+ }
+}