Exemplo n.º 1
0
        public void StateDeepCopyTest()
        {
            var game = new GameInstance(3);

            var ability   = new AbilityInfo(3, 1, 1, 0);
            var abilityId = game.AddAbilityWithInfo(ability);

            var abilities1 = new List <int>();
            var abilities2 = new List <int> {
                abilityId
            };

            var info1 = new MobInfo(TeamColor.Red, 5, 1, 0, abilities1);
            var info2 = new MobInfo(TeamColor.Blue, 5, 1, 1, abilities2);

            var m1 = game.AddMobWithInfo(info1);
            var m2 = game.AddMobWithInfo(info2);

            game.PrepareEverything();

            var copy = game.CopyStateOnly();

            TestHelpers.GameInstancesEqual(game, copy);

            var copy2 = copy.CopyStateOnly();

            ActionEvaluator.F(copy2, UctAction.AbilityUseAction(abilityId, m1, m2));

            TestHelpers.GameInstancesEqual(game, copy);

            TestHelpers.MobManagersEqual(game.MobManager, copy2.MobManager);
            TestHelpers.MapsEqual(game.Map, copy2.Map);
        }
Exemplo n.º 2
0
        public void BasicIniciativeTest()
        {
            var game = new GameInstance(3);
            var m2   = game.AddMobWithInfo(new MobInfo(TeamColor.Blue, 10, 10, 2, new List <int>()));
            var m3   = game.AddMobWithInfo(new MobInfo(TeamColor.Blue, 10, 10, 3, new List <int>()));
            var m4   = game.AddMobWithInfo(new MobInfo(TeamColor.Red, 10, 10, 4, new List <int>()));
            var m1   = game.AddMobWithInfo(new MobInfo(TeamColor.Red, 10, 10, 1, new List <int>()));

            game.PrepareEverything();

            Assert.AreEqual(game.CurrentMob, m1);

            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());
            Assert.AreEqual(game.CurrentMob, m2);

            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());
            Assert.AreEqual(game.CurrentMob, m3);

            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());
            Assert.AreEqual(game.CurrentMob, m4);

            // At this point a new turn should start

            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());
            Assert.AreEqual(game.CurrentMob, m1);

            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());
            Assert.AreEqual(game.CurrentMob, m2);

            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());
            Assert.AreEqual(game.CurrentMob, m3);

            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());
            Assert.AreEqual(game.CurrentMob, m4);
        }
Exemplo n.º 3
0
        public static void AssertValidAction(GameInstance game, UctAction action)
        {
            switch (action.Type)
            {
            case UctActionType.Null:
                break;

            case UctActionType.EndTurn:
                break;

            case UctActionType.Move:
            case UctActionType.DefensiveMove:
                AssertValidMoveAction(game, action);
                break;

            case UctActionType.AbilityUse:
                AssertValidAbilityUseAction(game, action);
                break;

            case UctActionType.AttackMove:
                AssertValidMoveAction(game, action);
                var afterMove = ActionEvaluator.F(game, action.ToPureMove());
                AssertValidAbilityUseAction(afterMove, action.ToPureAbilityUse());
                break;
            }
        }
Exemplo n.º 4
0
        public void NodeActionComputeTest()
        {
            var game = new GameInstance(3);

            var ability   = new AbilityInfo(3, 1, 1, 0);
            var abilityId = game.AddAbilityWithInfo(ability);

            var abilities1 = new List <int>();
            var abilities2 = new List <int> {
                abilityId
            };

            var info1 = new MobInfo(TeamColor.Red, 5, 1, 0, abilities1);
            var info2 = new MobInfo(TeamColor.Blue, 5, 1, 1, abilities2);

            var m1 = game.AddMobWithInfo(info1);
            var m2 = game.AddMobWithInfo(info2);

            game.PlaceMob(m1, new AxialCoord(1, 1));
            game.PlaceMob(m2, new AxialCoord(-1, -1));

            game.PrepareEverything();

            Assert.IsTrue(game.CurrentMob.HasValue);
            Assert.AreEqual(m1, game.CurrentMob.Value);

            var firstNode = new UctNode(0, 0, UctAction.NullAction(), game);

            firstNode.PrecomputePossibleActions(true, true);

            Assert.AreEqual(3, firstNode.PossibleActions.Count);
        }
