diff --git a/GameData/DummyExpenseRepository.cs b/GameData/DummyExpenseRepository.cs new file mode 100644 index 0000000..61e8329 --- /dev/null +++ b/GameData/DummyExpenseRepository.cs @@ -0,0 +1,13 @@ +using GameModel; +using GameModel.Contract; + +namespace GameData +{ + public class DummyExpenseRepository : IExpenseRepository + { + public IEnumerable GetAll() + { + return IExpenseRepository.TestData; + } + } +} \ No newline at end of file diff --git a/GameData/GameData.csproj b/GameData/GameData.csproj new file mode 100644 index 0000000..044def4 --- /dev/null +++ b/GameData/GameData.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/GameHandler.UnitTests/Mocks/FakeExpenseRepository.cs b/GameHandler.UnitTests/Mocks/FakeExpenseRepository.cs index e4928bd..bf5be23 100644 --- a/GameHandler.UnitTests/Mocks/FakeExpenseRepository.cs +++ b/GameHandler.UnitTests/Mocks/FakeExpenseRepository.cs @@ -9,22 +9,11 @@ namespace GameModel.Mocks { public class FakeExpenseRepository : IExpenseRepository { - Expense[] Data = new[] { - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Sink }, "Gosse", 0.5m, false), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Sink }, "Gosse2", 1.5m, false), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.FullSink }, "Gosse bei Anwurf", 1m, false), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Circle }, "Kranz", 1m, true), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.NinePins }, "alle Neune", 1m, true), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Eliminated }, "Ausgeschieden", 0.5m, false), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.NoWood }, "kein Holz", 0.5m, false), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Bell }, "Klingel", 0.5m, false), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.FirstThrowFail }, "Anwurffehler", 0.5m, false), - Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.ExpensePoint }, "Strafpunkt, z.B. im \"Scheißspiel\"", 0.5m, false), - }; + public IEnumerable GetAll() { - return Data; + return IExpenseRepository.TestData; } } } diff --git a/GameHandler/ExpenseHandler.cs b/GameHandler/ExpenseHandler.cs index 806e7cd..383e6cc 100644 --- a/GameHandler/ExpenseHandler.cs +++ b/GameHandler/ExpenseHandler.cs @@ -23,16 +23,20 @@ namespace GameHandler _expenseRepository = expenseRepository; } - private ExpenseModel _expenseModel = new ExpenseModel(Array.Empty()); + //private ExpenseModel _expenseModel = new ExpenseModel(Array.Empty()); - public ExpenseModel CheckThrow(BoardState currentState, PinThrow pinThrow, int[] PlayerIds) + public ExpenseModel CheckThrow(BoardState currentState, PinThrow pinThrow, int[] PlayerIds, ExpenseModel expenseModelToAppend = null) { if (!PlayerIds.Any(_ => _ == pinThrow.PlayerId)) { throw new InvalidPinThrowException($"Player {pinThrow.PlayerId} not found"); } - var memberExpenses = new List(_expenseModel.MemberExpenses); + if (expenseModelToAppend == null) + { + expenseModelToAppend = new ExpenseModel(Array.Empty()); + } + var memberExpenses = new List(expenseModelToAppend.MemberExpenses); var triggers = pinThrow.GetExpenseTriggers(currentState); var destExpenses = _expenseRepository.GetAll().Where(_ => _.ExpenseTriggers.Any(et => triggers.Any(et2 => et2 == et))); @@ -53,7 +57,7 @@ namespace GameHandler } } - return _expenseModel with { MemberExpenses = memberExpenses.ToArray() }; + return expenseModelToAppend with { MemberExpenses = memberExpenses.ToArray() }; } } } diff --git a/GameHandler/GameHandler.csproj b/GameHandler/GameHandler.csproj index 3a5ec60..8d810f8 100644 --- a/GameHandler/GameHandler.csproj +++ b/GameHandler/GameHandler.csproj @@ -7,6 +7,7 @@ + diff --git a/GameHandler/GameHandler/DeathGameHandler.cs b/GameHandler/GameHandler/DeathGameHandler.cs index 678e8b3..c39e4f8 100644 --- a/GameHandler/GameHandler/DeathGameHandler.cs +++ b/GameHandler/GameHandler/DeathGameHandler.cs @@ -70,7 +70,7 @@ namespace GameHandler.DeathGame } coffins.Add(new Coffin(playerId,0,0)); } - return new DeathGameModel(1, coffins.OrderBy(_ => random.Next()).ToList().ToArray(), deathGameSettings); + return new DeathGameModel(1, coffins.OrderBy(_ => random.Next()).ToList().ToArray(), deathGameSettings, playerIds); } public IGameModel Update(PinThrow pinThrow, IGameModel gameModel, BoardState boardStateBeforeUpdate) diff --git a/GameHandler/GameService.cs b/GameHandler/GameService.cs index 3183ca3..2300532 100644 --- a/GameHandler/GameService.cs +++ b/GameHandler/GameService.cs @@ -13,21 +13,28 @@ using GameModel.Contract; using GameModel.DeathGame; using GameModel.Contracts; using System.Data; +using Autofac.Core; +using Autofac; +using static System.Formats.Asn1.AsnWriter; namespace GameHandler { public class GameService { + private IContainer? _container { get; set; } private bool _isStarted = false; + private ILifetimeScope? _scope; private IGameHandler _gh; private ThrowHandler _th; private ExpenseHandler _eh; private GameState _lastState; - public GameState GameModel { get { return _lastState; } } + public GameState GameModel { get => _lastState; } - public GameService() + private IExpenseRepository? _expenseRepository { get => _scope?.Resolve(); } + + public GameService(IContainer? container =null) { - + _container = container; } public string ThrowModeName @@ -57,14 +64,16 @@ namespace GameHandler } _isStarted = true; + _scope = _container?.BeginLifetimeScope(); _gh = this.GetGameHandler(gameName); var gm = _gh.InitGameModel(playerIds, gameSettings); _th = new ThrowHandler(); - _eh = new ExpenseHandler(); + _eh = new ExpenseHandler(_expenseRepository); var throwState = ThrowState.Create(_gh.ThrowMode(), _gh.ThrowsPerRount()); - _lastState = GameState.Create(throwState, _gh.GetCurrentPlayerId(gm), gm); + _lastState = GameState.Create(throwState, _gh.GetCurrentPlayerId(gm), gm, ExpenseModel.Create()); + return _lastState; } @@ -82,10 +91,9 @@ namespace GameHandler var throwState = _th.Update(_lastState.ThrowState, pinThrow); var gameModel = _gh.Update(pinThrow, _lastState.GameModel, boardStateBeforeUpdate); - // todo: update expense model + var expenseModel = _eh.CheckThrow(throwState.BoardState, pinThrow, gameModel.PlayerIds, _lastState.ExpenseModel); - - _lastState = _lastState with { ThrowState = throwState, GameModel = gameModel, NextPlayerId = _gh.GetCurrentPlayerId(gameModel) }; + _lastState = _lastState with { ThrowState = throwState, GameModel = gameModel, NextPlayerId = _gh.GetCurrentPlayerId(gameModel), ExpenseModel = expenseModel }; return _lastState ; } @@ -111,6 +119,8 @@ namespace GameHandler throw new InvalidGameStateExcpetion("Game not started"); } _isStarted = false; + + _scope?.Dispose(); } public ThrowCommandData ParseThrowData(string stringData) diff --git a/GameModel/Contracts/IExpenseRepository.cs b/GameModel/Contracts/IExpenseRepository.cs index 96b4576..89831a9 100644 --- a/GameModel/Contracts/IExpenseRepository.cs +++ b/GameModel/Contracts/IExpenseRepository.cs @@ -4,6 +4,19 @@ namespace GameModel.Contract { public interface IExpenseRepository { + static Expense[] TestData = new[] { + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Sink }, "Gosse", 0.5m, false), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Sink }, "Gosse2", 1.5m, false), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.FullSink }, "Gosse bei Anwurf", 1m, false), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Circle }, "Kranz", 1m, true), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.NinePins }, "alle Neune", 1m, true), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Eliminated }, "Ausgeschieden", 0.5m, false), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.NoWood }, "kein Holz", 0.5m, false), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Bell }, "Klingel", 0.5m, false), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.FirstThrowFail }, "Anwurffehler", 0.5m, false), + Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.ExpensePoint }, "Strafpunkt, z.B. im \"Scheißspiel\"", 0.5m, false), + }; + IEnumerable GetAll(); } } \ No newline at end of file diff --git a/GameModel/Contracts/IGameModel.cs b/GameModel/Contracts/IGameModel.cs index be8804d..3631dd3 100644 --- a/GameModel/Contracts/IGameModel.cs +++ b/GameModel/Contracts/IGameModel.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; namespace GameModel.Contracts { public interface IGameModel - { + { + int[] PlayerIds { get; } } } diff --git a/GameModel/DeathGame/DeathGameModel.cs b/GameModel/DeathGame/DeathGameModel.cs index 9d2332a..34e56b1 100644 --- a/GameModel/DeathGame/DeathGameModel.cs +++ b/GameModel/DeathGame/DeathGameModel.cs @@ -7,5 +7,5 @@ using System.Threading.Tasks; namespace GameModel.DeathGame { - public record DeathGameModel(int Id, Coffin[] Coffins, DeathGameSettings deathGameSettings) : IGameModel; + public record DeathGameModel(int Id, Coffin[] Coffins, DeathGameSettings deathGameSettings, int[] PlayerIds) : IGameModel; } diff --git a/GameModel/ExpenseModel.cs b/GameModel/ExpenseModel.cs index 189779f..376e8d1 100644 --- a/GameModel/ExpenseModel.cs +++ b/GameModel/ExpenseModel.cs @@ -8,5 +8,9 @@ namespace GameModel { public record ExpenseModel(MemberExpense[] MemberExpenses) { + public static ExpenseModel Create() + { + return new ExpenseModel(Array.Empty()); + } } } diff --git a/GameModel/GameState.cs b/GameModel/GameState.cs index e50ec32..0048ae5 100644 --- a/GameModel/GameState.cs +++ b/GameModel/GameState.cs @@ -7,11 +7,11 @@ using System.Threading.Tasks; namespace GameModel { - public record GameState(ThrowState ThrowState, int NextPlayerId, IGameModel GameModel) + public record GameState(ThrowState ThrowState, int NextPlayerId, IGameModel GameModel, ExpenseModel ExpenseModel) { - public static GameState Create(ThrowState throwState, int nextPlayerId, IGameModel gm) + public static GameState Create(ThrowState throwState, int nextPlayerId, IGameModel gameModel, ExpenseModel expenseModel) { - return new GameState(throwState, nextPlayerId, gm); + return new GameState(throwState, nextPlayerId, gameModel, expenseModel); } } } diff --git a/GameModel/PinPicture.cs b/GameModel/PinPicture.cs index 2008f3d..0cf730a 100644 --- a/GameModel/PinPicture.cs +++ b/GameModel/PinPicture.cs @@ -198,9 +198,12 @@ namespace GameModel internal static PinPicture Create(string pindata) { - if (!int.TryParse(pindata, out int dummy)) + if (!string.IsNullOrEmpty(pindata)) { - throw new InvalidDataException($"{pindata} cannot be parsed as throw"); + if (!int.TryParse(pindata, out int dummy)) + { + throw new InvalidDataException($"{pindata} cannot be parsed as throw"); + } } var states = new[] { diff --git a/GameModel/PinThrow.cs b/GameModel/PinThrow.cs index 7eedef5..638b1d3 100644 --- a/GameModel/PinThrow.cs +++ b/GameModel/PinThrow.cs @@ -34,9 +34,12 @@ namespace GameModel public static PinThrow Create(string pindata, bool isBell, bool isSink, int playerId) { - if (!int.TryParse(pindata, out int dummy)) + if (!string.IsNullOrEmpty(pindata)) { - throw new InvalidDataException($"{pindata} cannot be parsed as throw"); + if (!int.TryParse(pindata, out int dummy)) + { + throw new InvalidDataException($"{pindata} cannot be parsed as throw"); + } } var pic = PinPicture.Create(pindata); diff --git a/KoogleCli/KoogleCli.csproj b/KoogleCli/KoogleCli.csproj index c235076..caaf8eb 100644 --- a/KoogleCli/KoogleCli.csproj +++ b/KoogleCli/KoogleCli.csproj @@ -14,6 +14,7 @@ + diff --git a/KoogleCli/Program.cs b/KoogleCli/Program.cs index 4fb85e6..d1043d0 100644 --- a/KoogleCli/Program.cs +++ b/KoogleCli/Program.cs @@ -1,5 +1,7 @@ // See https://aka.ms/new-console-template for more information +using Autofac; using CommandLine; +using GameData; using GameHandler; using GameHandler.DeathGame; using GameHandler.Extensions; @@ -48,7 +50,7 @@ void NewGameAction() var option = string.Empty; //do //{ - var games = new GameService().GetGameHandler().Keys.Order().ToList(); + var games = new GameService(null).GetGameHandler().Keys.Order().ToList(); games.Add("Abbreche"); option = AnsiConsole.Prompt( @@ -76,7 +78,7 @@ void NewGameAction() void StartGameAction(string gameName) { - _gs = new GameService(); + _gs = new GameService(GetContainer()); var bs = _gs.Start(new[] { 1,2,3,4}, GetGameSettings(gameName), gameName ); @@ -118,6 +120,13 @@ void StartGameAction(string gameName) ShowMainMenu(); } +IContainer GetContainer() +{ + var builder = new ContainerBuilder(); + builder.RegisterType().As(); + return builder.Build(); +} + IGameSettings GetGameSettings(string gameName) { if (gameName == DeathGameHandler.GAMENAME_DEATHBOX) diff --git a/KoogleV4.sln b/KoogleV4.sln index 4fc18e8..7192522 100644 --- a/KoogleV4.sln +++ b/KoogleV4.sln @@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameModel.UnitTests", "Game EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KoogleCli", "KoogleCli\KoogleCli.csproj", "{3FF45A02-42F9-4E75-993B-6582DD2A22BF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameData", "GameData\GameData.csproj", "{D026F84B-06F5-4BA4-8AB7-D1D385F0611C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,10 @@ Global {3FF45A02-42F9-4E75-993B-6582DD2A22BF}.Debug|Any CPU.Build.0 = Debug|Any CPU {3FF45A02-42F9-4E75-993B-6582DD2A22BF}.Release|Any CPU.ActiveCfg = Release|Any CPU {3FF45A02-42F9-4E75-993B-6582DD2A22BF}.Release|Any CPU.Build.0 = Release|Any CPU + {D026F84B-06F5-4BA4-8AB7-D1D385F0611C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D026F84B-06F5-4BA4-8AB7-D1D385F0611C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D026F84B-06F5-4BA4-8AB7-D1D385F0611C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D026F84B-06F5-4BA4-8AB7-D1D385F0611C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE