예제 #1
0
파일: PlayerBot.cs 프로젝트: qoter/GameBot
        private static Turn ExecuteFight(LevelView levelView)
        {
            var monsterInAttackRange = levelView.Monsters.First(m => levelView.Player.Location.IsInRange(m.Location, 1));
            var attackOffset         = monsterInAttackRange.Location - levelView.Player.Location;

            return(Turn.Attack(attackOffset));
        }
예제 #2
0
        public Turn Solve(LevelView level, Enviroment enviroment, out bool isAttack)
        {
            isAttack = false;
            if (level.Player.Health < MaxHp && level.HealthPacks.Any())
            {
                enviroment.EnemyMap.Multiplyer = 2;
                var map = Map.Sum(enviroment.TravelMap, enviroment.EnemyMap);

                foreach (var hp in level.HealthPacks.OrderBy(h => h.Location.Distance(level.Player.Location)))
                {
                    var path = map.FindPath(level.Player.Location, hp.Location);
                    if (path == null) //бывают ситуации, когда полуживой монстр закрывает на проход к аптечкам. Добиваем его (раз нет других вариантов)
                    {
                        if (level.Monsters.Any(m => m.Location.IsInRange(level.Player.Location, 1)))
                        {
                            isAttack = true;
                            return(Turn.Attack(level.Monsters.First(m => m.Location.IsInRange(level.Player.Location, 1)).Location - level.Player.Location));
                        }
                    }
                    else
                    {
                        return(Turn.Step(path[1] - path[0]));
                    }
                }
            }
            return(null);
        }
예제 #3
0
            public override Turn MakeTurn(LevelView levelView)
            {
                if (Bot.Health < panicHealth && levelView.HealthPacks.Any())
                {
                    GoToState(() => new StateHeal(Bot));
                    return(Bot.State.MakeTurn(levelView));
                }
                if (!levelView.Monsters.Any())
                {
                    GoToState(() => new StateIdle(Bot));
                    return(Bot.State.MakeTurn(levelView));
                }
                var nearbyMonster = levelView.Monsters.
                                    OrderBy(m => (m.Location - Bot.Location).Size()).
                                    ThenBy(m => m.Health).
                                    FirstOrDefault();

                if (nearbyMonster.HasValue && IsInAttackRange(Bot.Location, nearbyMonster.Location))
                {
                    return(Turn.Attack(nearbyMonster.Location - Bot.Location));
                }

                var path = Algorithm.BFS(levelView, location => location == nearbyMonster.Location);

                return(NextStep(levelView, path));
            }
예제 #4
0
 public Turn Solve(LevelView level, Enviroment enviroment, out bool isAttack)
 {
     isAttack = false;
     if (level.Monsters.Any(m => m.Location.IsInRange(level.Player.Location, 1)))
     {
         var monster = level.Monsters.Where(m => m.Location.IsInRange(level.Player.Location, 1)).OrderBy(m => m.Health).First();
         isAttack = true;
         return(Turn.Attack(monster.Location - level.Player.Location));
     }
     return(null);
 }
