Skip to content

Commit

Permalink
Feature/docs (overengineering#21)
Browse files Browse the repository at this point in the history
* Refactor and comment Engine

Next turn logic more explicit.

* Docs and some type aliases
  • Loading branch information
LeeARichardson committed Apr 18, 2018
1 parent 8966075 commit 325de66
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 31 deletions.
50 changes: 30 additions & 20 deletions Sharpasonne/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,32 @@

namespace Sharpasonne
{
using IRuleMap = IImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>>;
using RuleMap = ImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>>;

// TODO: Consider rename.
public class Engine : IEngine
{
public Board Board { get; } = new Board();
public Board Board { get; }

/// <summary>
/// Players collection for managing player stats and turns.
/// </summary>
/// <inheritdoc />
public Players Players { get; }

/// <summary>
/// 1-index number of the player who's turn it is to play an action.
/// </summary>
/// <inheritdoc />
public int CurrentPlayerTurn { get; } = 1;

public IImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>> Rules { get; }
= ImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>>.Empty;
/// <summary>
/// Map of IGameAction to rules that apply to that IGameAction.
/// Keys must be assignable from IGameAction.
/// </summary>
/// <remarks>Type system can't enforce this itself.</remarks>
public IRuleMap Rules { get; } = RuleMap.Empty;

/// <summary>Attempts to create a Game engine.</summary>
/// <param name="gameActions"></param>
/// <param name="rules">Must provide list for every action to be used by
/// Perform.</param>
/// <param name="gameActions"></param>
/// <returns>None if any key of <paramref name="rules"/> is not an <see cref="IGameAction"/>.</returns>
public static Option<Engine, Exception> Create(
[NotNull] IImmutableQueue<IGameAction> gameActions,
[NotNull] IImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>> rules,
Expand All @@ -49,24 +52,31 @@ public static Option<Engine, Exception> Create(
return Option.None<Engine, Exception>(new ArgumentOutOfRangeException(nameof(gameActions), message));
}

return Option.Some<Engine, Exception>(new Engine(gameActions, rules, players));
return Option.Some<Engine, Exception>(new Engine(gameActions, rules, players, new Board()));
}

private Engine(
[NotNull] IImmutableQueue<IGameAction> gameActions,
[NotNull] IImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>> 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<IGameAction>.Empty,
engine.Rules,
engine.Players,
engine.Board,
engine.Players.NextPlayer(engine.CurrentPlayerTurn));

return nextTurn;
}

public Optional.Option<Engine, IEnumerable<string>> Perform(
Expand All @@ -84,7 +94,7 @@ public Optional.Option<Engine, IEnumerable<string>> Perform(
return Option.None<Engine, IEnumerable<string>>(new string[] {});
}

var newEngine = new Engine(action.Perform(this));
var newEngine = Engine.NextTurn(action.Perform(this));

return Option.Some<Engine, IEnumerable<string>>(newEngine);
}
Expand Down
16 changes: 11 additions & 5 deletions Sharpasonne/GameActions/EngineState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@

namespace Sharpasonne.GameActions
{
public class EngineState : IEngine
using IRuleMap = IImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>>;

/// <summary>
/// Is the state of an engine without any functionality, because an Engine
/// cannot be constructed from the outside with this state.
/// </summary>
internal class EngineState : IEngine
{
public EngineState(Board board, IEngine engine)
{
Expand All @@ -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<Type, IImmutableList<IRule<IGameAction>>> Rules { get; }
public Board Board { get; }
public Players Players { get; }
public int CurrentPlayerTurn { get; }
public IRuleMap Rules { get; }
}
}
3 changes: 3 additions & 0 deletions Sharpasonne/GameActions/IGameAction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace Sharpasonne.GameActions
{
/// <summary>
/// A command to change the state of the game.
/// </summary>
public interface IGameAction
{
IEngine Perform(IEngine engine);
Expand Down
9 changes: 9 additions & 0 deletions Sharpasonne/IEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,17 @@ namespace Sharpasonne
public interface IEngine
{
Board Board { get; }

/// <summary>
/// Players collection for managing player stats and turns.
/// </summary>
Players Players { get; }

/// <summary>
/// 1-index number of the player who's turn it is to play an action.
/// </summary>
int CurrentPlayerTurn { get; }

IImmutableDictionary<Type, IImmutableList<IRule<IGameAction>>> Rules { get; }
}
}
22 changes: 16 additions & 6 deletions Sharpasonne/Rules/AdjacentFeaturesMatchRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,27 @@

namespace Sharpasonne.Rules
{
/// <summary>
/// Ensures that the type of features on all edges of the tile to place
/// match the corresponding features on the surrounding tiles.
/// </summary>
public class AdjacentFeaturesMatchRule : IRule<PlaceTileGameAction>
{
public bool Verify<T1>(IEngine engine, T1 action)
where T1 : PlaceTileGameAction
{
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)
{
Expand Down Expand Up @@ -61,6 +67,10 @@ public bool Verify<T1>(IEngine engine, T1 action)
return allMatch;
}

/// <summary>
/// Checks that the order of the types implementing <see cref="IFeatures"/>
/// are aligned, thereby showing that the edges are matched.
/// </summary>
protected bool EdgesMatch(
IFeature[] from,
IFeature[] to
Expand Down
4 changes: 4 additions & 0 deletions Sharpasonne/Rules/HasAdjacentTileRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

namespace Sharpasonne.Rules
{
/// <summary>
/// Verify that the <see cref="PlaceTileGameAction"/> will place a tile
/// adjacent to a pre-existing tile.
/// </summary>
public class HasAdjacentTileRule : IRule<PlaceTileGameAction>
{
public bool Verify<T1>(IEngine engine, T1 gameAction) where T1 : PlaceTileGameAction
Expand Down

0 comments on commit 325de66

Please sign in to comment.