Exemplo n.º 5
0
        public static void AssertAndRecord(GameInstance game, UctAction action, bool condition, string message)
        {
            if (!condition)
            {
                ReplayRecorder.Instance.SaveAndClear(game, 0);

                throw new InvariantViolationException($"Check failed for action {action}, reason: {message}");
            }
        }
Exemplo n.º 6
0
        public HistoryLogEntry(int actionIndex, TeamColor currentTeam, UctAction action, CachedMob mob, CachedMob target,
                               AbilityInfo abilityInfo,
                               int?moveCost,
                               AssetManager assetManager)
        {
            _actionIndex  = actionIndex;
            _assetManager = assetManager;
            Renderer      = this;
            CurrentTeam   = currentTeam;

            Message = BuildMessage(action, mob, target, abilityInfo, moveCost);
        }
Exemplo n.º 7
0
        public static void AssertValidMoveAction(GameInstance game, UctAction action)
        {
            var atCoord     = game.State.AtCoord(action.Coord, true);
            var mobInstance = game.State.MobInstances[action.MobId];

            var distance = game.Pathfinder.Distance(mobInstance.Coord, action.Coord);

            AssertAndRecord(game, action, mobInstance.Ap >= distance, "mobInstance.Ap >= distance");

            AssertAndRecord(game, action, game.Map[action.Coord] == HexType.Empty, "Trying to move into a wall");
            AssertAndRecord(game, action, atCoord != action.MobId,
                            "Trying to move into the coord you're already standing on.");
            AssertAndRecord(game, action, atCoord == null, "Trying to move into a mob.");
        }
Exemplo n.º 8
0
 public async Task SlowActionApplied(UctAction action)
 {
     if (action.Type == UctActionType.Move)
     {
         await SlowEventMobMoved(action.MobId, action.Coord);
     }
     else if (action.Type == UctActionType.AbilityUse)
     {
         await SlowEventAbilityUsed(action.MobId, action.TargetId, _game.MobManager.Abilities[action.AbilityId]);
     }
     else
     {
         throw new ArgumentException(
                   $"{nameof(GameBoardController)} only supports {nameof(UctActionType.Move)} and {nameof(UctActionType.AbilityUse)} actions.");
     }
 }
Exemplo n.º 9
0
        public void IsFinishedFastAutoUpdateTest()
        {
            var game = new GameInstance(3);

            var a1 = game.AddAbilityWithInfo(new AbilityInfo(5, 1, 5, 0));

            var m1 = game.AddMobWithInfo(new MobInfo(TeamColor.Red, 1, 10, 0, new[] { a1 }));
            var m2 = game.AddMobWithInfo(new MobInfo(TeamColor.Blue, 1, 10, 0, new[] { a1 }));

            game.PrepareEverything();

            Assert.IsFalse(game.IsFinished);

            ActionEvaluator.FNoCopy(game, UctAction.AbilityUseAction(a1, m1, m2));
            Assert.IsTrue(game.IsFinished);
        }
Exemplo n.º 10
0
        public static UctAction CanMoveTo(GameInstance game, CachedMob mob, AxialCoord coord)
        {
            bool isEmpty = game.Map[coord] == HexType.Empty && game.State.AtCoord(coord, true) == null;

            int  distance    = game.Pathfinder.Distance(mob.MobInstance.Coord, coord);
            int  remainingAp = mob.MobInstance.Ap - distance;
            bool enoughAp    = remainingAp >= 0;

            if (isEmpty && enoughAp)
            {
                return(UctAction.MoveAction(mob.MobId, coord));
            }
            else
            {
                return(UctAction.NullAction());
            }
        }
Exemplo n.º 11
0
        public static GameInstance FNoCopy(GameInstance state, UctAction action)
        {
            Actions++;
            ActionCounts[action.Type]++;

            Constants.WriteLogLine(action);

            if (Constants.RecordReplays)
            {
                ReplayRecorder.Instance.Actions.Add(action);
            }

            GameInvariants.AssertValidAction(state, action);

            switch (action.Type)
            {
            case UctActionType.Null:
                // do nothing
                break;

            case UctActionType.EndTurn:
                state.State.LastTeamColor = state.CurrentTeam;
                state.TurnManager.NextMobOrNewTurn();
                break;

            case UctActionType.AbilityUse:
                FastUse(state, action.AbilityId, action.MobId, action.TargetId);
                break;

            case UctActionType.AttackMove:
                FastMove(state, action.MobId, action.Coord);
                FastUse(state, action.AbilityId, action.MobId, action.TargetId);
                break;

            case UctActionType.Move:
            case UctActionType.DefensiveMove:
                FastMove(state, action.MobId, action.Coord);
                break;

            default:
                throw new InvalidOperationException($"Invalid value of {action.Type}");
            }

            return(state);
        }