예제 #5
0
        public Turn Iteration(LevelView level, IMessageReporter messageReporter, out bool isAttack)
        {
            isAttack = false;
            var             monsterMap = new EnemyMap(level, 1);
            var             trapMap    = new TrapMap(level);
            var             travelMap  = Map.Sum(trapMap, WallMap);
            var             pathMap    = Map.Sum(monsterMap, travelMap);
            List <Location> path       = null;

            if (level.Player.Health < 50 && level.HealthPacks.Any())
            {
                path = pathMap.FindPath(level.Player.Location, level.HealthPacks.OrderBy(h => h.Location.Distance(level.Player.Location)).First().Location);
                messageReporter.ReportMessage("Healing");
            }
            else if (level.Monsters.Any(m => m.Location.IsInRange(level.Player.Location, 1)))
            {
                messageReporter.ReportMessage("Attack");
                isAttack = false;
                return(Turn.Attack(level.Monsters.First(m => m.Location.IsInRange(level.Player.Location, 1)).Location - level.Player.Location));
            }
            else if (level.Monsters.Any())
            {
                int i = 0;
                path = travelMap.FindPath(level.Player.Location, level
                                          .Monsters.OrderBy(h => h.Location.Distance(level.Player.Location)).First().Location);
                if (i > 10)
                {
                    return(Turn.None);
                }
                messageReporter.ReportMessage("Far attack");
            }
            else if (level.Player.Health < 100 && level.HealthPacks.Any())
            {
                messageReporter.ReportMessage("100 Healing");
                path = pathMap.FindPath(level.Player.Location, level.HealthPacks.OrderBy(h => h.Location.Distance(level.Player.Location)).First().Location);
            }
            else if (Math.Max(BestItem(level).AttackBonus, BestItem(level).DefenceBonus) > Math.Max(level.Player.TotalAttack - level.Player.Attack, level.Player.TotalDefence - level.Player.Defence))
            {
                path = pathMap.FindPath(level.Player.Location, BestItem(level).Location);
            }
            else
            {
                messageReporter.ReportMessage("Leave");
                var leaveMap = Map.Sum(travelMap, new BadObjectMap(level, (view, location) => level.Items.Any(i => i.Location.Equals(location)), view => level.Items.Select(i => i.Location), 1));
                path = leaveMap.FindPath(level.Player.Location, Exit);
            }
            if (path != null)
            {
                return(Turn.Step(path[1] - path[0]));
            }
            return(Turn.None);
        }
예제 #6
0
 private void FightForExit(IEnumerable <PawnView> localMonsters)
 {
     if (localMonsters.Any())
     {
         var offset = localMonsters.First().Location - Self.playerLocation;
         Self.selectedTurn = Turn.Attack(offset);
     }
     else if (Self.level.Monsters.Any())
     {
         Offset step = StepToMonsters();
         Self.selectedTurn = Turn.Step(step);
     }
 }
예제 #7
0
        private Turn SearchMonstersAround()
        {
            if (panicHealthValue > 50)
            {
                panicHealthValue = 50;
            }

            var nearbyMonsters = levelView.Monsters
                                 .Where(m => m.Location.IsInRange(levelView.Player.Location, 1))
                                 .Select(m => new MonsterFightInfo(m, levelView.Player));

            if (nearbyMonsters.Count() == 0)
            {
                return(Turn.None);
            }
            else if (nearbyMonsters.Count() == 1)
            {
                var monster = nearbyMonsters.Single();
                if (monster.IsSaveToKill && levelView.Player.Health > panicHealthValue)
                {
                    messageReporter.ReportMessage("-----Monster Health: " + monster.Info.Health);
                    return(Turn.Attack(monster.Info.Location - levelView.Player.Location));
                }
                else
                {
                    return(Escape());
                }
            }
            else if (nearbyMonsters.Count() == 2)
            {
                var totalDamage = nearbyMonsters.Sum(m => m.DamageToSlave);
                var saveToKill  = nearbyMonsters
                                  .OrderBy(m => m.HitsToDeath)
                                  .Where(m => (m.HitsToDeath + 4 < levelView.Player.Health / totalDamage) || (levelView.Player.Health >= panicHealthValue * lvl && levelView.Player.Health > totalDamage))
                                  .FirstOrDefault();

                if (saveToKill != default(MonsterFightInfo))
                {
                    return(Turn.Attack(saveToKill.Info.Location - levelView.Player.Location));
                }
                else
                {
                    return(Escape());
                }
            }
            else
            {
                return(Escape());
            }
        }
