Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions MathGame.Cybernexus-code/MathGame.CyberNexus-code/Entities/Game.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Spectre.Console;

namespace Entities;

public class Game
{
public int Score {get; private set;}
private readonly IOperationProvider _operation;
private readonly GameSettings _gameSettings;
private readonly IGameTimer _timer;
private readonly GameMode _mode;
private readonly Random _rand;
public Game(IOperationProvider operation, DifficultyLevel difficultyLevel, IGameTimer timer, GameMode gameMode, Random random)
{
_operation = operation;
_mode = gameMode;
_gameSettings = new GameSettings(difficultyLevel);
_timer = timer;
_rand = random;
}
public GameResult Start()
{
int questionCount = 0;
AnsiConsole.MarkupLine($"[green]Game Started![/]");

_timer.Start();

while(questionCount < _gameSettings.QuestionCount)
{
Console.Clear();
AnsiConsole.Markup($"================== \nScore: {Score} \n==================\n");
AskQuestion(_rand);
questionCount++;
}

var duration = _timer.Stop();

Console.Clear();
AnsiConsole.MarkupLine($"You got {Score}/{_gameSettings.QuestionCount} questions correct! \n"
+ "Press any key to return to the Main menu...");
Console.ReadLine();

return new GameResult(Score, _operation.DisplayName , _gameSettings.DifficultyLevel, duration);
}


public void AskQuestion(Random rand)
{

var question = GetQuestion(rand);

int a = question.FirstNumber;
int b = question.SecondNumber;
string symbol = question.Symbol;

var answer = AnsiConsole
.Ask<int>("What is the solution to this math problem?"
+ $"\n{a} {symbol} {b} =");

if(SubmitAnswer(answer, question.Answer))
{
AnsiConsole.MarkupLine($"That is correct! {a} {symbol} {b} = [green]{question.Answer}[/] \n Press any key to continue...");
Console.ReadKey();
}
else
{
AnsiConsole.MarkupLine($"That is incorrect! {a} {symbol} {b} = {question.Answer} \n Press any key to continue...");
Console.ReadKey();
}
}

public MathQuestion GetQuestion(Random rand)
{
return new MathQuestion(_operation.GetOperation(), rand, _gameSettings);
}

public bool SubmitAnswer(int answer, int calculatedAnswer)
{
bool isCorrect = answer == calculatedAnswer;
if(isCorrect)
{
Score++;
}
return isCorrect;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
public class GameResult
{
public readonly int _score;
public readonly string _operation;
public readonly DifficultyLevel _difficultyLevel;
public readonly TimeSpan _duration;
public GameResult(int score, string mode, DifficultyLevel difficultyLevel, TimeSpan duration)
{
_score = score;
_operation = mode;
_difficultyLevel = difficultyLevel;
_duration = duration;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
public class GameSettings
{
public DifficultyLevel DifficultyLevel {get;}
public int MinNumber {get;} = 1;
public int MaxNumber {get;}
public int QuestionCount {get;}

public GameSettings(DifficultyLevel difficultyLevel)
{
DifficultyLevel = difficultyLevel;
(MaxNumber, QuestionCount) = DifficultyLevel switch
{
DifficultyLevel.Easy => (20,3),
DifficultyLevel.Normal => (50, 5),
DifficultyLevel.Hard => (100, 10),
_=> throw new ArgumentOutOfRangeException()
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
public class MathQuestion
{
private readonly Operation _operation;
private readonly Random _rand;
public int Answer {get; private set;}
public int FirstNumber {get; private set;}
public int SecondNumber {get; private set;}
public string Symbol {get; private set;} = string.Empty;
public GameSettings Gamesettings {get; private set;}
public MathQuestion(Operation operation, Random rand, GameSettings gameSettings)
{
_operation = operation;
_rand = rand;
Gamesettings = gameSettings;
GenerateNumbers();
CalculateAnswer(FirstNumber, SecondNumber);
}

private void CalculateAnswer(int a, int b)
{
(Answer, Symbol) = _operation switch{
Operation.Addition => (a + b, "+"),
Operation.Subtraction => (a - b, "-"),
Operation.Multiplication => (a * b, "*"),
Operation.Division => (a / b, "/"),
_=> throw new ArgumentOutOfRangeException()
};
}

private void GenerateNumbers()
{
FirstNumber = _rand.Next(Gamesettings.MinNumber, Gamesettings.MaxNumber + 1);
SecondNumber = _rand.Next(Gamesettings.MinNumber, Gamesettings.MaxNumber + 1);

while(_operation == Operation.Division && FirstNumber % SecondNumber != 0)
{
FirstNumber = _rand.Next(Gamesettings.MinNumber, Gamesettings.MaxNumber + 1);
SecondNumber = _rand.Next(Gamesettings.MinNumber, Gamesettings.MaxNumber + 1);
}

while(_operation == Operation.Subtraction && Gamesettings.DifficultyLevel != DifficultyLevel.Hard && FirstNumber < SecondNumber)
{
FirstNumber = _rand.Next(Gamesettings.MinNumber, Gamesettings.MaxNumber + 1);
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
public enum DifficultyLevel
{
Easy,
Normal,
Hard
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public enum GameMode
{
Single,
Random
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
public enum Operation
{
Addition,
Subtraction,
Multiplication,
Division
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public interface IGameTimer
{
void Start();
TimeSpan Stop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public interface IOperationProvider
{
string DisplayName {get;}
Operation GetOperation();
}
14 changes: 14 additions & 0 deletions MathGame.Cybernexus-code/MathGame.CyberNexus-code/MathGame.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.57.2" />
</ItemGroup>

</Project>
62 changes: 62 additions & 0 deletions MathGame.Cybernexus-code/MathGame.CyberNexus-code/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Net.Mail;
using Entities;
using Spectre.Console;

List<GameResult> gameResults = new();

while (true)
{

Console.Clear();

var choice = AnsiConsole.Prompt( new SelectionPrompt<string>().Title("==================\nMath Game").AddChoices("Start Game","View Scores", "Exit"));


if(choice == "Exit")
{
return;
}else if(choice == "View Scores")
{
var table = new Table().AddColumn("Difficulty").AddColumn("Operation").AddColumn("Score").AddColumn("Duration");

gameResults.ForEach(x => table.AddRow($"{x._difficultyLevel}",$"{x._operation}",$"{x._score}", $"{x._duration.ToString(@"mm\:ss")}"));

AnsiConsole.Write(table);
AnsiConsole.MarkupLine("Press any key to continue...");
Console.ReadKey();
}
else
{
var rand = new Random();
var timer = new GameTimer();

var mode = AnsiConsole
.Prompt(new SelectionPrompt<GameMode>()
.Title("==================\nMath Game\n==================\nPlease Select a game mode:")
.AddChoices(Enum.GetValues<GameMode>()));

var difficulty = AnsiConsole
.Prompt(new SelectionPrompt<DifficultyLevel>()
.Title("==================\nMath Game\n==================\nPlease Select a difficulty:")
.AddChoices(Enum.GetValues<DifficultyLevel>()));

if(mode == GameMode.Single)
{
var option = AnsiConsole.Prompt(
new SelectionPrompt<Operation>().Title("==================\nMath Game\n==================\nPlease Select an opperation:").AddChoices(Enum.GetValues<Operation>()));

var fixedOperation = new FixedOperationProvider(option);

var newGame = new Game(fixedOperation, difficulty, timer, mode, rand);
gameResults.Add(newGame.Start());
}
else
{
var randomOperationProvider = new RandomOperationProvider(rand, Enum.GetValues<Operation>().ToList());
var newGame = new Game(randomOperationProvider, difficulty, timer, mode, rand);
gameResults.Add(newGame.Start());
}
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
public class FixedOperationProvider(Operation operation) : IOperationProvider
{
public string DisplayName {get;} = operation.ToString();
private readonly Operation _operation = operation;

public Operation GetOperation()
{
return _operation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Diagnostics;

public class GameTimer: IGameTimer
{
private long _startingTimestamp;

public void Start()
{
_startingTimestamp = Stopwatch.GetTimestamp();
}

public TimeSpan Stop()
{
return Stopwatch.GetElapsedTime(_startingTimestamp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Buffers;

public class RandomOperationProvider : IOperationProvider
{
public string DisplayName {get;} = "Random";
private readonly Random _rand;
private readonly List<Operation> _operations;
public RandomOperationProvider(Random rand, List<Operation> operations)
{
_rand = rand;
_operations = operations;

}
public Operation GetOperation()
{
int index = _rand.Next(_operations.Count);
return _operations[index];
}
}
4 changes: 4 additions & 0 deletions MathGame.Cybernexus-code/MathGame.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Solution>
<Project Path="MathGame/MathGame.csproj" />
<Project Path="MathGame.Tests/MathGame.Tests.csproj" />
</Solution>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

namespace MathGame.Tests.Entities;

public class MathQuestionTest
{
private readonly Random _random = new();
private readonly GameSettings _gameSettings = new GameSettings(DifficultyLevel.Easy);

[Fact]
public void Addition_ShouldCalculateCorrectAnswer()
{
// Arrange
// Set up what the test needs
// Act
// Perform the behaviour we're testing
var question = new MathQuestion(Operation.Addition, _random, _gameSettings);

// Assert
// Verify the result
Assert.Equal(question.FirstNumber + question.SecondNumber, question.Answer);
}

[Fact]
public void Division_ShouldAlwaysProduceInteger()
{
var question = new MathQuestion(Operation.Division, _random, _gameSettings );

Assert.Equal(0, question.FirstNumber % question.SecondNumber);
}

[Theory]
[InlineData(Operation.Addition, "+")]
[InlineData(Operation.Subtraction, "-")]
[InlineData(Operation.Multiplication, "*")]
[InlineData(Operation.Division, "/")]

public void Operation_ShouldMatchSymbol(Operation operation, string symbol)
{
var question = new MathQuestion(operation, _random, _gameSettings);

Assert.Equal(symbol, question.Symbol);
}
}
Loading
Loading