Exemplo n.º 12
0
        private void AttackMob(int targetId)
        {
            Debug.Assert(SelectedAbilityIndex != null,
                         "_gameInstance.TurnManager.SelectedAbilityIndex != null");

            var abilityIndex = SelectedAbilityIndex.Value;
            var mobId        = _game.CurrentMob;

            Debug.Assert(mobId != null);
            var abilityId = _game.MobManager.MobInfos[mobId.Value].Abilities[abilityIndex];

            var visibilityPath =
                _game.Map.AxialLinedraw(_game.State.MobInstances[mobId.Value].Coord,
                                        _game.State.MobInstances[targetId].Coord);

            bool isVisible = true;

            foreach (var coord in visibilityPath)
            {
                if (_game.Map[coord] == HexType.Wall)
                {
                    isVisible = false;
                }
            }

            if (isVisible)
            {
                bool withinRange = (visibilityPath.Count - 1) <= _game.MobManager.Abilities[abilityId].Range;
                if (withinRange)
                {
                    InputManager.Instance.UserInputEnabled = false;
                    _eventHub.SlowPlayAction(_game, UctAction.AbilityUseAction(abilityId, mobId.Value, targetId))
                    .ContinueWith(t => { InputManager.Instance.UserInputEnabled = true; })
                    .LogContinuation();
                }
                else
                {
                    ShowMessage("Target is outside the range of the currently selected ability.");
                }
            }
            else
            {
                ShowMessage("The target is not visible.");
            }
        }
Exemplo n.º 13
0
        public HistoryLog(SpriteFont font, int width, AssetManager assetManager)
        {
            _font         = font;
            _width        = width;
            _assetManager = assetManager;

            _childrenPlaceholder          = AddChild(new VerticalLayout());
            _childrenPlaceholder.Position = _textOffset;
            _childrenPlaceholder.Renderer = new SpriteRenderer(_assetManager[AssetManager.HistoryLogBg]);
            _childrenPlaceholder.Padding  = new Vector4(35, 20, 20, 20);

            for (int i = 0; i < MaxHistorySize; i++)
            {
                var entry = new HistoryLogEntry(-1, TeamColor.Red, UctAction.NullAction(), null, null, null, null,
                                                assetManager);
                _log.Add(entry);
                _childrenPlaceholder.AddChild(entry);
            }
        }
Exemplo n.º 14
0
        public void DefaultPolicyTest()
        {
            var game = new GameInstance(3);

            var ability1 = new AbilityInfo(1, 1, 1, 0);
            var a1       = game.AddAbilityWithInfo(ability1);

            var ability2 = new AbilityInfo(3, 1, 1, 0);
            var a2       = game.AddAbilityWithInfo(ability2);

            var abilities1 = new List <int>();
            var abilities2 = new List <int> {
                a1,
                a2
            };

            var info1 = new MobInfo(TeamColor.Red, 5, 1, 0, abilities1);
            var info2 = new MobInfo(TeamColor.Blue, 5, 1, 1, abilities2);

            game.AddMobWithInfo(info1);
            game.AddMobWithInfo(info2);
            game.PrepareEverything();

            Assert.IsFalse(game.IsFinished);

            var uct    = new UctAlgorithm(100);
            var result = UctAlgorithm.DefaultPolicy(game, TeamColor.Red);

            Assert.AreEqual(0, result);
            ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction());

            Assert.AreEqual(TeamColor.Blue, game.CurrentTeam);

            var bestAction = ActionGenerator.DefaultPolicyAction(game);

            Console.WriteLine($"Best: {bestAction}");

            var node = uct.UctSearch(game);

            Console.WriteLine(node);
        }
