/// <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)));
        }