/// <summary>
        /// Fires at target.
        /// </summary>
        /// <param name="location">The current location.</param>
        /// <param name="target">The closest target.</param>
        /// <param name="direction">The direction.</param>
        private void FireAtTarget(Point location, EnemyData target)
        {
            var absBearing = target.BearingRadians + this.HeadingRadians;
            int direction = (Math.Sin(target.HeadingRadians - absBearing) * target.Velocity < 0) ? -1 : 1;

            var distance = Point.Distance(location, target.Location);
            double power = GetFirePower(distance);

            var fieldArea = GetFieldArea(target.Location);
            var distanceBucket = (int)(distance / 100);

            var lastBullet = target.LastBullet;

            // initialize it to be in the middle, guessfactor 0.
            int bestindex = guessFactors / 2;

            var stats = this.statistics.GetStatistics(target.Name);
            var bestStats = stats.SegmentedTargeting.Where(x => x.DistanceBucket == distanceBucket && x.FieldAreaBucket == fieldArea).OrderByDescending(x => x.Value).FirstOrDefault();

            if (bestStats != null)
            {
                bestindex = bestStats.GuessFactorBucket;
            }

            // this should do the opposite of the math in the WaveBullet
            double guessfactor = (double)(bestindex - (guessFactors - 1) / 2) / ((guessFactors - 1) / 2);
            double angleOffset = direction * guessfactor * lastBullet.MaxEscapeAngle();
            double gunAdjust = Utils.NormalRelativeAngle(lastBullet.StartBearing - this.GunHeadingRadians + angleOffset);

            this.SetTurnGunRightRadians(gunAdjust);

            if (this.GunHeat == 0 && gunAdjust < Math.Atan2(9, distance))
            {
                this.SetFireBullet(power);
            }
        }
        /// <summary>
        /// Gets the move target using radius sampling method
        /// </summary>
        /// <param name="location">The current location.</param>
        /// <param name="closestTarget">The closest target.</param>
        /// <param name="enemyLocations">Enemy locations.</param>
        /// <param name="angleChange">if set to <c>true</c>, a significant change of move angle has occured.</param>
        /// <returns></returns>
        private double GetRadiusSamplingMoveTarget(Point location, EnemyData closestTarget, List<Point> enemyLocations, out bool angleChange)
        {
            var potentialMoveTargets = GetPotentialMoveTargets(this.moveTargetSampleSize, location, enemyLocations, this.defaultDistance, this.maximumDistance, this.BattleFieldWidth, this.BattleFieldHeight);

            // move towards the closest target
            var moveTarget = potentialMoveTargets.OrderByDescending(x => Point.Distance(x, closestTarget.Location)).First();
            var angle = Math.Atan2(moveTarget.X - location.X, moveTarget.Y - location.Y);

            // not important if using this move method
            angleChange = false;
            return angle;
        }
        /// <summary>
        /// Handle the scan event.
        /// 
        /// Predict whether the enemy has fired.
        /// Fire a wave bullet atth
        /// </summary>
        /// <param name="evnt"></param>
        /// <inheritdoc/>
        public override void OnScannedRobot(ScannedRobotEvent evnt)
        {
            var name = evnt.Name;
            var absBearing = evnt.BearingRadians + this.HeadingRadians;
            int direction = (Math.Sin(evnt.HeadingRadians - absBearing) * evnt.Velocity < 0) ? -1 : 1;

            // if fighting one-on-one, maintain radar lock
            if (this.GunHeat < 1.0 && this.Others == 1)
            {
                var turn = this.HeadingRadians + evnt.BearingRadians - this.RadarHeadingRadians;
                this.SetTurnRadarRightRadians(this.radarFactor * Utils.NormalRelativeAngle(turn));
            }

            // get the updated enemy data snapshot
            var enemyData = new EnemyData()
            {
                Name = name,
                Location = new Point()
                {
                    X = this.X + Math.Sin(absBearing) * evnt.Distance,
                    Y = this.Y + Math.Cos(absBearing) * evnt.Distance
                },
                Time = evnt.Time,
                Energy = evnt.Energy,
                HeadingRadians = evnt.HeadingRadians,
                BearingRadians = evnt.BearingRadians,
                Velocity = evnt.Velocity
            };

            // predict whether the enemy has fired a bullet since last scan
            // skip this step if there are many robots left on the field to avoid noise
            if (this.Others <= 2)
            {
                if (enemies.ContainsKey(name))
                {
                    var energyDrop = enemies[name].Energy - enemyData.Energy;

                    if (energyDrop >= 0.1 && energyDrop <= 3)
                    {
                        this.enemyBullets.Add(new WaveBullet()
                        {
                            TargetName = this.Name,
                            StartPoint = enemyData.Location,
                            StartBearing = Utils.NormalRelativeAngle(Math.PI - absBearing),
                            Power = energyDrop,
                            Direction = direction,
                            Time = this.Time
                        });
                    }
                }
            }

            // update the enemy data
            this.enemies[name] = enemyData;

            // process targeting statistics
            var targetStatistics = this.statistics.GetStatistics(name);

            // add the enemy data to pattern history for pattern matching targeting
            //targetStatistics.PatternHistory.Add(enemyData);

            // fire a wave bullet at the enemy
            double power = GetFirePower(evnt.Distance);

            var location = new Point() { X = this.X, Y = this.Y };

            var waveBullet = new WaveBullet()
            {
                TargetName = name,
                StartPoint = location,
                StartBearing = absBearing,
                Power = power,
                Direction = direction,
                Time = this.Time
            };

            enemyData.LastBullet = waveBullet;
            targetStatistics.WaveBullets.Add(waveBullet);
        }