Example #1
0
 /// <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);
 }
Example #2
0
        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);
        }
Example #3
0
        /// <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);
        }
Example #5
0
        /// <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}.");
            }
        }
Example #6
0
 public void LoadGameState(GameData data)
 {
     GameData            = data;
     GameDataManipulator = new GameDataManipulator(GameData);
     PolicyDeck          = new PolicyDeck(data.DrawPile, data.DiscardPile, false);
 }
Example #7
0
        /// <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}.");
            }
        }