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!");
            }
        }
        public RH_Macro_Apply_Type Calculate_Macro_Application_Type(
            RH_State_Type state_Type,
            RH_Macro_Type macro_Type
            )
        {
            switch (state_Type)
            {
            case RH_State_Type.NextTurn:
                switch (macro_Type)
                {
                case RH_Macro_Type.MainPlayerActions:
                    return(RH_Macro_Apply_Type.Error);

                case RH_Macro_Type.Discarding_During:
                    return(RH_Macro_Apply_Type.Skip);

                case RH_Macro_Type.Discarding_After:
                    return(RH_Macro_Apply_Type.Skip);

                case RH_Macro_Type.None:
                    return(RH_Macro_Apply_Type.Skip);

                default:
                    return(RH_Macro_Apply_Type.Error);
                }

            case RH_State_Type.MainPlayerActions:
                switch (macro_Type)
                {
                case RH_Macro_Type.MainPlayerActions:
                    return(RH_Macro_Apply_Type.Normal);

                case RH_Macro_Type.Discarding_During:
                    return(RH_Macro_Apply_Type.Skip);

                case RH_Macro_Type.Discarding_After:
                    return(RH_Macro_Apply_Type.Insert);

                case RH_Macro_Type.None:
                    return(RH_Macro_Apply_Type.Insert);

                default:
                    return(RH_Macro_Apply_Type.Error);
                }

            case RH_State_Type.Discarding_During:
                switch (macro_Type)
                {
                case RH_Macro_Type.MainPlayerActions:
                    return(RH_Macro_Apply_Type.Insert);

                case RH_Macro_Type.Discarding_During:
                    return(RH_Macro_Apply_Type.Normal);

                case RH_Macro_Type.Discarding_After:
                    return(RH_Macro_Apply_Type.Insert);

                case RH_Macro_Type.None:
                    return(RH_Macro_Apply_Type.Insert);

                default:
                    return(RH_Macro_Apply_Type.Error);
                }

            case RH_State_Type.Discarding_After:
                switch (macro_Type)
                {
                case RH_Macro_Type.MainPlayerActions:
                    return(RH_Macro_Apply_Type.Error);

                case RH_Macro_Type.Discarding_During:
                    return(RH_Macro_Apply_Type.Skip);

                case RH_Macro_Type.Discarding_After:
                    return(RH_Macro_Apply_Type.Normal);

                case RH_Macro_Type.None:
                    return(RH_Macro_Apply_Type.Insert);

                default:
                    return(RH_Macro_Apply_Type.Error);
                }

            case RH_State_Type.None:
                switch (macro_Type)
                {
                case RH_Macro_Type.MainPlayerActions:
                    return(RH_Macro_Apply_Type.Error);

                case RH_Macro_Type.Discarding_During:
                    return(RH_Macro_Apply_Type.Error);

                case RH_Macro_Type.Discarding_After:
                    return(RH_Macro_Apply_Type.Error);

                case RH_Macro_Type.None:
                    return(RH_Macro_Apply_Type.Error);

                default:
                    return(RH_Macro_Apply_Type.Error);
                }

            default:
                return(RH_Macro_Apply_Type.Error);
            }
        }
        public void ApplySelfOnGameState(
            Random randomness_provider,
            PD_Game gameStateToApplySelfOn,
            PD_AI_PathFinder pathFinder,
            PD_AI_Macro_Agent_Base defaultPolicyAgent
            )
        {
            int currentMacroIndex = 0;

            while (Is_GameState_CorrectTurn_And_Ongoing(gameStateToApplySelfOn))
            {
                PD_MacroAction currentMacro;
                if (currentMacroIndex < MacroActions.Count)
                {
                    currentMacro = MacroActions[currentMacroIndex];
                }
                else
                {
                    currentMacro = null;
                }

                RH_State_Type state_Type = Calculate_State_Type(gameStateToApplySelfOn);
                RH_Macro_Type macro_Type = Calculate_Macro_Type(currentMacro);

                int currentGameState_TurnIndex = gameStateToApplySelfOn.game_state_counter.turn_index;

                RH_Macro_Apply_Type macroApplicationType = Calculate_Macro_Application_Type(
                    state_Type,
                    macro_Type
                    );

                // ACT ACCORDINGLY!
                switch (macroApplicationType)
                {
                case RH_Macro_Apply_Type.Normal:
                    ApplyMacroOnGameState(
                        randomness_provider,
                        gameStateToApplySelfOn,
                        currentMacro
                        );
                    currentMacroIndex++;
                    break;

                case RH_Macro_Apply_Type.Skip:
                    currentMacroIndex++;
                    break;

                case RH_Macro_Apply_Type.Insert:
                    var missingMacro = defaultPolicyAgent.GetNextMacroAction(
                        randomness_provider,
                        gameStateToApplySelfOn,
                        pathFinder
                        );
                    RH_Macro_Type missingMacroType = Calculate_Macro_Type(missingMacro);
                    MacroActions.Insert(
                        currentMacroIndex,
                        missingMacro
                        );
                    ApplyMacroOnGameState(
                        randomness_provider,
                        gameStateToApplySelfOn,
                        missingMacro
                        );
                    currentMacroIndex++;
                    break;

                case RH_Macro_Apply_Type.Error:
                    throw new System.Exception("something wrong here!");

                default:
                    throw new System.Exception("something wrong here!");
                }
            }
        }