예제 #8
0
        public Turn MakeTurn(LevelView levelView, IMessageReporter messageReporter)
        {
            if (Ai == null || !levelView.Field.GetCellsOfType(CellType.Exit).First().Equals(Ai.Exit) || MonsterCount < levelView.Monsters.Count())
            {
                LevelIndex++;
                if (IsLastLevel(levelView))
                {
                    Ai = new ArenaDestroyerAi(levelView);
                }
                else if (AiFactories.ContainsKey(LevelIndex))
                {
                    Ai = AiFactories[LevelIndex].CreateBot(levelView, LevelIndex);
                }
                else
                {
                    Ai = AiFactories[AiFactories.Keys.OrderBy(k => Math.Abs(k - LevelIndex)).First()].CreateBot(levelView, LevelIndex);
                }
                history = new Queue <Location>(historySize);
            }
            MonsterCount = levelView.Monsters.Count();

            var isAttack = false;
            var action   = Ai.Iteration(levelView, messageReporter, out isAttack);

            if (!isAttack)
            {
                history.Enqueue(levelView.Player.Location);
                if (history.Count > historySize)
                {
                    history.Dequeue();
                    if (new HashSet <Location>(history).Count < (historySize * Ai.CriticalPercentageInactivity / 100))
                    {
                        messageReporter.ReportMessage("T");
                        history.Clear();
                        if (levelView.Monsters.Any(m => m.Location.IsInRange(levelView.Player.Location, 1)))
                        {
                            messageReporter.ReportMessage("A");
                            return(Turn.Attack(levelView.Monsters.First(m => m.Location.IsInRange(levelView.Player.Location, 1)).Location - levelView.Player.Location));
                        }
                        var solve = Ai.HandleCycle(levelView);
                        if (solve != null)
                        {
                            return(solve);
                        }
                        return(Turn.Step((StepDirection) new Random().Next(0, 4)));
                    }
                }
            }
            return(action);
        }
예제 #9
0
        public override void Tick()
        {
            var attackRoute = Self.pathFinder.FindPath(Self.targetMonster.Location);

            if (attackRoute.Count == 0)
            {
                GoToState(() => new StateEscape(Self));
                return;
            }

            var monsters = MonstersInRange(attackRoute.Last());

            if (monsters.Count() > 1)
            {
                GoToState(() => new StateEscape(Self));
                return;
            }

            if (FightDecideFunction(Self.targetMonster))
            {
                if (Self.IsInAttackRange(Self.targetMonster))
                {
                    var attackOffset = Self.targetMonster.Location - Self.playerLocation;
                    Self.selectedTurn = Turn.Attack(attackOffset);
                    return;
                }

                if (Offset.StepOffsets.Any(o => Self.level.GetItemAt(Self.playerLocation + o).HasValue))
                {
                    var item = Self.level.Items
                               .Where(i => Offset.StepOffsets
                                      .Any(o => i.Location == Self.playerLocation + o))
                               .OrderByDescending(i => PlayerBot.ItemValue(i))
                               .First();
                    if (PlayerBot.ItemValue(item) > PlayerBot.ItemValue(Self.equippedItem))
                    {
                        var itemStep = item.Location - Self.playerLocation;

                        Self.selectedTurn = Turn.Step(itemStep);
                        return;
                    }
                }
                var attackStep = (attackRoute.First() - Self.playerLocation).SnapToStep();
                Self.selectedTurn = Turn.Step(attackStep);
                return;
            }

            GoToState(() => new StateEscape(Self));
        }
예제 #10
0
        public Turn Solve(LevelView level, Enviroment enviroment, out bool isAttack)
        {
            isAttack = false;
            //если монстры атакуют более чем двумя - убегаем на другой конец карты
            if (level.Monsters.Count(m => m.Location.IsInRange(level.Player.Location, 1)) > 1 && level.Monsters.Count() > 2)
            {
                enviroment.EnemyMap.Multiplyer = 2;
                var map = Map.Sum(enviroment.TravelMap, enviroment.EnemyMap);
                var spot = new[] { enviroment.Exit, enviroment.Start }.OrderByDescending(s => s.Distance(level.Player.Location)).First();
                var target = spot.Near().Where(p => enviroment.TravelMap.IsTravaible(p)).OrderBy(p => p.Distance(level.Player.Location)).First(); //эта клетка вроде всегда свободна
                var near   =
                    level.Player.Location.Near()
                    .Where(p => map.IsTravaible(p) && enviroment.WallMap.GetWeight(p) < 2)
                    .OrderBy(p => level.Monsters.Count(m => m.Location.IsInRange(p, 1)));

                foreach (var location in near)//new
                {
                    if (level.Monsters.Count(m => m.Location.IsInRange(location, 1)) > 0)
                    {
                        break;
                    }
                    var p = map.FindPath(level.Player.Location, target);
                    if (p != null && p.Count > 1)
                    {
                        return(Turn.Step(p[1] - p[0]));
                    }
                }

                var path = map.FindPath(level.Player.Location, target);
                if (path == null)
                {
                    if (level.Monsters.Any(m => m.Location.IsInRange(level.Player.Location, 1)))
                    {
                        isAttack = true;
                        return
                            (Turn.Attack(
                                 level.Monsters.First(m => m.Location.IsInRange(level.Player.Location, 1)).Location -
                                 level.Player.Location));
                    }
                    else
                    {
                        return(Turn.None);
                    }
                }
                return(Turn.Step(path[1] - path[0]));
            }
            return(null);
        }
