diff --git a/mantpaa.MathGame/MathGame.csproj b/mantpaa.MathGame/MathGame.csproj
new file mode 100644
index 00000000..ed9781c2
--- /dev/null
+++ b/mantpaa.MathGame/MathGame.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
diff --git a/mantpaa.MathGame/MathGame.sln b/mantpaa.MathGame/MathGame.sln
new file mode 100644
index 00000000..c408e597
--- /dev/null
+++ b/mantpaa.MathGame/MathGame.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MathGame", "MathGame.csproj", "{8E44D313-4A8D-F5FA-1FB5-C00DA569A7BD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8E44D313-4A8D-F5FA-1FB5-C00DA569A7BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8E44D313-4A8D-F5FA-1FB5-C00DA569A7BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8E44D313-4A8D-F5FA-1FB5-C00DA569A7BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8E44D313-4A8D-F5FA-1FB5-C00DA569A7BD}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {BA2070F0-AF12-4B1E-BF4A-511581206CBF}
+ EndGlobalSection
+EndGlobal
diff --git a/mantpaa.MathGame/Models/GameData.cs b/mantpaa.MathGame/Models/GameData.cs
new file mode 100644
index 00000000..b4d4fc55
--- /dev/null
+++ b/mantpaa.MathGame/Models/GameData.cs
@@ -0,0 +1,46 @@
+namespace MathGame.Models;
+
+internal class GameData
+{
+ private int score;
+ private double avgTimePerQuestion;
+ private int difficultyLevel;
+ private Question[] questions;
+
+ public GameData(int score, int difficultyLevel, Question[] questions)
+ {
+ this.score = score;
+
+ this.difficultyLevel = difficultyLevel;
+ this.questions = questions;
+ this.avgTimePerQuestion = CalculateAvgTimePerQuestion();
+ }
+
+ public override string ToString()
+ {
+ string returnString = "";
+ foreach (var question in questions)
+ {
+ returnString += $"Equation: {question.Equation} = ?, Answer: {question.Answer}, Expected answer: {question.ExpectedAnswer}, Time spent: {((question.TimeSpentSeconds) >= 0 ? (question.TimeSpentSeconds) : "N/A")} seconds.\n";
+ }
+ returnString += "".PadLeft(Console.BufferWidth, '-') + "\n";
+ returnString += $"Score: {score}, Difficulty level: {difficultyLevel}, Average time per question: {avgTimePerQuestion} seconds.";
+ return returnString;
+ }
+
+ private double CalculateAvgTimePerQuestion()
+ {
+ int totalTime = 0;
+ int questionsAnswered = 0;
+ foreach (var question in questions)
+ {
+ if (question.TimeSpentSeconds >= 0)
+ {
+ totalTime += question.TimeSpentSeconds;
+ questionsAnswered++;
+ }
+ }
+
+ return questionsAnswered > 0 ? (double)totalTime / questionsAnswered : 0;
+ }
+}
\ No newline at end of file
diff --git a/mantpaa.MathGame/Models/GameEngine.cs b/mantpaa.MathGame/Models/GameEngine.cs
new file mode 100644
index 00000000..4bceab67
--- /dev/null
+++ b/mantpaa.MathGame/Models/GameEngine.cs
@@ -0,0 +1,204 @@
+using System.Diagnostics;
+
+namespace MathGame.Models;
+
+internal class GameEngine
+{
+ string[] operators = new string[] { "+", "-", "*", "/" };
+ List gameHistory = new List();
+ int difficulty = 1;
+ GameType gameType = GameType.Addition;
+
+ public void PlayGame()
+ {
+ GameData gameData;
+
+ int score = 0;
+
+
+ Console.WriteLine("Starting the game! Answer the following questions:");
+ Console.WriteLine("To give up, type 'exit'.");
+
+ Question[] questions = InitializeGame(difficulty);
+ for (int i = 0; i < questions.Length; i++)
+ {
+ Stopwatch stopwatch = new Stopwatch();
+ stopwatch.Start();
+
+ Console.WriteLine($"Question {i + 1}: {questions[i].Equation}");
+ string? userAnswer = Console.ReadLine();
+ stopwatch.Stop();
+
+ if (userAnswer != null && userAnswer.ToLower() == "exit")
+ {
+ Console.WriteLine("Exiting the game. Goodbye!");
+ break;
+ }
+
+ if (userAnswer != null)
+ {
+ questions[i].Answer = userAnswer;
+ questions[i].TimeSpentSeconds = stopwatch.Elapsed.Seconds;
+ if (userAnswer == questions[i].ExpectedAnswer)
+ {
+ Console.WriteLine("Correct!");
+ score++;
+ }
+ else
+ {
+ Console.WriteLine($"Wrong! The correct answer is {questions[i].ExpectedAnswer}");
+ }
+ }
+ }
+ gameData = new GameData(score, difficulty, questions);
+
+ gameHistory.Add(gameData);
+ }
+
+ public void ViewGameHistory()
+ {
+ Console.WriteLine("Score history:");
+ for (int i = 0; i < gameHistory.Count; i++)
+ {
+ Console.WriteLine($"Game {i + 1}:\n{gameHistory[i].ToString()}\n");
+ }
+ Console.WriteLine("Press any key to continue...");
+ Console.ReadKey();
+ Console.Clear();
+ }
+
+ public void ChangeDifficulty()
+ {
+ string? input;
+ Console.WriteLine("Current difficulty level: " + difficulty);
+ Console.WriteLine("Enter new difficulty level (1-3):");
+ input = Console.ReadLine();
+
+ while (input == null || !new string[] { "1", "2", "3" }.Contains(input))
+ {
+
+ Console.WriteLine("Invalid input, try again.");
+ input = Console.ReadLine();
+ }
+
+ difficulty = int.Parse(input);
+ }
+ public void ChangeQuestionType()
+ {
+ string? input;
+ Console.WriteLine("Enter question type:\na - addition\ns - subtraction\nm - multiplication\nd - division\nr - random!");
+ input = Console.ReadLine();
+
+ while (input == null || !new string[] { "a", "s", "m", "d", "r" }.Contains(input.ToLower()))
+ {
+ Console.WriteLine("Invalid input, try again.");
+ input = Console.ReadLine();
+ }
+
+ switch (input.ToLower())
+ {
+ case "a":
+ gameType = GameType.Addition;
+ break;
+ case "s":
+ gameType = GameType.Subtraction;
+ break;
+ case "m":
+ gameType = GameType.Multiplication;
+ break;
+ case "d":
+ gameType = GameType.Division;
+ break;
+ case "r":
+ gameType = GameType.Random;
+ break;
+ }
+ }
+ private Question[] InitializeGame(int difficultyLevel)
+ {
+ Random random = new Random();
+ string[] operatorValue = new string[] { "+", "-", "*", "/" }; // 0:+, 1: -, 2: *, 3: / : GameType enum values correspond to these indices.
+ int questionsToAsk = 5;
+ Question[] questions = new Question[questionsToAsk];
+ for (int i = 0; i < questionsToAsk; i++)
+ {
+ string op = "+";
+
+ if (gameType == GameType.Random)
+ {
+ op = GetOperator(random);
+ }
+ else
+ {
+ op = operatorValue[(int) gameType];
+ }
+
+ questions[i] = CreateQuestion(op, difficultyLevel, random);
+ }
+
+ return questions;
+ }
+
+ private Question CreateQuestion(string op, int difficultyLevel, Random random)
+ {
+ if (op == "/")
+ {
+ int dividend = 1;
+ int divisor = 1;
+ bool valid = false;
+ while (valid == false)
+ {
+ dividend = random.Next(0, 101);
+ int minValue = (difficultyLevel > 1) ? 2 : 1; // disallow division by 1 for higher difficulties.
+ divisor = random.Next(minValue, (dividend > minValue) ? dividend : minValue +1); // Ensure maxval is larger than minval
+ if (dividend % divisor == 0)
+ {
+ valid = true;
+ }
+ }
+
+ string equation = $"{dividend} / {divisor}";
+ string expectedAnswer = (dividend / divisor).ToString();
+ return new Question(equation, "", expectedAnswer);
+ }
+
+ else if (new string[] {"+", "*", "-" }.Contains(op))
+ {
+ int num1 = random.Next(1, 10 * difficultyLevel);
+ int num2 = random.Next(1, 10 * difficultyLevel);
+ string equation = $"{num1} {op} {num2}";
+ string expectedAnswer = "";
+ if (op == "+")
+ expectedAnswer = (num1 + num2).ToString();
+ else if (op == "-")
+ expectedAnswer = (num1 - num2).ToString();
+ else if (op == "*")
+ expectedAnswer = (num1 * num2).ToString();
+ else
+ expectedAnswer = "issue occured";
+
+ return new Question(equation, "", expectedAnswer);
+ }
+
+ else
+ {
+ throw new InvalidDataException("Invalid operator: " + op);
+ }
+ }
+
+ // Pick a random operator for the question, to help randomize the questions a bit more.
+ private string GetOperator(Random random)
+ {
+ int val = random.Next(0, operators.Length);
+ return operators[val];
+ }
+
+ enum GameType
+ {
+ Addition,
+ Subtraction,
+ Multiplication,
+ Division,
+ Random
+ }
+}
\ No newline at end of file
diff --git a/mantpaa.MathGame/Models/Question.cs b/mantpaa.MathGame/Models/Question.cs
new file mode 100644
index 00000000..10cab316
--- /dev/null
+++ b/mantpaa.MathGame/Models/Question.cs
@@ -0,0 +1,18 @@
+namespace MathGame.Models;
+
+internal class Question
+{
+ public string Equation { get; set; }
+ public string Answer { get; set; }
+
+ public string ExpectedAnswer { get; set; }
+
+ public int TimeSpentSeconds { get; set; } = -1; // Todo: better value?
+ public Question(string equation, string answer, string expectedAnswer)
+ {
+ Equation = equation;
+ Answer = answer;
+ ExpectedAnswer = expectedAnswer;
+ }
+
+}
\ No newline at end of file
diff --git a/mantpaa.MathGame/Program.cs b/mantpaa.MathGame/Program.cs
new file mode 100644
index 00000000..9072f782
--- /dev/null
+++ b/mantpaa.MathGame/Program.cs
@@ -0,0 +1,53 @@
+using MathGame.Models;
+
+namespace MathGame;
+
+public static class MathGame
+{
+ public static void Main()
+ {
+ GameEngine gameEngine = new GameEngine();
+
+ string input = "";
+ do
+ {
+ Console.WriteLine("Math game!\n" +
+ "Press the number to choose a menu option.\n"+
+ "1. Play game\n"+
+ "2. See history.\n"+
+ "3. Change difficulty(1-3).\n"+
+ "4. Change question type\n"
+ +"Exit to exit.");
+ string? userInput = Console.ReadLine();
+
+ if (userInput != null)
+ {
+ input = userInput.ToLower();
+ switch (input)
+ {
+ case "1":
+ gameEngine.PlayGame();
+ break;
+ case "2":
+ gameEngine.ViewGameHistory();
+ break;
+ case "3":
+ gameEngine.ChangeDifficulty();
+ break;
+ case "4":
+ gameEngine.ChangeQuestionType();
+ break;
+ case "exit":
+ Console.WriteLine("Exiting the game. Goodbye!");
+ break;
+ default:
+ Console.WriteLine("Invalid input, try again.");
+ Console.WriteLine("Press any key to continue...");
+ Console.ReadKey();
+ Console.Clear();
+ break;
+ }
+ }
+ } while (input != "exit");
+ }
+}