Exemplo n.º 15
0
        public string BuildMessage(UctAction action, CachedMob mob, CachedMob target, AbilityInfo abilityInfo, int?moveCost)
        {
            if (action.Type == UctActionType.Null)
            {
                return(" ");
            }

            string str;

            switch (action.Type)
            {
            case UctActionType.AbilityUse:
                str = $"Did {abilityInfo.Dmg} damage for {abilityInfo.Cost} AP.";
                break;

            case UctActionType.AttackMove:
                str = $"Moved towards enemy for {moveCost} AP and did {abilityInfo.Dmg} damage for {abilityInfo.Cost} AP.";
                break;

            case UctActionType.Move:
                str = $"Moved from {mob.MobInstance.Coord} to {action.Coord} for {moveCost} AP.";
                break;

            case UctActionType.DefensiveMove:
                str = $"Is trying to hide at {action.Coord} for {moveCost} AP.";
                break;

            case UctActionType.EndTurn:
                throw new InvalidOperationException("End turn shouldn't be logged.");

            case UctActionType.Null:
                throw new InvalidOperationException("Null action should never be logged.");

            default:
                throw new ArgumentException($"Invalid action type ${action.Type}", nameof(action));
            }

            return($"{string.Format("{0,3}", _actionIndex)}. {str}");
        }
Exemplo n.º 16
0
        /// <summary>
        /// Asnychronously run a given action, notifying all of the subscribers.
        /// </summary>
        public async Task SlowPlayAction(GameInstance game, UctAction action)
        {
            Debug.Assert(game == _gameInstance, "instance == _gameInstance");

            foreach (var subscriber in _subscribers)
            {
                subscriber.ActionApplied(action);
            }

            switch (action.Type)
            {
            case UctActionType.AbilityUse:
                await SlowBroadcastAction(action);

                break;

            case UctActionType.EndTurn:
                break;

            case UctActionType.AttackMove:
                GameInvariants.AssertValidMoveAction(_gameInstance, action);

                await SlowBroadcastAction(action.ToPureMove());
                await SlowBroadcastAction(action.ToPureAbilityUse());

                break;

            case UctActionType.DefensiveMove:
            case UctActionType.Move:
                GameInvariants.AssertValidMoveAction(_gameInstance, action);

                await SlowBroadcastAction(action.ToPureMove());

                break;

            case UctActionType.Null:
                break;
            }
        }
Exemplo n.º 17
0
        public async Task <int> SlowMainLoop(Func <bool> turnEndFunc, Action gameFinishedFunc)
        {
            // Wait for GUI initialization
            await Task.Delay(TimeSpan.FromSeconds(1));

            State = GameEventState.SettingUpTurn;

            var state = _gameInstance.State;

            _gameInstance.Reset();

            int totalTurns = 0;

            state.SlowUpdateIsFinished(_gameInstance.MobManager);

            while (!_gameInstance.IsFinished)
            {
                while (IsPaused)
                {
                    await Task.Delay(TimeSpan.FromMilliseconds(100));
                }

                totalTurns++;

                await _gameInstance.CurrentController.SlowPlayTurn(this);

                ActionEvaluator.FNoCopy(_gameInstance, UctAction.EndTurnAction());

                turnEndFunc();
                await Task.Delay(200);
            }

            ReplayRecorder.Instance.SaveAndClear(_gameInstance);
            Console.WriteLine(Constants.GetLogBuffer());

            gameFinishedFunc();

            return(totalTurns);
        }
Exemplo n.º 18
0
        public static void AssertValidAbilityUseAction(GameInstance game, UctAction action)
        {
            var mobInstance    = game.State.MobInstances[action.MobId];
            var targetInstance = game.State.MobInstances[action.TargetId];
            var abilityInfo    = game.MobManager.Abilities[action.AbilityId];

            AssertAndRecord(game, action, game.State.Cooldowns[action.AbilityId] == 0,
                            "game.State.Cooldowns[action.AbilityId] == 0");

            AssertAndRecord(game, action, mobInstance.Ap >= abilityInfo.Cost, "mobInstance.Ap >= abilityInfo.Cost");
            AssertAndRecord(game, action, mobInstance.Hp > 0, $"Using an ability with {mobInstance.Hp}HP");
            AssertAndRecord(game, action, targetInstance.Hp > 0,
                            $"Using an ability on a target with {mobInstance.Hp}HP");

            var isVisible = game.Map.IsVisible(mobInstance.Coord, targetInstance.Coord);

            AssertAndRecord(game, action, isVisible, "Target is not visible");

            int distance = mobInstance.Coord.Distance(targetInstance.Coord);

            AssertAndRecord(game, action, abilityInfo.Range >= distance,
                            "abilityInfo.Range >= mobInstance.Coord.Distance(targetInstance.Coord)");
        }
