/// <summary> /// Calls each move to make decision what to do (next move) /// </summary> public override Command WhatToDo(Board board) { var me = board.GetMe(); if (Static.TurnsWithoutAim == Constants.MaxTurnCountWithoutAim) { Static.TurnsWithoutAim = 0; return(Command.Reset()); } if (board.GetExits().Contains(me)) { return(Command.DoNothing()); } if (!board.IsMeAlive()) { HandleDie(); return(Command.DoNothing()); } if (Static.PerkCooldownDeathRay > 0) { Static.PerkCooldownDeathRay--; } if (Static.PerkCooldownUnlimitedFire > 0) { Static.PerkCooldownUnlimitedFire--; } if (Static.PerkCooldownUnstopableLaser > 0) { Static.PerkCooldownUnstopableLaser--; } foreach (var point in board.GetStepBarriers(PrevBoard)) { board.AddOnLayer4(point.X, point.Y, 's'); } foreach (var point in board.GetJumpBarriers(PrevBoard)) { board.AddOnLayer5(point.X, point.Y, 'j'); } if (board.IsAt(me, Element.ROBO_FLYING)) { if (prevBestPath != null) { foreach (var pathPoint in prevBestPath) { board.AddOnLayer4(pathPoint.X, pathPoint.Y, 't'); } board.AddOnLayer4(prevBestPath.Last().X, prevBestPath.Last().Y, 'a'); } return(Command.DoNothing()); } //Check that fire is not danger and gun is ready if (CanFire(board, me)) { //Try to use Death Ray perk if (Static.PerkCooldownDeathRay > 0) { if (board.GetOtherHeroes().Any(hero => hero.Y == me.Y && hero.X > me.X && hero.GetLengthTo(me) < Constants.DeathRayLength) || board.GetZombies().Any(hero => hero.Y == me.Y && hero.X > me.X && hero.GetLengthTo(me) < Constants.DeathRayLength)) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Right)); } if (board.GetOtherHeroes().Any(hero => hero.Y == me.Y && hero.X < me.X && hero.GetLengthTo(me) < Constants.DeathRayLength) || board.GetZombies().Any(hero => hero.Y == me.Y && hero.X < me.X && hero.GetLengthTo(me) < Constants.DeathRayLength)) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Left)); } if (board.GetOtherHeroes().Any(hero => hero.X == me.X && hero.Y < me.Y && hero.GetLengthTo(me) < Constants.DeathRayLength) || board.GetZombies().Any(hero => hero.X == me.X && hero.Y < me.Y && hero.GetLengthTo(me) < Constants.DeathRayLength)) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Up)); } if (board.GetOtherHeroes().Any(hero => hero.X == me.X && hero.Y > me.Y && hero.GetLengthTo(me) < Constants.DeathRayLength) || board.GetZombies().Any(hero => hero.X == me.X && hero.Y > me.Y && hero.GetLengthTo(me) < Constants.DeathRayLength)) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Down)); } } if (ShouldFireToLeft()) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Left)); } if (ShouldFireToRight()) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Right)); } if (ShouldFireToTop()) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Up)); } if (ShouldFireToBottom()) { board.AddOnLayer2(me.X, me.Y, '~'); return(Command.Fire(Direction.Down)); } } Static.CanExit = false; //Priority 1 aims: Corners of the full map (map new areas discovering) List <Point> bestPath = GetTheNearestToHero(GetCornersAims()); //Not discover new arias if level is not final (22) and exist already visible if (board.CurrentLevel < 22 && GetTheNearestToHero(GetExitAims()) != null) { bestPath = null; } //Strategy choice: Farm on the start or collect gold and go to exit if (GetTheNearestToHero(GetGoldAims()) != null || goldCollected > 0) { Static.Farm = 0; } else if (board.GetOtherHeroes().Any()) { Static.Farm = 1; } //Kill other heroes on the start if no gold nearly if (Static.Farm == 1) { bestPath = GetTheNearestToHero(GetFarmAims()); } //Go to nearest gold or perk if (bestPath == null) { var stuffAims = new List <Point>(); stuffAims.AddRange(GetGoldAims()); stuffAims.AddRange(GetPerkAims()); bestPath = GetTheNearestToHero(stuffAims); } //Try to find exit if (bestPath == null) { Static.CanExit = true; //Exit is allowed there are no other aims bestPath = GetTheNearestToHero(GetExitAims()); if (bestPath != null) { Static.IsExitOpen = true; boxesMoved = 0; } } if (bestPath == null) { Static.IsExitOpen = false; } //If all map is discovered and no path to exit - try to move boxes that is nearest to exit if (bestPath == null && boxesMoved <= 5) { var boxToPull = GetTheNearestToExit(GetBoxAims()); if (boxToPull != null) { bestPath = boxToPull.Value.Item1; if (bestPath.Count == 1) { boxesMoved++; return(Command.Pull(boxToPull.Value.Item2)); } } } //If still no exist after boxes move - kill everything if (bestPath == null) { var heroAims = new List <Point>(); heroAims.AddRange(GetAfkAims()); heroAims.AddRange(GetHeroesAims()); heroAims.AddRange(GetZombieAims()); bestPath = GetTheNearestToHero(heroAims); } if (bestPath == null) { Static.TurnsWithoutAim++; return(Command.DoNothing()); } else { Static.TurnsWithoutAim = 0; } bestPath = bestPath.Select(x => x.AbsoluteToRelative(board.Size, board.Offset)).ToList(); prevBestPath = bestPath; //Show best path on the board foreach (var pathPoint in bestPath) { board.AddOnLayer4(pathPoint.X, pathPoint.Y, 't'); var absolute = pathPoint.RelativeToAbsolute(board.Size, board.Offset); FullBoard.AddOnLayer4(absolute.X, absolute.Y, 't'); } board.AddOnLayer4(bestPath.Last().X, bestPath.Last().Y, 'a'); var a = bestPath.Last().RelativeToAbsolute(board.Size, board.Offset); FullBoard.AddOnLayer4(a.X, a.Y, 'a'); var nextPosition = bestPath[1]; if (board.IsAt(nextPosition, Element.GOLD)) { goldCollected++; } if (board.IsAt(nextPosition, Element.EXIT)) { goldCollected = 0; } if (board.IsAt(nextPosition, Element.DEATH_RAY_PERK)) { Static.PerkCooldownDeathRay = 10; } if (board.IsAt(nextPosition, Element.UNLIMITED_FIRE_PERK)) { Static.PerkCooldownUnlimitedFire = 10; } if (board.IsAt(nextPosition, Element.UNSTOPPABLE_LASER_PERK)) { Static.PerkCooldownUnstopableLaser = 10; } if (me.GetLengthTo(nextPosition) == 1) { return(Command.Go(GetDirection(me, nextPosition))); } return(Command.Jump(GetDirection(me, nextPosition))); }