Any time you have multiple independent boolean variables representing a state, consider using a bitfield through the use of an enum with the FlagsAttribute
applied. That way you don't need to maintain multiple variables to represent a single state.
[Flags]
public enum BoardState
{
None = 0x0,
IsCheck = 0x1,
IsStuck = 0x2,
}
Then you could map these board states to the appropriate game state. Just make sure you map out every valid combination if you plan on using a dictionary.
private Dictionary<BoardState, GameState> transition = new Dictionary<BoardState, GameState>
{
{ BoardState.None, GameState.Ok },
{ BoardState.IsCheck, GameState.Check },
{ BoardState.IsStuck, GameState.Stalemate },
{ BoardState.IsCheck | BoardState.IsStuck, GameState.Mate },
};
public GameState Next(BoardState boardState)
{
GameState nextState;
if (!transition.TryGetValue(boardState, out nextState))
throw new ArgumentOutOfRangeException("boardState");
return nextState;
}
Otherwise use a switch statement if the mapping gets too unruly or you want to map multiple combinations to a single value (it's not necessary in this case).
public GameState Next(BoardState boardState)
{
switch (boardState)
{
case BoardState.None:
return GameState.Ok;
case BoardState.IsCheck:
return GameState.Check;
case BoardState.IsStuck:
return GameState.Stalemate;
case BoardState.IsCheck | BoardState.IsStuck:
return GameState.Mate;
default:
throw new ArgumentOutOfRangeException("boardState");
}
}
Then use regular bit manipulation to set/clear the flags. Do take care in using this if you have values that represent multiple values
BoardState boardState = ...;
// to set a flag
boardState |= BoardState.IsCheck;
// to clear a flag
boardState &= ~BoardState.IsStuck;
// to test a flag
boardState.HasFlag(BoardState.IsCheck);
You can clean keep this nice and clean exposing this through boolean properties.
private BoardState internalBoardState;
public bool IsCheck
{
get { return internalBoardState.HasFlag(BoardState.IsCheck); }
set
{
if (value)
internalBoardState |= BoardState.IsCheck;
else
internalBoardState &= ~BoardState.IsCheck;
}
}
public bool IsStuck
{
get { return internalBoardState.HasFlag(BoardState.IsStuck); }
set
{
if (value)
internalBoardState |= BoardState.IsStuck;
else
internalBoardState &= ~BoardState.IsStuck;
}
}
GetGameState(isCheck, isStuck)
. \$\endgroup\$if (isStuck) { displayReason(); GameOver();}
... else ...if (IsCheck) { SayCheck(); }
. If you generate the enum, then you still need to run a bunch of conditions on it. \$\endgroup\$