예제 #11
0
        private Turn Attack(LevelView levelView, PawnView monster)
        {
            if (monster.HasValue)
            {
                return(Turn.Attack(monster.Location - levelView.Player.Location));
            }

            var nearbyMonster = GetNearbyMonster(levelView, monster.Location);

            if (nearbyMonster.HasValue)
            {
                return(Turn.Attack(nearbyMonster.Location - levelView.Player.Location));
            }

            return(null);
        }
예제 #12
0
        private Turn MakeYourselfStronger()
        {
            messageReporter.ReportMessage("-----MakeYourselfStronger-----");
            var closestMonster = CheckOnAvailableExperience();

            Turn turn;

            if (!isFinalRoom)
            {
                turn = SearchMonstersAround();
                if (turn != Turn.None)
                {
                    return(turn);
                }
            }
            turn = CheckEquipAndExp();
            if (turn != Turn.None)
            {
                return(turn);
            }

            if (closestMonster != default(MonsterFightInfo))
            {
                if (levelView.Player.Location.IsInRange(closestMonster.Info.Location, 1))
                {
                    // на финального босса
                    if (levelView.Player.Health > 30)
                    {
                        return(Turn.Attack(closestMonster.Info.Location - levelView.Player.Location));
                    }
                    else
                    {
                        return(Escape());
                    }
                }
                else
                {
                    return(CreateMap(closestMonster.Info.Location, false));
                }
            }
            else
            {
                return(ObjectiveDoneOrImpossible());
            }
        }
예제 #13
0
        public Turn MakeTurn(LevelView levelView, IMessageReporter messageReporter)
        {
            messageReporter.ReportMessage("Hey ho! I'm still breathing");

            if (levelView.Random.NextDouble() < 0.1)
            {
                return(Turn.None);
            }

            var nearbyMonster = levelView.Monsters.FirstOrDefault(m => IsInAttackRange(levelView.Player.Location, m.Location));

            if (nearbyMonster.HasValue)
            {
                return(Turn.Attack(nearbyMonster.Location - levelView.Player.Location));
            }

            return(Turn.Step((StepDirection)levelView.Random.Next(4)));
        }
예제 #14
0
        private Turn GoHealYourself()
        {
            messageReporter.ReportMessage("-----GoHealYourself-----");
            // ежеходное обновление карты, чтобы быть совершенно точно уверенным в корректности данных, при хиле риск минимизируется
            map = new Map(ref levelView);
            var fruits       = levelView.HealthPacks.ToList();
            var closestFruit = GetClosestFruit(fruits);

            if (closestFruit.HasValue)
            {
                // перебор хилок, если ближайшая недоступна
                Turn turn = CreateMap(closestFruit.Location, true);
                while (turn == Turn.None || fruits.Count == 0)
                {
                    fruits.Remove(closestFruit);
                    turn = CreateMap(closestFruit.Location, true);
                }
                if (turn == Turn.None || fruits.Count == 0)
                {
                    var closestMonster = levelView.Monsters.Where(m => m.Location.IsInRange(levelView.Player.Location, 1)).FirstOrDefault();
                    if (closestMonster.HasValue)
                    {
                        return(Turn.Attack(closestMonster.Location - levelView.Player.Location));
                    }
                    else
                    {
                        return(CreateMap(levelView.Field.GetCellsOfType(CellType.Exit).Single(), false));
                    }
                }
                else
                {
                    return(turn);
                }
            }
            else
            {
                return(ObjectiveDoneOrImpossible());
            }
        }
