private RH_Macro_Type Calculate_Macro_Type(
            PD_MacroAction macroAction
            )
        {
            if (macroAction == null)
            {
                return(RH_Macro_Type.None);
            }
            else if (
                macroAction.MacroAction_Type == PD_MacroAction_Type.Stay_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.Walk_Macro

                || macroAction.MacroAction_Type == PD_MacroAction_Type.TreatDisease_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.TreatDisease_Medic_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.AutoTreatDisease_Medic_Macro

                || macroAction.MacroAction_Type == PD_MacroAction_Type.BuildResearchStation_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.BuildResearchStation_OperationsExpert_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.MoveResearchStation_Macro

                || macroAction.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Give_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Take_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Give_ResearcherGives_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Take_FromResearcher_Macro

                || macroAction.MacroAction_Type == PD_MacroAction_Type.TakePositionFor_ShareKnowledge_Give_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.TakePositionFor_ShareKnowledge_Take_Macro

                || macroAction.MacroAction_Type == PD_MacroAction_Type.DiscoverCure_Macro ||
                macroAction.MacroAction_Type == PD_MacroAction_Type.DiscoverCure_Scientist_Macro
                )
            {
                return(RH_Macro_Type.MainPlayerActions);
            }
            else if (
                macroAction.MacroAction_Type == PD_MacroAction_Type.Discard_DuringMainPlayerActions_Macro
                )
            {
                return(RH_Macro_Type.Discarding_During);
            }
            else if (
                macroAction.MacroAction_Type == PD_MacroAction_Type.Discard_AfterDrawing_Macro
                )
            {
                return(RH_Macro_Type.Discarding_After);
            }
            else
            {
                throw new System.Exception("something wrong here!");
            }
        }
        public void Apply_Macro_Action(
            Random randomness_provider,
            PD_MacroAction macro
            )
        {
            if (game_FSM.CurrentState.GetType() == typeof(PD_GS_ApplyingMainPlayerActions))
            {
                if (
                    macro.MacroAction_Type == PD_MacroAction_Type.Walk_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.Stay_Macro

                    || macro.MacroAction_Type == PD_MacroAction_Type.TreatDisease_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.TreatDisease_Medic_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.AutoTreatDisease_Medic_Macro

                    || macro.MacroAction_Type == PD_MacroAction_Type.BuildResearchStation_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.BuildResearchStation_OperationsExpert_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.MoveResearchStation_Macro

                    || macro.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Give_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Give_ResearcherGives_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Take_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.ShareKnowledge_Take_FromResearcher_Macro

                    || macro.MacroAction_Type == PD_MacroAction_Type.TakePositionFor_ShareKnowledge_Give_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.TakePositionFor_ShareKnowledge_Take_Macro

                    || macro.MacroAction_Type == PD_MacroAction_Type.DiscoverCure_Macro ||
                    macro.MacroAction_Type == PD_MacroAction_Type.DiscoverCure_Scientist_Macro
                    )
                {
                    var executablePart = new List <PD_Action>();
                    int numRemainingActionsThisRound = 4 - game_state_counter.player_action_index;
                    for (int i = 0; i < numRemainingActionsThisRound; i++)
                    {
                        if (i < macro.Count_Total_Length())
                        {
                            executablePart.Add(macro.Actions_All[i].GetCustomDeepCopy());
                        }
                    }

                    foreach (var command in executablePart)
                    {
                        if (CurrentAvailablePlayerActions.Contains(command))
                        {
                            Apply_Action(
                                randomness_provider,
                                command
                                );
                        }
                        else
                        {
                            Console.WriteLine(macro.GetDescription());
                            Console.WriteLine("problem: " + command.GetDescription());
                            throw new System.Exception("command cannot be applied!");
                        }
                    }
                }
                else
                {
                    throw new System.Exception("wrong macro type");
                }
            }
            else if (this.GQ_IsInState_DiscardAfterDrawing())
            {
                PD_MacroAction_Type mat = macro.MacroAction_Type;
                if (mat == PD_MacroAction_Type.Discard_AfterDrawing_Macro)
                {
                    var action = macro.Actions_All[0];
                    if (CurrentAvailablePlayerActions.Contains(action))
                    {
                        //Console.WriteLine("applying command: " + action.GetDescription());
                        Apply_Action(
                            randomness_provider,
                            action
                            );
                    }
                    else
                    {
                        throw new System.Exception("command cannot be applied!");
                    }
                }
                else
                {
                    throw new System.Exception("wrong macro type");
                }
            }
            else if (this.GQ_IsInState_DiscardDuringMainPlayerActions())
            {
                PD_MacroAction_Type mat = macro.MacroAction_Type;
                if (mat == PD_MacroAction_Type.Discard_DuringMainPlayerActions_Macro)
                {
                    var action = macro.Actions_All[0];
                    if (CurrentAvailablePlayerActions.Contains(action))
                    {
                        //Console.WriteLine("applying command: " + action.GetDescription());
                        Apply_Action(
                            randomness_provider,
                            action
                            );
                    }
                    else
                    {
                        throw new System.Exception("command cannot be applied!");
                    }
                }
                else
                {
                    throw new System.Exception("wrong macro type");
                }
            }
        }
        public void MutateSelf(
            Random randomness_provider,
            PD_Game initial_gameState,
            PD_AI_PathFinder pathFinder,
            PD_AI_Macro_Agent_Base defaultPolicyAgent,
            PD_AI_Macro_Agent_Base mutatorAgent
            )
        {
            PD_Game mutation_GameState = initial_gameState.Request_Randomized_Copy(randomness_provider);

            int numberOfMacros = MacroActions.Count;
            int mutationIndex  = randomness_provider.Next(numberOfMacros);

            List <PD_MacroAction> mutated_MacroActions = new List <PD_MacroAction>();

            // first apply the non - mutated actions
            int counter = 0;

            while (Is_GameState_CorrectTurn_And_Ongoing(mutation_GameState))
            {
                if (counter < mutationIndex)
                {
                    // counter < mutation index => simply copy the existing macros into the mutated macros list.

                    PD_MacroAction currentMacro = MacroActions[counter];

                    RH_State_Type stateType = Calculate_State_Type(mutation_GameState);
                    RH_Macro_Type macroType = Calculate_Macro_Type(currentMacro);

                    RH_Macro_Apply_Type response = Calculate_Macro_Application_Type(
                        stateType,
                        macroType
                        );

                    switch (response)
                    {
                    case RH_Macro_Apply_Type.Normal:

                        // store the macro and then apply it
                        mutated_MacroActions.Add(
                            MacroActions[counter]
                            );

                        ApplyMacroOnGameState(
                            randomness_provider,
                            mutation_GameState,
                            MacroActions[counter]
                            );

                        counter++;

                        break;

                    case RH_Macro_Apply_Type.Insert:

                        PD_MacroAction actionToInsert = defaultPolicyAgent.GetNextMacroAction(
                            randomness_provider,
                            mutation_GameState,
                            pathFinder
                            );

                        // first correct the macro actions, themselves...
                        MacroActions.Insert(
                            counter,
                            actionToInsert
                            );

                        mutated_MacroActions.Add(
                            actionToInsert
                            );

                        ApplyMacroOnGameState(
                            randomness_provider,
                            mutation_GameState,
                            actionToInsert
                            );

                        counter++;

                        mutationIndex++;

                        break;

                    case RH_Macro_Apply_Type.Skip:

                        // keep the skipped action, but do not apply it!
                        mutated_MacroActions.Add(
                            MacroActions[counter]
                            );

                        counter++;

                        break;

                    case RH_Macro_Apply_Type.Error:

                        throw new System.Exception("error here!");
                    }
                }
                else if (counter == mutationIndex)
                {
                    // counter == mutation index => ask the mutator to provide a new action

                    var replacement_MacroAction = mutatorAgent.GetNextMacroAction(
                        randomness_provider,
                        mutation_GameState,
                        pathFinder
                        );

                    mutated_MacroActions.Add(replacement_MacroAction);

                    ApplyMacroOnGameState(
                        randomness_provider,
                        mutation_GameState,
                        replacement_MacroAction
                        );

                    counter++;
                }
                else
                {
                    // counter > mutation index => ask the default policy agent to provide a new action

                    var nextMacro = defaultPolicyAgent.GetNextMacroAction(
                        randomness_provider,
                        mutation_GameState,
                        pathFinder
                        );
                    if (nextMacro == null)
                    {
                        throw new System.Exception("problem here");
                    }
                    ApplyMacroOnGameState(
                        randomness_provider,
                        mutation_GameState,
                        nextMacro
                        );
                    mutated_MacroActions.Add(nextMacro);

                    counter++;
                }
            }

            MacroActions = mutated_MacroActions;
        }
        public void ApplyMacroOnGameState(
            Random randomness_provider,
            PD_Game gameState,
            PD_MacroAction macro
            )
        {
            RH_State_Type stateType = Calculate_State_Type(gameState);
            RH_Macro_Type macroType = Calculate_Macro_Type(macro);

            bool gameStateOngoing = gameState.GQ_Is_Ongoing();

            if (gameStateOngoing == false)
            {
                return;
            }

            if (macroType == RH_Macro_Type.MainPlayerActions)
            {
                int numAvailableActions         = gameState.GQ_RemainingPlayerActions_ThisRound();
                List <PD_Action> executablePart = new List <PD_Action>();
                for (int i = 0; i < numAvailableActions; i++)
                {
                    if (i < macro.Actions_All.Count)
                    {
                        executablePart.Add(macro.Actions_All[i]);
                    }
                }
                // soft apply!
                foreach (var action in executablePart)
                {
                    var availableCommands = gameState.CurrentAvailablePlayerActions;
                    if (availableCommands.Contains(action))
                    {
                        gameState.Apply_Action(
                            randomness_provider,
                            action
                            );
                    }
                    else
                    {
                        var stayAction = availableCommands.Find(
                            x =>
                            x.GetType() == typeof(PA_Stay)
                            );
                        if (stayAction != null)
                        {
                            gameState.Apply_Action(
                                randomness_provider,
                                stayAction
                                );
                        }
                        else
                        {
                            throw new System.Exception("something wrong here!");
                        }
                    }
                }
            }
            else if (macroType == RH_Macro_Type.Discarding_During)
            {
                foreach (var action in macro.Actions_All)
                {
                    var availableCommands = gameState.CurrentAvailablePlayerActions;
                    if (availableCommands.Contains(action))
                    {
                        gameState.Apply_Action(
                            randomness_provider,
                            action
                            );
                    }
                    else
                    {
                        // pick one at random!
                        gameState.Apply_Action(
                            randomness_provider,
                            availableCommands.GetOneRandom(randomness_provider)
                            );
                    }
                }
            }
            else if (macroType == RH_Macro_Type.Discarding_After)
            {
                foreach (var action in macro.Actions_All)
                {
                    var availableCommands = gameState.CurrentAvailablePlayerActions;
                    if (availableCommands.Contains(action))
                    {
                        gameState.Apply_Action(
                            randomness_provider,
                            action
                            );
                    }
                    else
                    {
                        // pick one at random!
                        gameState.Apply_Action(
                            randomness_provider,
                            availableCommands.GetOneRandom(randomness_provider)
                            );
                    }
                }
            }
            else
            {
                throw new System.Exception("something wrong here!");
            }
        }