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"); + } +}