public void WriteMoves(Move[] moves) { WriteEnum((sbyte?)MessageType.Moves); if (moves == null) { WriteInt(-1); } else { int moveCount = moves.Length; WriteInt(moveCount); for (int moveIndex = 0; moveIndex < moveCount; ++moveIndex) { Move move = moves[moveIndex]; if (move == null) { WriteBoolean(false); } else { WriteBoolean(true); WriteDouble(move.LeftTrackPower); WriteDouble(move.RightTrackPower); WriteDouble(move.TurretTurn); WriteEnum((sbyte?)move.FireType); } } } writer.Flush(); }
private void Fire(Tank self, World world, Move move) { double angleToTank = double.MaxValue; Tank selectedTank = null; foreach (Tank tank in world.Tanks) { if (tank.IsTeammate) continue; if (tank.CrewHealth < 1 || tank.HullDurability < 1) continue; double angle = self.GetTurretAngleTo(tank); if (Math.Abs(angle) < Math.Abs(angleToTank)) { angleToTank = angle; selectedTank = tank; } } if (selectedTank == null) return; Ray ray = new Ray(self.Id, self.X, self.Y, self.Angle + self.TurretRelativeAngle); Location expectedLocation = selectedTank.GetExpectedPositionForFire<Location>(self, world); double expectedAngle = self.GetTurretAngleTo(expectedLocation.X, expectedLocation.Y); double distance = self.GetDistanceTo(selectedTank); // if we can shoot enemy if (ray.IsCollide(selectedTank) && !selectedTank.IsCovered(ray, world)) { if (distance < self.Width) { move.FireType = FireType.PremiumPreferred; } else if (distance < 3.0d * self.Width && Math.Abs(expectedAngle) < 2.0d * Const.MIN_ANGLE) { move.FireType = FireType.PremiumPreferred; } else if (Math.Abs(expectedAngle) < Const.MIN_ANGLE) { move.FireType = FireType.Regular; } } if (expectedAngle > 0) { move.TurretTurn = self.TurretTurnSpeed; } else { move.TurretTurn = -self.TurretTurnSpeed; } }
public void run() { try { remoteProcessClient.WriteToken(token); int teamSize = remoteProcessClient.ReadTeamSize(); IStrategy[] strategies = new IStrategy[teamSize]; TankType[] tankTypes = new TankType[teamSize]; for (int strategyIndex = 0; strategyIndex < teamSize; ++strategyIndex) { IStrategy strategy = new MyStrategy(); strategies[strategyIndex] = strategy; tankTypes[strategyIndex] = strategy.SelectTank(strategyIndex, teamSize); } remoteProcessClient.WriteSelectedTanks(tankTypes); PlayerContext playerContext; while ((playerContext = remoteProcessClient.ReadPlayerContext()) != null) { Tank[] playerTanks = playerContext.Tanks; if (playerTanks.Length != teamSize) { break; } Move[] moves = new Move[teamSize]; for (int strategyIndex = 0; strategyIndex < teamSize; ++strategyIndex) { Move move = new Move(); moves[strategyIndex] = move; strategies[strategyIndex].Move(playerTanks[strategyIndex], playerContext.World, move); } remoteProcessClient.WriteMoves(moves); } } finally { remoteProcessClient.Close(); } }
private void MoveToBonus(Tank self, World world, Move move) { double distanceToBonus = double.MaxValue; Bonus selectedBonus = null; foreach (Bonus bonus in world.Bonuses) { double distance = self.GetDistanceTo(bonus); if (distance < distanceToBonus) { distanceToBonus = distance; selectedBonus = bonus; } } if (selectedBonus == null) return; double angle = self.GetAngleTo(selectedBonus); double absAngle = Math.Abs(angle); if (absAngle < Const.MIN_ANGLE) // move forward { move.LeftTrackPower = 1.0d; move.RightTrackPower = 1.0d; } else if (absAngle > Math.PI - Const.MIN_ANGLE) // move back { move.LeftTrackPower = -1.0d; move.RightTrackPower = -1.0d; } else if (absAngle > Const.HALF_PI - Const.MIN_ANGLE && absAngle < Const.HALF_PI + Const.MIN_ANGLE) // turn { move.LeftTrackPower = 1.0d; move.RightTrackPower = -1.0d; } else if (absAngle < Const.HALF_PI) { move.LeftTrackPower = 1.0d; move.RightTrackPower = 1.0d - absAngle * 2d; if (angle < 0.0d) { var tmp = move.LeftTrackPower; move.LeftTrackPower = move.RightTrackPower; move.RightTrackPower = tmp; } } else // if (absAngle > HALF_PI) { move.LeftTrackPower = -1.0d; move.RightTrackPower = -1.0d - absAngle * 2d; if (angle < 0.0d) { var tmp = move.LeftTrackPower; move.LeftTrackPower = move.RightTrackPower; move.RightTrackPower = tmp; } } }
public void Move(Tank self, World world, Move move) { Fire(self, world, move); MoveToBonus(self, world, move); }
public void Move(Tank self, World world, Move move) { if (start == -1) { start = self.TeammateIndex == 0 ? 10 : 20; int cnt = 0; foreach (Tank t in world.Tanks) if (t.IsTeammate) cnt++; gameType = cnt - 1; } // определяю центральный прямоугольник x1 = world.Width * 0.25; x2 = world.Width - x1; y1 = world.Height * 0.25; y2 = world.Height - y1; rectX = new double[] { x1, x2, x2, x1 }; rectY = new double[] { y1, y1, y2, y2 }; this.world = world; this.move = move; int bonusId = SelectBonus(self); int selectedTank = world.Tanks.Length; if (bonusId != world.Bonuses.Length) { Go(self, world.Bonuses[bonusId].X, world.Bonuses[bonusId].Y); } else { double[] bestPos = FindBestPosition(self); Go(self, bestPos[0], bestPos[1]); } // теперь находим максимально удобную цель для стрельбы selectedTank = world.Tanks.Length; double maxK = 0; bool goalFinded = false; for (int i = 0; i < world.Tanks.Length; i++) { if (!world.Tanks[i].IsTeammate && IsAlive(world.Tanks[i]) && !Intersected(self, world.Tanks[i])) { double k = TurretCoeff(self, world.Tanks[i]); if (k > maxK) { maxK = k; selectedTank = i; goalFinded = true; } } } if (!goalFinded) { // если не нашли цель для стрельбы - ищем не обращая внимания на препятствия for (int i = 0; i < world.Tanks.Length; i++) { if (!world.Tanks[i].IsTeammate && IsAlive(world.Tanks[i])) { double k = TurretCoeff(self, world.Tanks[i]); if (k > maxK) { maxK = k; selectedTank = i; } } } } if (selectedTank == world.Tanks.Length) return; bool gogogo = false; if (world.Tick > 200) { // Проверяю что в меня могут попасть int check = CheckToBeWounded(self, 2); if (check != 0) { int c0 = CheckToBeWounded(self, 0); // Стоять на месте if (c0 == 0) { SetMove(0, 0); gogogo = true; } else { double speed = GetSpeed(self); int c1 = CheckToBeWounded(self, 1); // Вперёд double AngleBetweenSelfAndSpeed = self.Angle - Math.Atan2(self.SpeedY, self.SpeedX); // угол между скоростью и мной AngleBetweenSelfAndSpeed = NormAngle(AngleBetweenSelfAndSpeed); if (AngleBetweenSelfAndSpeed < 0) AngleBetweenSelfAndSpeed = -AngleBetweenSelfAndSpeed; if (c1 == 0 && (speed < 0.15 || AngleBetweenSelfAndSpeed < Angle[90])) { SetMove(1, 1); gogogo = true; } else { int c2 = CheckToBeWounded(self, -1); // Назад if (c2 == 0) { SetMove(-1, -1); gogogo = true; } else { if (DistanseToBorder(self) < self.Width) { if (!OutOfRange(FictiveTank(self.X + 20 * Math.Cos(self.Angle), self.Y + 20 * Math.Sin(self.Angle), 3452343), 0.85)) SetMove(1, 1); else SetMove(-1, -1); gogogo = true; } // Если приходится ставиться под рикошет else if (c1 == 2 || c2 == 2) { SetMove(1, -1); gogogo = true; } } } } } } /* // Поиск тех кто направил на меня пушку int fireTo = -1; double mindist = 10000; for (int i = 0; i < world.Tanks.Length; i++) { if (!world.Tanks[i].IsTeammate && IsAlive(world.Tanks[i])) { double angle = world.Tanks[i].GetTurretAngleTo(self); if (Math.Abs(angle) < Angle[5]) { double d = self.GetDistanceTo(world.Tanks[i]); if (d < mindist) { mindist = d; fireTo = i; } } } } if (fireTo != -1 && self.GetDistanceTo(world.Tanks[fireTo]) < self.Width * 5) { selectedTank = fireTo; goalFinded = true; }*/ if (!gogogo && CountAlive() == 2 && bonusId != world.Bonuses.Length) { // Поиск тех кто направил пушку и стоит перпендикулярно мне for (int i = 0; i < world.Tanks.Length; i++) { if (!world.Tanks[i].IsTeammate && IsAlive(world.Tanks[i])) { double AngleBetweenSelfAndHisTurret = Math.Abs(NormAngle(self.Angle - GetTurretAngle(world.Tanks[i]))); if (AngleBetweenSelfAndHisTurret > Angle[90]) AngleBetweenSelfAndHisTurret = Angle[180] - AngleBetweenSelfAndHisTurret; // если он под углом меньше 30 if (AngleBetweenSelfAndHisTurret < Angle[30] && world.Tanks[i].GetTurretAngleTo(self) < Angle[20]) { // Поворачиваемся перпендикулярно и отъезжаем double an1 = self.Angle + Angle[90]; double an2 = self.Angle - Angle[90]; double X1 = self.X + 300 * Math.Cos(an1); double Y1 = self.Y + 300 * Math.Sin(an1); double X2 = self.X + 300 * Math.Cos(an2); double Y2 = self.Y + 300 * Math.Sin(an2); if (!OutOfRange(X1, Y1)) { Go(self, X1, Y1); /*xGoAway = X1; yGoAway = Y1; goAway = 50;*/ } else if (!OutOfRange(X2, Y2)) { Go(self, x2, y2); /*xGoAway = X2; yGoAway = Y2; goAway = 50;*/ } } } } } if (End()) { foreach (Tank t in world.Tanks) { if (!t.IsTeammate && IsAlive(t)) { Go(self, t.X, t.Y); break; } } } double Dist = self.GetDistanceTo(world.Tanks[selectedTank]); move.TurretTurn = self.GetTurretAngleTo(world.Tanks[selectedTank]); if (goalFinded && Hit(self, world.Tanks[selectedTank])) { double angle = Math.Abs(NormAngle(world.Tanks[selectedTank].Angle - NormAngle(self.GetTurretAngleTo(world.Tanks[selectedTank]) + self.Angle + self.TurretRelativeAngle))); if (angle > Angle[90]) angle = Angle[180] - angle; if (!(angle > Angle[60] && Dist > world.Height * 0.7) || noFire > 300) { noFire = 0; if (Dist < world.Width / 2 || (Dist < world.Height && angle < Angle[20]) || world.Tick > 4500) move.FireType = FireType.PremiumPreferred; else move.FireType = FireType.Regular; } else { noFire++; } } if (world.Tick < 200) { if (!selectedPoint) { double minDist = 10000; minX = 10000; minY = 10000; for (double x = world.Width * 0.03; x < world.Width; x += world.Width * 0.94) { for (double y = world.Height * 0.03; y < world.Height; y += world.Height * 0.94) { double d = self.GetDistanceTo(x, y); if (d < minDist) { minDist = d; minX = x; minY = y; } } } selectedPoint = true; } Go(self, minX, minY); } if (world.Tick < start) { move.FireType = FireType.None; } }
//public static void Set() //{ // Time = Stopwatch.ElapsedTicks; //} //public static void Lap(string comment) //{ // Console.WriteLine(comment + ": " + (Stopwatch.ElapsedTicks - Time)); // Set(); //} public void Move(Tank self, World world, Move move) { Self = self; SelfLocation = new Point(Self.X, Self.Y); World = world; AnglesRegular.Clear(); AnglesPremium.Clear(); //for (int i = 0; i < _lol; ++i) //{ // i += 1; // i -= 1; //} //Point tmpIntersection; //var t00 = Mathematics.DoSegmentsIntersect(new Point(10, 10), new Point(110, 15), new Point(60, 50), new Point(60, 0), out tmpIntersection); //return; //var t00 = Mathematics.Newton(x => x * x, x => 2 * x, 2, 0.00000001); // 1.41421356237 //var t01 = Mathematics.Newton(x => x * x * x, x => 3 * x * x, 2, 0.0000001); // 1.25992104989 //var tmpShellType = ShellType.Regular; //double tmpDistance = 0; //foreach (Tank tmpTank in world.Tanks) // if (tmpTank.PlayerName == "QuickStartGuy") // { // tmpDistance = Mathematics.Distance(new Point(Self.X, Self.Y), new Point(tmpTank.X, tmpTank.Y)) - 100; // break; // } //var t02 = Mathematics.Newton( // t => (MyStrategy.ShellProperties[tmpShellType].InitialSpeed * (Math.Exp(MyStrategy.ShellProperties[tmpShellType].SpeedPowerRatio * t) - 1)) / MyStrategy.ShellProperties[tmpShellType].SpeedPowerRatio, // integral of speed // t => MyStrategy.ShellProperties[tmpShellType].InitialSpeed * Math.Exp(MyStrategy.ShellProperties[tmpShellType].SpeedPowerRatio * t), // speed // tmpDistance, Settings.TickApproximationEpsilon); //return; //Set(); if (Tanks == null) { Tanks = new Dictionary<long, Tank>(); foreach (Tank tmpTank in world.Tanks) Tanks.Add(tmpTank.Id, tmpTank); TankPlus = new Dictionary<long, TankPlus>(); foreach (Tank tmpTank in world.Tanks) TankPlus.Add(tmpTank.Id, new TankPlus(tmpTank.Id)); //Bonuses = new Dictionary<long, Bonus>(); //BonusPlus = new Dictionary<long, BonusPlus>(); } else { foreach (Tank tmpTank in world.Tanks) Tanks[tmpTank.Id] = tmpTank; //List<long> tmpOutdatedBonuses = new List<long>(); //foreach (BonusPlus tmpBonusPlus in BonusPlus.Values) // if (tmpBonusPlus.DeathTick == World.Tick) // tmpOutdatedBonuses.Add(tmpBonusPlus.Id); //foreach (long tmpBonusId in tmpOutdatedBonuses) //{ // Bonuses.Remove(tmpBonusId); // BonusPlus.Remove(tmpBonusId); //} //foreach (Bonus tmpBonus in world.Bonuses) // if (!Bonuses.ContainsKey(tmpBonus.Id)) // { // Bonuses.Add(tmpBonus.Id, tmpBonus); // BonusPlus.Add(tmpBonus.Id, new BonusPlus(tmpBonus.Id, World.Tick + Settings.BonusLifeTime)); // } } foreach (TankPlus tmpTankPlus in TankPlus.Values) tmpTankPlus.Update(); if (!TankPlus[Self.Id].IsAlive) return; // SHOOTING ------------------------------------------------------------------------------------------------------------- AnglesRegular.Sort((Comparison<KeyValuePair<double, double>>)((x, y) => y.Value.CompareTo(x.Value))); AnglesPremium.Sort((Comparison<KeyValuePair<double, double>>)((x, y) => y.Value.CompareTo(x.Value))); double tmpAngle = Self.Angle + Self.TurretRelativeAngle, bestAngle = tmpAngle; if (AnglesRegular.Count > 0 && AnglesRegular[0].Value > 0) { bestAngle = AnglesRegular[0].Key; if (Math.Abs(Mathematics.AngleDifference(tmpAngle, AnglesRegular[0].Key)) < 0.017453292519943) // 1 degree move.FireType = FireType.Regular; } if (Self.PremiumShellCount > 0 && AnglesPremium.Count > 0 && (AnglesRegular.Count == 0 || AnglesPremium[0].Value > AnglesRegular[0].Value)) { bestAngle = AnglesPremium[0].Key; if (Math.Abs(Mathematics.AngleDifference(tmpAngle, AnglesPremium[0].Key)) < 0.017453292519943) move.FireType = FireType.Premium; } if (bestAngle != tmpAngle) { double tmpTurnAngle = Mathematics.AngleDifference(tmpAngle, bestAngle); move.TurretTurn = tmpTurnAngle; //move.LeftTrackPower = tmpTurnAngle > 0 ? Self.EngineRearPowerFactor : -1; //move.RightTrackPower = tmpTurnAngle < 0 ? Self.EngineRearPowerFactor : -1; } // DRIVING ------------------------------------------------------------------------------------------------------------- double bestBonusDistance = 10000, tmpDistance; Point bestBonusLocation = new Point(), tmpBonusLocation; bool haveTarget = false; foreach (Bonus tmpBonus in World.Bonuses) { tmpBonusLocation = new Point(tmpBonus.X, tmpBonus.Y); tmpDistance = Mathematics.Distance(SelfLocation, tmpBonusLocation); if ((_currentBonus != null && tmpBonus.Id == _currentBonus.Id) || tmpDistance < bestBonusDistance) { haveTarget = true; _currentBonus = tmpBonus; bestBonusDistance = tmpDistance; bestBonusLocation = tmpBonusLocation; } } if (!haveTarget) { _currentBonus = null; return; } //double movementAngle = TankPlus[Self.Id].AnglePrediction[0]; double turnAngle = Mathematics.AngleDifference(Self.Angle, Mathematics.SegmentAngle(SelfLocation, bestBonusLocation)); if (Math.Abs(turnAngle) < Mathematics.SixthPI) { move.LeftTrackPower = 1; move.RightTrackPower = 1; } else { move.TurretTurn = turnAngle; move.LeftTrackPower = turnAngle > 0 ? 0.75 : -1; move.RightTrackPower = turnAngle < 0 ? 0.75 : -1; } /*double turnRatio = (Math.PI * Math.PI - Math.Abs(turnAngle * turnAngle)) / (Math.PI * Math.PI); if (Math.Abs(turnAngle) < Mathematics.HalfPI) { turnRatio /= 2; if (Math.Abs(turnAngle) < Mathematics.ThirdPI) { turnRatio /= 2; if (Math.Abs(turnAngle) < Mathematics.SixthPI) { turnRatio /= 2; } } } move.LeftTrackPower = turnAngle > 0 ? 1 - 0.25 * turnRatio : 1 - 2 * turnRatio; move.RightTrackPower = turnAngle < 0 ? 1 - 0.25 * turnRatio : 1 - 2 * turnRatio;*/ //double tmpAngle = Mathematics.AddAnglesAbsolute(Self.Angle, Self.TurretRelativeAngle); //Point tmpLocation = new Point(Self.X, Self.Y); //List<KeyValuePair<double, double>> tmpAnglesRegular = new List<KeyValuePair<double, double>>(); //List<KeyValuePair<double, double>> tmpAnglesPremium = new List<KeyValuePair<double, double>>(); //for (int i = -Settings.PredictionAngleCount; i < Settings.PredictionAngleCount; ++i) //{ // double tmpTestAngle = Mathematics.AddAnglesAbsolute(tmpAngle, Settings.PredictionAngleStep * i); // tmpAnglesRegular.Add(new KeyValuePair<double, double>(tmpTestAngle, CalculateValue(tmpLocation, tmpTestAngle, ShellType.Regular))); // //tmpAnglesPremium.Add(new KeyValuePair<double, double>(tmpTestAngle, CalculateValue(tmpLocation, tmpTestAngle, ShellType.Premium))); //} //tmpAnglesRegular.Sort((Comparison<KeyValuePair<double, double>>)((x, y) => y.Value.CompareTo(x.Value))); ////tmpAnglesPremium.Sort((Comparison<KeyValuePair<double, double>>)((x, y) => y.Value.CompareTo(x.Value))); //if (tmpAnglesRegular[0].Key == tmpAngle && tmpAnglesRegular[0].Value > Settings.RegularLimit) // move.FireType = FireType.Regular; ////if (Self.PremiumShellCount > 0 && tmpAnglesPremium[0].Key == tmpAngle && tmpAnglesPremium[0].Value > Settings.RegularLimit) //// move.FireType = FireType.Premium; //if (move.FireType == null && tmpAnglesRegular[0].Value > 0) //{ // double tmpTurnAngle = tmpAnglesRegular[0].Key; // //if (tmpAnglesRegular[0].Value > tmpAnglesPremium[0].Value) // // tmpTurnAngle = tmpAnglesRegular[0].Key; // //else // // tmpTurnAngle = tmpAnglesPremium[0].Key; // move.TurretTurn = Mathematics.AddAnglesAbsolute(tmpTurnAngle, -tmpAngle); // move.LeftTrackPower = move.TurretTurn > 0 ? Self.EngineRearPowerFactor : -1; // move.RightTrackPower = move.TurretTurn < 0 ? Self.EngineRearPowerFactor : -1; //} ////Lap("A"); ////Console.ReadLine(); }