diff --git a/Sharpasonne/Engine.cs b/Sharpasonne/Engine.cs index 83b3d29..37a4953 100644 --- a/Sharpasonne/Engine.cs +++ b/Sharpasonne/Engine.cs @@ -10,29 +10,32 @@ namespace Sharpasonne { + using IRuleMap = IImmutableDictionary>>; + using RuleMap = ImmutableDictionary>>; + // TODO: Consider rename. public class Engine : IEngine { - public Board Board { get; } = new Board(); + public Board Board { get; } - /// - /// Players collection for managing player stats and turns. - /// + /// public Players Players { get; } - /// - /// 1-index number of the player who's turn it is to play an action. - /// + /// public int CurrentPlayerTurn { get; } = 1; - public IImmutableDictionary>> Rules { get; } - = ImmutableDictionary>>.Empty; + /// + /// Map of IGameAction to rules that apply to that IGameAction. + /// Keys must be assignable from IGameAction. + /// + /// Type system can't enforce this itself. + public IRuleMap Rules { get; } = RuleMap.Empty; /// Attempts to create a Game engine. /// /// Must provide list for every action to be used by /// Perform. - /// + /// None if any key of is not an . public static Option Create( [NotNull] IImmutableQueue gameActions, [NotNull] IImmutableDictionary>> rules, @@ -49,24 +52,31 @@ public static Option Create( return Option.None(new ArgumentOutOfRangeException(nameof(gameActions), message)); } - return Option.Some(new Engine(gameActions, rules, players)); + return Option.Some(new Engine(gameActions, rules, players, new Board())); } private Engine( [NotNull] IImmutableQueue gameActions, [NotNull] IImmutableDictionary>> rules, - [NotNull] Players players) + [NotNull] Players players, + [NotNull] Board board, + int currentPlayerTurn = 1) { - this.Rules = rules; - this.Players = players; + this.Rules = rules; + this.Players = players; + this.Board = board; + this.CurrentPlayerTurn = currentPlayerTurn; } - private Engine(IEngine engine) + private static Engine NextTurn(IEngine engine) { - this.Board = engine.Board; - this.Rules = engine.Rules; - this.Players = engine.Players; - this.CurrentPlayerTurn = engine.Players.NextPlayer(engine.CurrentPlayerTurn); + var nextTurn = new Engine(ImmutableQueue.Empty, + engine.Rules, + engine.Players, + engine.Board, + engine.Players.NextPlayer(engine.CurrentPlayerTurn)); + + return nextTurn; } public Optional.Option> Perform( @@ -84,7 +94,7 @@ public Optional.Option> Perform( return Option.None>(new string[] {}); } - var newEngine = new Engine(action.Perform(this)); + var newEngine = Engine.NextTurn(action.Perform(this)); return Option.Some>(newEngine); } diff --git a/Sharpasonne/GameActions/EngineState.cs b/Sharpasonne/GameActions/EngineState.cs index 0c011aa..1d3bdd4 100644 --- a/Sharpasonne/GameActions/EngineState.cs +++ b/Sharpasonne/GameActions/EngineState.cs @@ -5,7 +5,13 @@ namespace Sharpasonne.GameActions { - public class EngineState : IEngine + using IRuleMap = IImmutableDictionary>>; + + /// + /// Is the state of an engine without any functionality, because an Engine + /// cannot be constructed from the outside with this state. + /// + internal class EngineState : IEngine { public EngineState(Board board, IEngine engine) { @@ -15,9 +21,9 @@ public EngineState(Board board, IEngine engine) this.CurrentPlayerTurn = engine.CurrentPlayerTurn; } - public Board Board { get; } - public Players Players { get; } - public int CurrentPlayerTurn { get; } - public IImmutableDictionary>> Rules { get; } + public Board Board { get; } + public Players Players { get; } + public int CurrentPlayerTurn { get; } + public IRuleMap Rules { get; } } } \ No newline at end of file diff --git a/Sharpasonne/GameActions/IGameAction.cs b/Sharpasonne/GameActions/IGameAction.cs index 1856c7b..ba15e4d 100644 --- a/Sharpasonne/GameActions/IGameAction.cs +++ b/Sharpasonne/GameActions/IGameAction.cs @@ -1,5 +1,8 @@ namespace Sharpasonne.GameActions { + /// + /// A command to change the state of the game. + /// public interface IGameAction { IEngine Perform(IEngine engine); diff --git a/Sharpasonne/IEngine.cs b/Sharpasonne/IEngine.cs index 8e9cb37..16cf07c 100644 --- a/Sharpasonne/IEngine.cs +++ b/Sharpasonne/IEngine.cs @@ -9,8 +9,17 @@ namespace Sharpasonne public interface IEngine { Board Board { get; } + + /// + /// Players collection for managing player stats and turns. + /// Players Players { get; } + + /// + /// 1-index number of the player who's turn it is to play an action. + /// int CurrentPlayerTurn { get; } + IImmutableDictionary>> Rules { get; } } } diff --git a/Sharpasonne/Rules/AdjacentFeaturesMatchRule.cs b/Sharpasonne/Rules/AdjacentFeaturesMatchRule.cs index 0cacbf6..418e05a 100644 --- a/Sharpasonne/Rules/AdjacentFeaturesMatchRule.cs +++ b/Sharpasonne/Rules/AdjacentFeaturesMatchRule.cs @@ -6,6 +6,10 @@ namespace Sharpasonne.Rules { + /// + /// Ensures that the type of features on all edges of the tile to place + /// match the corresponding features on the surrounding tiles. + /// public class AdjacentFeaturesMatchRule : IRule { public bool Verify(IEngine engine, T1 action) @@ -13,14 +17,16 @@ public bool Verify(IEngine engine, T1 action) { var adjacent = engine.Board.GetAdjecentTiles(action.Point); var allMatch = adjacent - .Where(o => o.Value.HasValue) - .Select(o => ( - o.Key, - o.Value.ValueOrFailure() + // Where orientation has a Placement + .Where(kv => kv.Value.HasValue) + .Select(kv => ( + kv.Key, + // Never failure due to Where. + kv.Value.ValueOrFailure() )) - .All(o => + .All(kv => { - (var direction, var placement) = o; + (var direction, var placement) = kv; switch (direction) { @@ -61,6 +67,10 @@ public bool Verify(IEngine engine, T1 action) return allMatch; } + /// + /// Checks that the order of the types implementing + /// are aligned, thereby showing that the edges are matched. + /// protected bool EdgesMatch( IFeature[] from, IFeature[] to diff --git a/Sharpasonne/Rules/HasAdjacentTileRule.cs b/Sharpasonne/Rules/HasAdjacentTileRule.cs index 7e51fc9..7caf0b0 100644 --- a/Sharpasonne/Rules/HasAdjacentTileRule.cs +++ b/Sharpasonne/Rules/HasAdjacentTileRule.cs @@ -3,6 +3,10 @@ namespace Sharpasonne.Rules { + /// + /// Verify that the will place a tile + /// adjacent to a pre-existing tile. + /// public class HasAdjacentTileRule : IRule { public bool Verify(IEngine engine, T1 gameAction) where T1 : PlaceTileGameAction