static ActionNode CreateActionNodeAttackMelee(TBGState s, int targetUnitIndex, int damage, BoardPath path)
        {
            var cpState = new TBGState(s);
            var cpUnitCurrent = cpState.UnitCurrent;
            var cpUnitTarget = cpState.Units[targetUnitIndex];
            var cpPath = new BoardPath(path);
            bool isDead = cpUnitCurrent.Attack(cpUnitTarget, damage);

            // move unit
            cpUnitCurrent.Pos = cpPath.Last;

            // update wait list
            cpState.UpdateWaitListNext();

            return new ActionNode(new TBGActionAttackMelee(
                s.PlayerCurrent,
                s.UnitCurrentIndex,
                cpPath,
                damage,
                targetUnitIndex,
                s.Units[targetUnitIndex].Pos,
                isDead),
                //
                new StateNode(cpState));
        }
        /// <summary>
        /// Create ActionContainer that contain true and average node.
        /// </summary>
        public static ActionContainer CreateAttackRanged(TBGState s, int targetUnitIndex)
        {
            var unitCurrent = s.UnitCurrent;

            return ActionContainer.CreateAverage(
                CreateActionNodeAttackRanged(s, targetUnitIndex, unitCurrent.CreateDamageRandom()),
                CreateActionNodeAttackRanged(s, targetUnitIndex, unitCurrent.CreateDamageAverage()));
        }
        /// <summary>
        /// Create ActionContainer that contain true and average node.
        /// </summary>
        public static ActionContainer CreateAttackMelee(TBGState s, int targetUnitIndex, BoardPath path)
        {
            var unitCurrent = s.UnitCurrent;

            return ActionContainer.CreateAverage(
                CreateActionNodeAttackMelee(s, targetUnitIndex, unitCurrent.CreateDamageRandom(), path),
                CreateActionNodeAttackMelee(s, targetUnitIndex, unitCurrent.CreateDamageAverage(), path));
        }
        /// <summary>
        /// Create ActionContainer that contain only true node.
        /// </summary>
        public static ActionContainer CreateMove(TBGState s, BoardPath path)
        {
            var cpState = new TBGState(s);
            var cpUnitCurrent = cpState.UnitCurrent;
            var cpPath = new BoardPath(path);

            // update unit pos
            cpUnitCurrent.Pos = cpPath.Last;

            // update wait list
            cpState.UpdateWaitListNext();

            var moveNode = new ActionNode(new TBGActionMove(
                    s.UnitCurrent.Owner,
                    s.UnitCurrentIndex,
                    cpPath),
                    //
                    new StateNode(cpState));

            return ActionContainer.CreateTrue(moveNode);
        }
        static ActionNode CreateActionNodeAttackRanged(TBGState s, int targetUnitIndex, int damage)
        {
            var cpState = new TBGState(s);
            var cpUnitCurrent = cpState.UnitCurrent;
            var cpUnitTarget = cpState.Units[targetUnitIndex];
            bool isDead = cpUnitCurrent.Attack(cpUnitTarget, damage);

            // update wait list
            cpState.UpdateWaitListNext();

            return new ActionNode(new TBGActionAttackRanged(
                s.PlayerCurrent,
                s.UnitCurrentIndex,
                s.UnitCurrent.Pos,
                damage,
                targetUnitIndex,
                s.Units[targetUnitIndex].Pos,
                true,
                isDead),
                //
                new StateNode(cpState));
        }
        void UpdateUIForHuman(TBGState state, List<ActionContainer> actions)
        {
            var unitCurrent = state.UnitCurrent;

            // 選択状態のユニットを目立たせる
            floorButtonControllers[unitCurrent.Pos.y, unitCurrent.Pos.x].ChangeModeCurrentUnit();

            this.InterpretActionList(state, this.tacticsBG.ForceActionList(false));
        }
        /// <summary>
        /// Hp やユニットの位置などを同期させる
        /// </summary>
        /// <param name="state"></param>
        void SyncState(TBGState state)
        {
            var units = state.Units;
            for (int i = 0; i < units.Length; i++)
            {
                unitControllers[i].transform.position = ConvertBoardToWorldPos(units[i].Pos);

                if (unitControllers[i].HpSlider.gameObject.activeSelf == true)
                    unitControllers[i].SetHpbar(units[i].HpFraction);
            }
        }
        /// <summary>
        /// Action list を解釈し、UIを設定する
        /// </summary>
        /// <param name="actions"></param>
        void InterpretActionList(TBGState state, List<ActionContainer> actions)
        {
            var size = actions.Count;
            for (int i = 0; i < size; i++)
            {
                var actionNode = actions[i].ActionTrue;
                var action = actions[i].ActionTrue.Action;
                int captureIndex = i;

                // -- Move

                var actMove = action as TBGActionMove;
                if (actMove != null)
                {
                    Basic.Vec2Int goalPos = actMove.Path[actMove.Path.Count - 1];

                    // Create move button
                    floorButtonControllers[goalPos.y, goalPos.x].ChangeModeMovable(() =>
                    {
                        this.SelectActionNode(captureIndex);
                        this.AnimationMoveThenHandleStateNode(actMove);
                    });
                }

                // -- Attack ranged

                var actRanged = action as TBGActionAttackRanged;
                if (actRanged != null)
                {
                    this.targetImages.Add(this.TargetImageCreate(Define.Path.Sprite.WeaponBow, actRanged.TargetUnitIndex));

                    // Create ranged attack button
                    floorButtonControllers[actRanged.TargetUnitPos.y, actRanged.TargetUnitPos.x].ChangeModeTarget(() =>
                    {
                        this.TargetImagesClear();
                        this.SelectActionNode(captureIndex);
                        this.AnimationAttackRangedThenHandleStateNode(actRanged);
                    });
                }
            }

            // -- Melee attack

            // Collect index and melee attack
            var actionIndexAndMeleeAttacks = new Dictionary<int, TBGActionAttackMelee>(actions.Count);
            for (int i = 0; i < actions.Count; i++)
            {
                var action = actions[i].ActionTrue.Action;
                var cast = action as TBGActionAttackMelee;
                if (cast != null)
                {
                    actionIndexAndMeleeAttacks.Add(i, cast);
                }
            }

            if (actionIndexAndMeleeAttacks.Count > 0)
            {
                for (int indexUnit = 0; indexUnit < state.Units.Length; indexUnit++)
                {
                    // Collect attack action of attacking same target
                    var actionIndexAndAttackMeleeTargetUnits = new Dictionary<int, TBGActionAttackMelee>(actionIndexAndMeleeAttacks.Count);
                    var attackTargetPos = Basic.Vec2Int.Zero;
                    var captureUnitIndex = indexUnit;

                    foreach (KeyValuePair<int, TBGActionAttackMelee> indexAndAttack in actionIndexAndMeleeAttacks)
                    {
                        if (indexAndAttack.Value.TargetUnitIndex == indexUnit)
                        {
                            attackTargetPos = indexAndAttack.Value.TargetUnitPos;
                            actionIndexAndAttackMeleeTargetUnits.Add(indexAndAttack.Key, indexAndAttack.Value);
                        }
                    }

                    // Create target button
                    if (actionIndexAndAttackMeleeTargetUnits.Count >= 1)
                    {
                        this.targetImages.Add(this.TargetImageCreate(Define.Path.Sprite.WeaponAxe, captureUnitIndex));

                        // Create melee attack button
                        floorButtonControllers[attackTargetPos.y, attackTargetPos.x].ChangeModeTarget(() =>
                        {
                            this.DisableUI();
                            this.TargetImagesClear();

                            var captureAttacks = actionIndexAndAttackMeleeTargetUnits;
                            var captureX = attackTargetPos.x;
                            var captureY = attackTargetPos.y;

                            floorButtonControllers[captureY, captureX].ChangeModeTargetNoClick();

                            foreach (KeyValuePair<int, TBGActionAttackMelee> indexAndAttack in captureAttacks)
                            {

                                var index = indexAndAttack.Key;
                                var attack = indexAndAttack.Value;
                                var attackFromPos = attack.Path.Last;
                                var attackVec = attack.TargetUnitPos - attackFromPos;
                                var unitObject = unitControllers[attack.UnitIndex];
                                var targetUnitObject = unitControllers[attack.TargetUnitIndex];

                                bool isAttackFromActiveUnit = false;
                                if (attackFromPos == state.UnitCurrent.Pos)
                                    isAttackFromActiveUnit = true;

                                // Create attack direction image
                                this.attackDirectionImages.Add(AttackDirectionImageCreate(attackFromPos, attack.TargetUnitPos));

                                // create attack direction button
                                floorButtonControllers[attackFromPos.y, attackFromPos.x].ChangeModeAttackDirection(() =>
                                {
                                    this.AttackDirectionImagesClear();
                                    this.SelectActionNode(index);
                                    this.AnimationAttackMeleeThenHandleStateNode(attack);
                                }, isAttackFromActiveUnit);
                            }
                    });
                    }
                }
            }
        }
        void GameEnd(TBGState state)
        {
            var winner = TacticsBG.TacticsBG.Winners(state);
            Debug.Log(DebugUtil.FN + "Game End");

            StartCoroutine(Coroutine_.Action.WaitFunc(2f, () =>
            {
                windowGameEnd.gameObject.SetActive(true);
                windowGameEnd.Init("墓荒らし", "墓守",
                    winner[0] == 0 ? true : false,
                    isPlayerVsPlayer,
                    // LButton
                    this.Replay,
                    // RButton
                    () => { SceneArgumentManager.LoadScene(Define.Scene.Title); });
            }));
        }