Exemplo n.º 19
0
        public void Log(TeamColor currentTeam, UctAction action, CachedMob mob, CachedMob target,
                        AbilityInfo abilityInfo, int?moveCost)
        {
            GameManager.CurrentSynchronizationContext.Post(_ => {
                var entry = new HistoryLogEntry(ActionCount++,
                                                currentTeam,
                                                action,
                                                mob,
                                                target,
                                                abilityInfo,
                                                moveCost,
                                                _assetManager);

                _log.Add(entry);
                _childrenPlaceholder.AddChild(entry);

                if (_log.Count > MaxHistorySize)
                {
                    _log.RemoveAt(0);
                    _childrenPlaceholder.Children.RemoveAt(0);
                }
            }, null);
        }
Exemplo n.º 20
0
        public void ActionApplied(UctAction action)
        {
            var mob    = _game.CachedMob(action.MobId);
            var target = _game.CachedMob(action.TargetId);

            AbilityInfo abilityInfo = null;

            if (action.Type == UctActionType.AttackMove || action.Type == UctActionType.AbilityUse)
            {
                abilityInfo = _game.MobManager.Abilities[action.AbilityId];
            }

            int?moveCost = null;

            if (action.Type == UctActionType.AttackMove || action.Type == UctActionType.DefensiveMove ||
                action.Type == UctActionType.Move)
            {
                moveCost = _game.Pathfinder.Distance(mob.MobInstance.Coord, action.Coord);
            }

            Debug.Assert(_game.CurrentTeam != null, "_gameInstance.CurrentTeam != null");

            HistoryLog.Instance.Log(_game.CurrentTeam.Value, action, mob, target, abilityInfo, moveCost);
        }
Exemplo n.º 21
0
 public static GameInstance F(GameInstance state, UctAction action)
 {
     return(FNoCopy(state.CopyStateOnly(), action));
 }
Exemplo n.º 22
0
 public void FastPlayAction(UctAction action)
 {
     ActionEvaluator.FNoCopy(_gameInstance, action);
 }
Exemplo n.º 23
0
        private async Task SlowBroadcastAction(UctAction action)
        {
            await Task.WhenAll(_subscribers.Select(x => x.SlowActionApplied(action)));

            ActionEvaluator.FNoCopy(_gameInstance, action);
        }
Exemplo n.º 24
0
        private void HandleLeftClick()
        {
            var abilitySelected = SelectedAbilityIndex.HasValue;

            var mouseHex   = Camera2D.Instance.MouseHex;
            var currentMob = _game.CurrentMob;

            if (_game.Pathfinder.IsValidCoord(mouseHex))
            {
                var targetId = _game.State.AtCoord(mouseHex, true);
                if (targetId != null)
                {
                    if (targetId == currentMob)
                    {
                        ShowMessage("You can't target yourself.");
                    }
                    else
                    {
                        var mobInfo        = _game.MobManager.MobInfos[currentMob.Value];
                        var targetInstance = _game.State.MobInstances[targetId.Value];
                        var targetInfo     = _game.MobManager.MobInfos[targetId.Value];

                        if (targetInstance.Hp == 0)
                        {
                            ShowMessage("This mob is already dead.");
                        }
                        else
                        {
                            if (mobInfo.Team == targetInfo.Team)
                            {
                                ShowMessage("You can't target your team.");
                            }
                            else if (SelectedAbilityIndex.HasValue)
                            {
                                if (abilitySelected)
                                {
                                    AttackMob(targetId.Value);
                                }
                                else
                                {
                                    ShowMessage("You can't move here.");
                                }
                            }
                        }
                    }
                }
                else
                {
                    if (abilitySelected)
                    {
                        ShowMessage("You can't cast spells on the ground.");
                    }
                    else
                    {
                        var mobInstance = _game.State.MobInstances[currentMob.Value];

                        if (_game.Map[mouseHex] == HexType.Empty)
                        {
                            var distance = _game.Pathfinder.Distance(mobInstance.Coord, mouseHex);

                            if (distance == int.MaxValue)
                            {
                                ShowMessage("Target is unreachable");
                            }
                            else if (distance > mobInstance.Ap)
                            {
                                ShowMessage("You don't have enough AP.");
                            }
                            else
                            {
                                InputManager.Instance.UserInputEnabled = false;
                                _eventHub.SlowPlayAction(_game, UctAction.MoveAction(currentMob.Value, mouseHex))
                                .ContinueWith(t => { InputManager.Instance.UserInputEnabled = true; })
                                .LogContinuation();
                            }
                        }
                        else
                        {
                            ShowMessage("You can't walk into a wall.");
                        }
                    }
                }
            }
        }