예제 #15
0
 public override void Tick()
 {
     if (objectiveRoute.Count == 0)
     {
         if (Self.level.Monsters.Any(Self.IsInAttackRange))
         {
             var attackOffset = Self.level.Monsters
                                .Where(Self.IsInAttackRange)
                                .OrderBy(m => m.Health)
                                .ThenBy(m => m.Attack)
                                .ThenBy(m => m.Defence)
                                .First()
                                .Location - Self.playerLocation;
             Self.selectedTurn = Turn.Attack(attackOffset);
         }
     }
     else
     {
         var objectiveStep = (objectiveRoute.First() - Self.playerLocation).SnapToStep();
         Self.selectedTurn = Turn.Step(objectiveStep);
     }
 }
예제 #16
0
        //идем туда, куда будет проложен маршрут по карте
        public Turn AutomaticStep(Map map, Location target, LevelView level, out bool isAttack)
        {
            isAttack = false;
            var path = map.FindPath(level.Player.Location, target);

            if (path == null)
            {
                if (level.Monsters.Any(m => m.Location.IsInRange(level.Player.Location, 1)))
                {
                    isAttack = true;
                    return
                        (Turn.Attack(
                             level.Monsters.First(m => m.Location.IsInRange(level.Player.Location, 1)).Location -
                             level.Player.Location));
                }
                else
                {
                    return(Turn.None);
                }
            }
            return(Turn.Step(path[1] - path[0]));
        }
예제 #17
0
        public Turn Iteration(LevelView level, IMessageReporter reporter, out bool isAttack)
        {
            Enviroment.Update(level, 3);
            var bonusIgnore = new BadObjectMap(level, (view, location) => level.Items.Any(i => i.Location.Equals(location)), view => level.Items.Select(i => i.Location), 1);
            var attackMap   = Map.Sum(Enviroment.WallMap, Enviroment.TrapMap, bonusIgnore);
            var travelMap   = Map.Sum(attackMap, Enviroment.EnemyMap, bonusIgnore);

            if (level.Monsters.Any())
            {
                var monster        = level.Monsters.First();
                var enemyHp        = monster.Health;
                var healingHpLevel = 50;
                if (enemyHp < MonsterStartHp * 0.6) //если враг пытается отрегениться - забираем его аптечку))
                {
                    healingHpLevel = 60;
                }
                if (level.Player.Health < healingHpLevel && level.HealthPacks.Any())
                {
                    var path = travelMap.FindPath(level.Player.Location,
                                                  level.HealthPacks.OrderBy(h => h.Location.Distance(level.Player.Location)).First().Location);
                    isAttack = false;
                    if (path != null && path.Count > 1)
                    {
                        return(Turn.Step(path[1] - path[0]));
                    }
                    return(Turn.None);
                }
            }

            if (level.Monsters.Any(m => m.Location.IsInRange(level.Player.Location, 1)))
            {
                var monster = level.Monsters.Where(m => m.Location.IsInRange(level.Player.Location, 1)).OrderBy(m => m.Health).First();
                isAttack = true;
                return(Turn.Attack(monster.Location - level.Player.Location));
            }
            if (level.Monsters.Any())
            {
                var target  = level.Monsters.First().Location;
                var targets = target
                              .Near(3)
                              .Where(
                    p =>
                    p.X >= 0 && p.Y >= 0 && p.X < Enviroment.TravelMap.Width &&
                    p.Y < Enviroment.TravelMap.Height)
                              .Where(p => Enviroment.TravelMap.IsTravaible(p))
                              .OrderBy(p => p.Distance(target));

                foreach (var location in targets)
                {
                    var path = attackMap.FindPath(level.Player.Location, location);
                    isAttack = false;
                    if (path != null && path.Count > 1)
                    {
                        return(Turn.Step(path[1] - path[0]));
                    }
                }
            }
            if (!ExitIsClosed(level))
            {
                Enviroment = new Enviroment(level, 2);
                var path = travelMap.FindPath(level.Player.Location, Exit);
                isAttack = false;
                if (path == null || path.Count < 2)
                {
                    return(Turn.None);
                }
                return(Turn.Step(path[1] - path[0]));
            }
            isAttack = false;
            return(Turn.None);
        }
