/// <summary> /// Constructs a new instance of the game state machine. /// </summary> public GameStateMachine(IPlayerDirector director, ILogger <GameStateMachine> logger) { _logger = logger; Director = director; GameData = new GameData(); GameDataManipulator = new GameDataManipulator(GameData); PolicyDeck = new PolicyDeck(GameData.DrawPile, GameData.DiscardPile, true); }
private async Task InvokePolicyPeek() { var policiesToDisplay = PolicyDeck.Peek(Constants.PresidentialPolicyDrawCount); GameData.MachineState = StateMachineState.AwaitingSpecialPowerAcknowledgment; await Director.Broadcast($"The president is being shown the topmost {Constants.PresidentialPolicyDrawCount} policies on the draw pile."); await Director.PolicyPeek(GameData.President, policiesToDisplay); }
/// <summary> /// Indicates that a vote has been collected. /// </summary> /// <param name="vote">The collected vote.</param> public async Task VoteCollected(bool vote) { if (GameData.MachineState != StateMachineState.AwaitingVotes) { throw new GameStateException($"{nameof(VoteCollected)} called for invalid state {GameData.MachineState}."); } if (vote) { GameData.JaVoteCount++; } else { GameData.NeinVoteCount++; } if (GameData.JaVoteCount + GameData.NeinVoteCount < GameData.Players.Count(_ => _.IsAlive)) { return; } var message = $"Votes have been tallied: {GameData.JaVoteCount} ja, {GameData.NeinVoteCount} nein."; if (GameData.JaVoteCount > GameData.NeinVoteCount) { await Director.Broadcast($"{message} The election was successful."); if (GameData.EnactedFascistPolicyCount >= Constants.RequiredFascistPoliciesForHitlerChancellorshipVictory && GameData.Chancellor.Role == PlayerRole.Hitler) { GameData.MachineState = StateMachineState.None; await Director.Broadcast("Congratulations on becoming chancellor, Hitler. FASCIST VICTORY!"); await DisseminateGameData(); return; } GameData.MachineState = StateMachineState.AwaitingPresidentialPolicies; await DisseminateGameData(); GameData.DrawnPolicies = PolicyDeck.Draw(Constants.PresidentialPolicyDrawCount).ToList(); await Director.GetPresidentialPolicies(GameData.President, GameData.DrawnPolicies); } else { message = $"{message} The election failed."; await UpdateElectionTrackerAndHandleChaos(message); } GameData.JaVoteCount = 0; GameData.NeinVoteCount = 0; }
/// <summary> /// Initialize the game data for a new game. /// </summary> public virtual void ResetGame() { // Mark all players as alive and assign them some roles foreach (var player in Game.Players) { player.Role = PlayerRole.Liberal; player.IsAlive = true; player.IsPresident = false; player.IsChancellor = false; } var liberals = Game.Players.ToArray(); liberals.Shuffle(); var fascistCount = 1 + ((Game.Players.Count - 5) / 2); foreach (var fascist in liberals.Take(fascistCount)) { fascist.Role = PlayerRole.Fascist; } liberals.Skip(fascistCount).First().Role = PlayerRole.Hitler; // Set up the presidential queue var shuffled = Game.Players.Select(p => p.Identifier).ToList(); shuffled.Shuffle(); Game.PresidentialQueue = new Queue <Guid>(shuffled); Game.Players = new List <PlayerData>(Game.PresidentialQueue.Join(Game.Players, o => o, i => i.Identifier, (o, i) => i).ToList()); Game.IneligibleChancellors = new List <Guid>(); Game.EnactedFascistPolicyCount = 0; Game.EnactedLiberalPolicyCount = 0; Game.ElectionTracker = 0; Game.GameGuid = Guid.NewGuid(); Game.JaVoteCount = 0; Game.NeinVoteCount = 0; var _ = new PolicyDeck(Game.DrawPile, Game.DiscardPile, true); }
/// <summary> /// Indicates a simple acknowledgement from a client. /// </summary> /// <param name="acknowledge">Favorable or unfavorable response, or null if not applicable.</param> public async Task Acknowledge(bool?acknowledge) { switch (GameData.MachineState) { case StateMachineState.AwaitingVetoResponse: if (!acknowledge.HasValue) { throw new GameStateException("Expecting true or false response for veto approval, not null."); } else if (acknowledge.Value) { // TODO test PolicyDeck.Discard(GameData.DrawnPolicies); GameData.DrawnPolicies = null; await UpdateElectionTrackerAndHandleChaos("The policies were successfully vetoed!"); } else { // TODO test await Director.Broadcast("Unsuccessful veto. The chancellor must choose a policy."); GameData.MachineState = StateMachineState.AwaitingEnactedPolicy; await Director.GetEnactedPolicy(GameData.Chancellor, GameData.DrawnPolicies, false); } break; case StateMachineState.AwaitingSpecialPowerAcknowledgment: await PrepareNextElection(); break; default: throw new GameStateException($"{nameof(Acknowledge)} called for invalid state {GameData.MachineState}."); } }
public void LoadGameState(GameData data) { GameData = data; GameDataManipulator = new GameDataManipulator(GameData); PolicyDeck = new PolicyDeck(data.DrawPile, data.DiscardPile, false); }
/// <summary> /// Indicates that one or more policies were selected by the client asked to select policies. /// </summary> /// <param name="policies">The selected policies.</param> public async Task PoliciesSelected(IEnumerable <PolicyType> policies) { var myPolicies = policies.ToList(); switch (GameData.MachineState) { case StateMachineState.AwaitingEnactedPolicy: // TODO Validate policy was actually drawn, delivered by correct player if (myPolicies.Count != Constants.ChancellorPolicySelectionCount) { throw new GameStateException("Too many policies selected for the current game state."); } var policy = myPolicies.First(); if (policy == PolicyType.None) { if (!AllowVetoes) { throw new GameStateException("Currently not eligible to veto policies."); } await Director.Broadcast("A veto has been requested."); GameData.MachineState = StateMachineState.AwaitingVetoResponse; await Director.ApproveVeto(GameData.President); return; } foreach (var p in myPolicies) { GameData.DrawnPolicies.Remove(p); } PolicyDeck.Discard(GameData.DrawnPolicies); GameData.DrawnPolicies = null; if (policy == PolicyType.Fascist) { await Director.Broadcast("A fascist policy has been enacted!"); GameData.EnactedFascistPolicyCount++; await DisseminateGameData(); if (InvokeCurrentPresidentialPower()) { return; } } else if (policy == PolicyType.Liberal) { await Director.Broadcast("A liberal policy has been enacted!"); GameData.EnactedLiberalPolicyCount++; } await PrepareNextElection(); break; case StateMachineState.AwaitingPresidentialPolicies: // TODO Validate policy was actually drawn, delivered by correct player // TODO Test me. if (myPolicies.Count != Constants.PresidentialPolicyPassCount) { throw new GameStateException("Too many/few policies selected for the current game state."); } foreach (var p in myPolicies) { GameData.DrawnPolicies.Remove(p); } PolicyDeck.Discard(GameData.DrawnPolicies); GameData.DrawnPolicies = policies.ToList(); await Director.Broadcast("The president has offered policies to the chancellor."); GameData.MachineState = StateMachineState.AwaitingEnactedPolicy; await Director.GetEnactedPolicy(GameData.Chancellor, policies, AllowVetoes); break; default: throw new GameStateException($"{nameof(PoliciesSelected)} called for invalid state {GameData.MachineState}."); } }