예제 #18
0
        public Turn MakeTurn(LevelView level, IMessageReporter messageReporter)
        {
            if (_hiddenYet == default(HashSet <Location>) ||
                level.Field[level.Player.Location] == CellType.PlayerStart)
            {
                _hiddenYet = new HashSet <Location>(level.Field.GetCellsOfType(CellType.Hidden));
            }

            _hiddenYet.IntersectWith(level.Field.GetCellsOfType(CellType.Hidden));

            if (_emptiesOnceWasVisible == default(HashSet <Location>) ||
                level.Field[level.Player.Location] == CellType.PlayerStart)
            {
                _emptiesOnceWasVisible = new HashSet <Location>(level.Field.GetCellsOfType(CellType.Empty));
            }

            _emptiesOnceWasVisible.UnionWith(level.Field.GetCellsOfType(CellType.Empty));
            _emptiesOnceWasVisible.UnionWith(level.Field.GetCellsOfType(CellType.Exit));
            _emptiesOnceWasVisible.UnionWith(level.Field.GetCellsOfType(CellType.PlayerStart));

            if (_exit == default(Location) ||
                level.Field[level.Player.Location] == CellType.PlayerStart)
            {
                _exit = level.Field.GetCellsOfType(CellType.Exit).SingleOrDefault();
            }

            if (level.Player.Health <= CriticalHealth && TryGetBestStepToHealth(level, out var locationToStep))
            {
                return(Turn.Step(locationToStep - level.Player.Location));
            }

            var attackRangeMonsters =
                level.Monsters.Where(x => x.Location.IsInRange(level.Player.Location, 1)).ToArray();

            if (attackRangeMonsters.Any())
            {
                if (attackRangeMonsters.Length == 1 && level.Player.Health >= CriticalHealth)
                {
                    return(Turn.Attack(
                               attackRangeMonsters
                               .Aggregate((result, current) => result.Health < current.Health ? result : current)
                               .Location - level.Player.Location));
                }

                if (TryGetBestStepAwayFromMonsters(level, out locationToStep))
                {
                    return(Turn.Step(locationToStep - level.Player.Location));
                }
            }

            if (level.Monsters.Any() && TryGetBestStepToAttack(level, out locationToStep))
            {
                return(Turn.Step(locationToStep - level.Player.Location));
            }

            level.Player.TryGetEquippedItem(out var item);

            if (level.Items.Any(x => x.AttackBonus > item.AttackBonus && x.DefenceBonus > item.DefenceBonus) &&
                TryGetBestStepToItem(level, out locationToStep))
            {
                return(Turn.Step(locationToStep - level.Player.Location));
            }

            return(Turn.Step(GetBestStepToExit(level) - level.Player.Location));
        }
예제 #19
0
        public Turn AskPlayerInput()
        {
            while (true)
            {
                var key = mouseDriver.WaitForInput();

                Console.CancelKeyPress += (sender, args) =>
                                          args.Cancel = true;

                switch (key.Key)
                {
                case ConsoleKey.Escape:
                    return(null);

                case ConsoleKey.LeftArrow:
                    MoveCursor(-1, 0);
                    break;

                case ConsoleKey.UpArrow:
                    MoveCursor(0, -1);
                    break;

                case ConsoleKey.RightArrow:
                    MoveCursor(1, 0);
                    break;

                case ConsoleKey.DownArrow:
                    MoveCursor(0, 1);
                    break;

                case ConsoleKey.A:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.West));
                    }
                    return(Turn.Step(StepDirection.West));

                case ConsoleKey.C:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.SouthEast));
                    }
                    break;

                case ConsoleKey.D:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.East));
                    }
                    return(Turn.Step(StepDirection.East));

                case ConsoleKey.E:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.NorthEast));
                    }
                    break;

                case ConsoleKey.Q:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.NorthWest));
                    }
                    break;

                case ConsoleKey.S:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.South));
                    }
                    return(Turn.Step(StepDirection.South));

                case ConsoleKey.W:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.North));
                    }
                    return(Turn.Step(StepDirection.North));

                case ConsoleKey.X:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.South));
                    }
                    break;

                case ConsoleKey.Z:
                    if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
                    {
                        return(Turn.Attack(AttackDirection.SouthWest));
                    }
                    break;

                case ConsoleKey.Spacebar:
                    return(Turn.None);

                case ConsoleKey.F1:
                    DisplayHelp();
                    break;
                }
            }
        }