public void Move(Hockeyist self, World world, Game game, Move move) { if (self.State == HockeyistState.Swinging) { move.Action = ActionType.Strike; return; } if (world.Puck.OwnerPlayerId == self.PlayerId) { if (world.Puck.OwnerHockeyistId == self.Id) { Player opponentPlayer = world.GetOpponentPlayer(); double netX = 0.5D * (opponentPlayer.NetBack + opponentPlayer.NetFront); double netY = 0.5D * (opponentPlayer.NetBottom + opponentPlayer.NetTop); netY += (self.Y < netY ? 0.5D : -0.5D) * game.GoalNetHeight; double angleToNet = self.GetAngleTo(netX, netY); move.Turn = angleToNet; if (Math.Abs(angleToNet) < STRIKE_ANGLE) { move.Action = ActionType.Swing; } } else { Hockeyist nearestOpponent = getNearestOpponent(self.X, self.Y, world); if (nearestOpponent != null) { if (self.GetDistanceTo(nearestOpponent) > game.StickLength) { move.SpeedUp = 1.0D; } else if (Math.Abs(self.GetAngleTo(nearestOpponent)) < 0.5D * game.StickSector) { move.Action = ActionType.Strike; } move.Turn = self.GetAngleTo(nearestOpponent); } } } else { move.SpeedUp = 1.0D; move.Turn = self.GetAngleTo(world.Puck); move.Action = ActionType.TakePuck; } }
public void Move(Hockeyist self, World world, Game game, Move move) { OP = world.GetOpponentPlayer(); MP = world.GetMyPlayer(); RinkMiddleHeight = (game.RinkTop + game.RinkBottom) / 2; RinkMiddleWidth = (game.RinkLeft + game.RinkRight) / 2; double TX; double TY; // 0. Таблица ударных позиций /* using (System.IO.StreamWriter sw = new System.IO.StreamWriter("Speed.txt")) { double[,] xy = new double[200, 200]; for (double speed = 0.0; speed <= 70.0; speed += 1.0) for (double y = game.RinkTop; y <= game.RinkBottom; y += 10.0) for (double x = game.RinkLeft; x <= game.RinkRight; x += 10.0) { TX = OP.NetFront; TY = (y <= RinkMiddleHeight) ? OP.NetBottom - 9 : OP.NetTop + 9; if (CanShot(GetAngleBetween(x, y, TX, TY, 0), self.Radius, x, y, world.Puck.Radius, speed, Math.PI / 3, OP.NetFront, (y >= RinkMiddleHeight) ? OP.NetBottom : OP.NetTop, game.GoalieMaxSpeed)) if (xy[(int)(x / 10), (int)(y / 10)] == 0) xy[(int)(x / 10), (int)(y / 10)] = speed; } for (double y = game.RinkTop; y <= game.RinkBottom; y += 10.0) { for (double x = game.RinkLeft; x <= game.RinkRight; x += 10.0) sw.Write("{0} ", ((int)(xy[(int)(x / 10), (int)(y / 10)])).ToString("D2")); sw.WriteLine(); } return; } */ // 1. Завершение удара // если идет замах более 13 тиков, то ударить if (self.LastAction == ActionType.Swing && world.Tick - self.LastActionTick >= 13.0) { move.Action = ActionType.Strike; return; } // 2. Назначение второго вратаря // TX, TY - координаты позиции второго вратаря TX = (MP.NetFront < RinkMiddleWidth) ? MP.NetFront + 80 : MP.NetFront - 80; TY = RinkMiddleHeight; // проверить является ли хоккеист ближайшим к позиции вратаря bool nearest = true; foreach (Hockeyist h in world.Hockeyists) if (self.GetDistanceTo(TX, TY) > h.GetDistanceTo(TX, TY) && h.PlayerId == MP.Id && h.Type != HockeyistType.Goalie) nearest = false; // ближайщий к воротам не владеющий шайбой становится вторым вратарем if (world.Puck.OwnerPlayerId == MP.Id && world.Puck.OwnerHockeyistId != self.Id || world.Puck.OwnerPlayerId != MP.Id && nearest) { if (self.GetDistanceTo(world.Puck) < game.StickLength && Math.Abs(self.GetAngleTo(world.Puck)) <= game.StickSector) { if (world.Puck.SpeedX * world.Puck.SpeedX + world.Puck.SpeedY * world.Puck.SpeedY < 12.0 * 12.0 && world.Puck.OwnerHockeyistId == -1) { move.Action = ActionType.TakePuck; return; } else { move.Action = ActionType.Strike; return; } } if (self.GetDistanceTo(world.Puck) < 2.6 * game.StickLength && self.GetDistanceTo(TX, TY) < 1.2 * game.StickLength && world.Puck.OwnerHockeyistId != MP.Id) { move.SpeedUp = 1.0; move.Turn = self.GetAngleTo(world.Puck); return; } else if (self.GetDistanceTo(world.Puck) < 5 * game.StickLength && self.GetDistanceTo(TX, TY) < 30) { move.SpeedUp = 0.0; move.Turn = self.GetAngleTo(world.Puck); } else GoTo(self, TX, TY, 0, 0, 200, game, move); // выбрать первого попавшегося вражеского игрока и бить клюшкой foreach (Hockeyist h in world.Hockeyists) if (h.IsTeammate == false && h.Type != HockeyistType.Goalie && h.State == HockeyistState.Active) if (self.GetDistanceTo(h) < game.StickLength && Math.Abs(self.GetAngleTo(h)) <= game.StickSector) { move.Action = ActionType.Strike; return; } // вратарь ничего не делает return; } // 3. Отбор шайбы // наша команда не владеет шайбой if (world.Puck.OwnerPlayerId != MP.Id) { // двигаться к шайбе GoTo(self, world.Puck, 0, game, move); // если шайбой никто не владеет и она в пределах клюшки, подобрать if (world.Puck.OwnerHockeyistId == -1 && self.GetDistanceTo(world.Puck) < game.StickLength && Math.Abs(self.GetAngleTo(world.Puck)) <= game.StickSector) { move.Action = ActionType.TakePuck; return; } // если вражеский хоккеист в пределах клюшки, ударить его foreach (Hockeyist h in world.Hockeyists) if (h.Id == world.Puck.OwnerHockeyistId) { // двигаться к владельцу шайбы GoTo(self, h, 0, game, move); if (self.GetDistanceTo(h) < game.StickLength && Math.Abs(self.GetAngleTo(h)) <= game.StickSector) { move.Action = ActionType.Strike; return; } } // команда без шайбы, а хоккеист ничего не делает return; } // 4. Атака // наша команда владеет шайбой else // если хоккеист владеет шайбой if (world.Puck.OwnerHockeyistId == self.Id) { TX = OP.NetFront; TY = (world.Puck.Y <= RinkMiddleHeight) ? OP.NetBottom - 9 : OP.NetTop + 9; // если можно забить страйком if (CanShot(self, world.Puck, 20.0, Math.PI / 360.0, TX, TY, game.GoalieMaxSpeed)) { move.Action = ActionType.Swing; return; } // если можно забить пасом if (CanShot(self, world.Puck, 15.0, Math.PI / 3.0, TX, TY, game.GoalieMaxSpeed)) { move.PassPower = 1.0; move.PassAngle = GetAngleBetween(world.Puck.X, world.Puck.Y, TX, TY, self.Angle); move.Action = ActionType.Pass; return; } // ВЫБОР НАПРАВЛЕНИЯ // нужно выбрать и ехать к ударной позиции TX = RinkMiddleWidth; TY = RinkMiddleHeight; double dX = 110.0; double X1 = 367.5; double Y1 = 107.0; double X2 = 267.5; double Y2 = 207.0; double t; if (world.Puck.Y <= RinkMiddleHeight && OP.NetFront < RinkMiddleWidth) { if (world.Puck.X - dX >= game.RinkLeft + X1) { TX = world.Puck.X - dX; TY = game.RinkTop + Y1; } else if (world.Puck.X - dX >= game.RinkLeft + X2) { TX = world.Puck.X - dX; t = (TX - game.RinkLeft - X2) / (X1 - X2); TY = game.RinkTop + Y1 * t + Y2 * (1 - t); } else { TX = game.RinkLeft + X2; TY = game.RinkTop + Y2; } } if (world.Puck.Y <= RinkMiddleHeight && OP.NetFront >= RinkMiddleWidth) { if (world.Puck.X + dX <= game.RinkRight - X1) { TX = world.Puck.X + dX; TY = game.RinkTop + Y1; } else if (world.Puck.X + dX <= game.RinkRight - X2) { TX = world.Puck.X + dX; t = (game.RinkRight - TX - X2) / (X1 - X2); TY = game.RinkTop + Y1 * t + Y2 * (1 - t); } else { TX = game.RinkRight - X2; TY = game.RinkTop + Y2; } } if (world.Puck.Y > RinkMiddleHeight && OP.NetFront < RinkMiddleWidth) { if (world.Puck.X - dX >= game.RinkLeft + X1) { TX = world.Puck.X - dX; TY = game.RinkBottom - Y1; } else if (world.Puck.X - dX >= game.RinkLeft + X2) { TX = world.Puck.X - dX; t = (TX - game.RinkLeft - X2) / (X1 - X2); TY = game.RinkBottom - Y1 * t - Y2 * (1 - t); } else { TX = game.RinkLeft + X2; TY = game.RinkBottom - Y2; } } if (world.Puck.Y > RinkMiddleHeight && OP.NetFront >= RinkMiddleWidth) { if (world.Puck.X + dX <= game.RinkRight - X1) { TX = world.Puck.X + dX; TY = game.RinkBottom - Y1; } else if (world.Puck.X + dX <= game.RinkRight - X2) { TX = world.Puck.X + dX; t = (game.RinkRight - TX - X2) / (X1 - X2); TY = game.RinkBottom - Y1 * t - Y2 * (1 - t); } else { TX = game.RinkRight - X2; TY = game.RinkBottom - Y2; } } if (world.Puck.X > RinkMiddleWidth && OP.NetFront <= RinkMiddleWidth) { TX = world.Puck.X - dX; Hockeyist hm = null; foreach (Hockeyist h in world.Hockeyists) if (h.IsTeammate == false && h.Type != HockeyistType.Goalie && (hm == null || self.GetDistanceTo(hm) > self.GetDistanceTo(h))) hm = h; if (hm.Y <= self.Y) TY = game.RinkBottom - Y1; else TY = game.RinkTop + Y1; } if (world.Puck.X <= RinkMiddleWidth && OP.NetFront > RinkMiddleWidth) { TX = world.Puck.X + dX; Hockeyist hm = null; foreach (Hockeyist h in world.Hockeyists) if (h.IsTeammate == false && h.Type != HockeyistType.Goalie && (hm == null || self.GetDistanceTo(hm) > self.GetDistanceTo(h))) hm = h; if (hm.Y <= self.Y) TY = game.RinkBottom - Y1; else TY = game.RinkTop + Y1; } // ПРОДВИЖЕНИЕ // если позиция далеко, ехать дальше if (world.Puck.GetDistanceTo(TX, TY) >= 100.0) { move.SpeedUp = 1.0; move.Action = ActionType.None; move.Turn = self.GetAngleTo(TX, TY); } // около ударной позиции замедлиться, развернуться // и замахнуться в верхнюю или нижнюю штангу else { TY = (world.Puck.Y >= RinkMiddleHeight) ? OP.NetTop + 9 : OP.NetBottom - 9; move.SpeedUp = 0.0; move.Turn = self.GetAngleTo(OP.NetFront, TY); if (Math.Abs(GetAngleBetween(world.Puck.X, world.Puck.Y, OP.NetFront, TY, self.Angle)) <= Math.PI / 360.0) { move.Action = ActionType.Swing; return; } else move.Action = ActionType.None; } // можно отдать пас foreach (Hockeyist h in world.Hockeyists) if (h.IsTeammate == true && h.Type != HockeyistType.Goalie && h.State == HockeyistState.Active) if (Math.Abs(self.GetAngleTo(h)) <= Math.PI / 90.0) { move.PassAngle = self.GetAngleTo(h); move.PassPower = 0.75; move.Action = ActionType.Pass; } // хоккеист владеет шайбой и при этом ничего не делает return; } // хоккеист без шайбы атакует вражеских хоккеистов else { // выбрать первого попавшегося вражеского игрока и бить клюшкой foreach (Hockeyist h in world.Hockeyists) if (h.IsTeammate == false && h.Type != HockeyistType.Goalie && h.State == HockeyistState.Active) { move.SpeedUp = 1.0; move.Turn = self.GetAngleTo(h); // GoTo(self, h, 0, game, move); if (self.GetDistanceTo(h) < game.StickLength && Math.Abs(self.GetAngleTo(h)) <= game.StickSector) move.Action = ActionType.Strike; else move.Action = ActionType.TakePuck; return; } // хоккеист без шайбы и при этом ничего не делает return; } }
public void Move(Hockeyist self, World world, Game game, Move move) { if (self.State == HockeyistState.Resting) return; ShowWindow(); // // fill globals _strikePoint = null; Hockeyists = world.Hockeyists; MyRest = Hockeyists.Where(x => x.IsTeammate && x.State == HockeyistState.Resting).ToArray(); this.puck = world.Puck; this.move = move; World = world; Game = game; Opp = world.GetOpponentPlayer(); My = world.GetMyPlayer(); RinkWidth = game.RinkRight - game.RinkLeft; RinkHeight = game.RinkBottom - game.RinkTop; OppGoalie = Hockeyists.FirstOrDefault(x => !x.IsTeammate && x.Type == HockeyistType.Goalie); MyGoalie = Hockeyists.FirstOrDefault(x => x.IsTeammate && x.Type == HockeyistType.Goalie); HoRadius = self.Radius; RinkCenter = new Point(game.RinkLeft + RinkWidth/2, game.RinkTop + RinkHeight/2); PuckRadius = puck.Radius; var friends = Hockeyists .Where(x => x.IsTeammate && x.Id != self.Id && x.Type != HockeyistType.Goalie && x.State != HockeyistState.Resting) .ToArray(); var friend1 = friends.Count() < 2 || friends[0].TeammateIndex < friends[1].TeammateIndex ? friends[0] : friends[1]; var friend2 = friends.Count() > 1 ? friends[0].TeammateIndex < friends[1].TeammateIndex ? friends[1] : friends[0] : null; FillWayPoints(); // // if (Game.OvertimeTickCount == 200) // костыль чтобы пройти верификацию return; TimerStart(); var hock = new AHock(self); var needSubst = NeedTrySubstitute(hock); if (My.IsJustMissedGoal || My.IsJustScoredGoal) { SubstSignal = false; StayOn(self, GetSubstitutePoint(hock).First, null); TrySubstitute(hock); } else { var range = TurnRange(hock.AAgility); move.SpeedUp = Inf; if (self.State == HockeyistState.Swinging && self.Id != puck.OwnerHockeyistId) { if (!TryStrikeWithoutTakeIfSwinging(hock, new APuck(puck, OppGoalie))) move.Action = ActionType.CancelStrike; } else if (puck.OwnerHockeyistId == self.Id) { var wait = Inf; double selTurn = 0, selSpeedUp = 0; var willSwing = false; var maxProb = 0.15; var selAction = ActionType.Strike; TimerStart(); if (self.State != HockeyistState.Swinging) { var spUps = self.RemainingCooldownTicks == 0 || Math.Abs(self.X - My.NetFront) < RinkWidth / 2 ? (Math.Abs(self.X - Opp.NetFront) < RinkWidth / 3 ? new[] { 0.0, 1.0 } : new[] { 1.0 }) : new[] { 1.0, 0.5, 0.0, -0.5 }; var moveDirBase = MyRight() && self.Y > RinkCenter.Y || MyLeft() && self.Y < RinkCenter.Y ? 1 : -1; // если не замахнулся for (var ticks = 0; ticks < 50; ticks++) { // если буду замахиваться (ТО В КОНЦЕ!!!), то нужно подождать минимум game.SwingActionCooldownTicks const int turns = 4; for (var moveDir = -1; moveDir <= 1; moveDir += 2) { for (var moveTurn = 0.0; moveTurn - Eps <= range; moveTurn += range/turns) { var turn = moveDir*moveTurn; foreach (var spUp in spUps) { if (moveDir == moveDirBase || spUp <= Eps && IsFinal()) { var end = ticks + game.SwingActionCooldownTicks; var start = Math.Max(0, end - game.MaxEffectiveSwingTicks); // когда начинаем замахиваться var p = ProbabStrikeAfter(end - start, self, new[] { new MoveAction {Ticks = start, SpeedUp = spUp, Turn = turn}, new MoveAction {Ticks = end - start, SpeedUp = 0, Turn = 0}, }, ActionType.Strike); if (p > maxProb) { wait = start; willSwing = true; maxProb = p; selTurn = turn; selSpeedUp = spUp; selAction = ActionType.Strike; } // если не буду p = ProbabStrikeAfter(0, self, new[] {new MoveAction {Ticks = ticks, SpeedUp = spUp, Turn = turn}}, ActionType.Strike); if (p > maxProb) { wait = ticks; willSwing = false; maxProb = p; selTurn = turn; selSpeedUp = spUp; selAction = ActionType.Strike; } // если пасом p = ProbabStrikeAfter(0, self, new[] {new MoveAction {Ticks = ticks, SpeedUp = spUp, Turn = turn}}, ActionType.Pass); if (p > maxProb) { wait = ticks; willSwing = false; maxProb = p; selTurn = turn; selSpeedUp = spUp; selAction = ActionType.Pass; } } } } } } } else { // если уже замахнулся for (var ticks = Math.Max(0, game.SwingActionCooldownTicks - self.SwingTicks); ticks < 80; ticks++) { var p = ProbabStrikeAfter(ticks + self.SwingTicks, self, new[] {new MoveAction {Ticks = ticks, SpeedUp = 0, Turn = 0}}, ActionType.Strike); if (p > maxProb) { wait = ticks; willSwing = true; maxProb = p; selAction = ActionType.Strike; } } } Log("STRIKE " + TimerStop()); if (wait < Inf) { SubstSignal = true; } drawInfo.Enqueue((wait == Inf ? 0 : maxProb) + ""); if (!willSwing && self.State == HockeyistState.Swinging) { move.Action = ActionType.CancelStrike; } else if (willSwing && wait == 0 && self.State != HockeyistState.Swinging) { move.Action = ActionType.Swing; } else if (wait == Inf) { var wayPoint = FindWayPoint(self); if (wayPoint == null) { needPassQueue.Enqueue(Get(self)); if (!TryPass(hock)) { var pt = Math.Abs(Opp.NetFront - self.X) < RinkWidth/3 ? Get(friend2 == null || (MyLeft() ? friend2.X > friend1.X : friend2.X < friend1.X) ? friend1 : friend2) : GetStrikePoint(); DoMove(self, pt, 1); } } else { DoMove(self, wayPoint, 1); } } else if (wait == 0) { move.Action = selAction; if (selAction == ActionType.Pass) { move.PassPower = 1; move.PassAngle = PassAngleNorm(hock.GetAngleTo(GetStrikePoint())); } } else { move.SpeedUp = selSpeedUp; move.Turn = selTurn; } } else if (puck.OwnerPlayerId != -1 || !TryStrikeWithoutTake(hock, new APuck(puck, OppGoalie))) { var owner = Hockeyists.FirstOrDefault(x => x.Id == puck.OwnerHockeyistId); var pk = new APuck(puck, MyGoalie) {IsDefend = true}; if (puck.OwnerPlayerId == Opp.Id && (CanStrike(self, owner) || CanStrike(self, puck))) { // попытаться выбить move.Action = ActionType.Strike; } else if (puck.OwnerPlayerId != self.PlayerId && CanStrike(self, puck)) { // проверяем что не летит в чужие ворота var cpk = new APuck(puck, OppGoalie); if (cpk.Move(200, true) == 0) { if (pk.Move(200, goalCheck: true) == 1) // если вратарь не отобьёт move.Action = ActionType.Strike; else move.Action = ActionType.TakePuck; } } else { var toPuck = GoToPuck(self, null); var toPuck1 = GoToPuck(friend1, null); var toPuck2 = friend2 == null ? null : GoToPuck(friend2, null); if (friend2 != null && toPuck1.Third < toPuck2.Third) { Swap(ref friend1, ref friend2); Swap(ref toPuck1, ref toPuck2); } var def = GetDefendPos2(); var have = puck.OwnerPlayerId == My.Id; // 1 - дольше всего идет до шайбы var net = new Point(My.NetFront, RinkCenter.Y); double ii = net.GetDistanceTo(self) < 300 ? 1.0 : 1.0; double jj = net.GetDistanceTo(friend1) < 300 ? 1.0 : 1.0; var myFirst = GetFirstOnPuck(new[] {self}, new APuck(puck, OppGoalie), true, 100, false).Second == (friend2 == null ? -1 : friend2.Id); if (have ? (friend2 == null || ii*GetTicksTo(def, self) < jj*GetTicksTo(def, friend1)) // если я ближе, то иду на ворота : toPuck.Third/ii > toPuck1.Third/jj) // если я дольше всего, то иду на ворота { if (needSubst && (SubstSignal || puck.OwnerPlayerId != Opp.Id && self.Y <= Game.RinkTop + 0.666 * RinkHeight || self.Y <= Game.SubstitutionAreaHeight + Game.RinkTop)) { if (TrySubstitute(hock)) SubstSignal = false; else StayOn(self, GetSubstitutePoint(hock).First, null); } else { StayOn(self, def, Get(puck)); } } // иначе 1 идет на воротаpuck.OwnerPlayerId != My.Id else if (friend2 == null || (puck.OwnerPlayerId != My.Id && ( toPuck.Third < toPuck2.Third //|| Math.Abs(Opp.NetFront - puck.X) < RinkWidth / 2 // шайба не у нас и на чужой половине || !myFirst ))) { var bestTime = Inf; double bestTurn = 0.0; var needTime = GetFirstOnPuck(Hockeyists.Where(x => x.IsTeammate), new APuck(puck, OppGoalie), true, -1).First; var lookAt = new Point(Opp.NetFront, RinkCenter.Y); for (var turn = -range; turn <= range; turn += range / 10) { var I = hock.Clone(); var P = new APuck(puck, OppGoalie); for (var t = 0; t < needTime - 10 && t < 70; t++) { if (CanStrike(I, P)) { var cl = I.Clone(); var tm = GetTicksToUp(cl, lookAt) + t; if (tm < bestTime) { bestTime = tm; bestTurn = turn; } } I.Move(0, turn); P.Move(1); } } var i = hock.Clone(); var direct = MoveHockTo(i, toPuck.First); direct += MoveHockTo(i, lookAt); if (bestTime < direct && bestTime < Inf) { move.Turn = bestTurn; move.SpeedUp = 0.0; } DoMove(self, toPuck.First, toPuck.Second); } else { if (needSubst && (SubstSignal || puck.OwnerPlayerId != Opp.Id && self.Y <= RinkCenter.Y || self.Y <= Game.SubstitutionAreaHeight + Game.RinkTop)) { if (TrySubstitute(hock)) SubstSignal = false; else StayOn(self, GetSubstitutePoint(hock).First, null); } else { var c1 = new Point(RinkCenter.X, Game.RinkTop + 2*HoRadius); var c2 = new Point(RinkCenter.X, Game.RinkBottom - 2*HoRadius); var c = c1.GetDistanceTo(puck) > c2.GetDistanceTo(puck) ? c1 : c2; var s = GetStrikePoint(); StayOn(self, c, s); } } } } if (Eq(move.SpeedUp, Inf)) move.SpeedUp = 1; } Log(self.TeammateIndex + " >>>>>>>>>>>> " + TimerStop()); if (move.Action != ActionType.None) Log(move.Action); #if DEBUG draw(); Thread.Sleep(8); #endif drawInfo.Clear(); needPassQueue.Clear(); }
public void Move(Hockeyist self, World world, Game game, Move move) { Player OP = world.GetOpponentPlayer(); Player MP = world.GetMyPlayer(); double RinkMiddleHeight = (game.RinkTop + game.RinkBottom) / 2; double RinkMiddleWidth = (game.RinkLeft + game.RinkRight) / 2; double TargetX; double TargetY; // 1. Завершение удара // если идет замах более 13 тиков, то ударить if (self.LastAction == ActionType.Swing && world.Tick - self.LastActionTick >= 20) { move.Action = ActionType.Strike; return; } // 2. Назначение второго вратаря // NX, NY - координаты позиции второго вратаря double NX = (MP.NetFront < RinkMiddleWidth) ? MP.NetFront + 75 : MP.NetFront - 75; double NY = RinkMiddleHeight; // проверить является ли хоккеист ближайшим к позиции вратаря bool nearest = true; if (self.Id == world.Puck.OwnerHockeyistId) nearest = false; foreach (Hockeyist h in world.Hockeyists) if (h.IsTeammate && h.Id != self.Id && h.Type != HockeyistType.Goalie && h.Id != world.Puck.OwnerHockeyistId && h.GetDistanceTo(NX, NY) < self.GetDistanceTo(NX, NY)) nearest = false; // ближайщий к воротам не владеющий шайбой становится вторым вратарем if (nearest) { // двигаться к позиции второго вратаря move.SpeedUp = 1.0D; move.Turn = self.GetAngleTo(NX, NY); move.Action = ActionType.TakePuck; // приблизившись к позиции тормозить и разворачиваться if (self.GetDistanceTo(NX, NY) < 270) { move.SpeedUp = -1.0D; move.Turn = NormalizeAngle(self.GetAngleTo(NX, NY) + Math.PI); move.Action = ActionType.TakePuck; } // полностью остановиться в небольшом радиусе от позиции if (self.GetDistanceTo(NX, NY) < 70) { move.SpeedUp = 0.0D; move.Turn = self.GetAngleTo(world.Puck); if (self.GetDistanceTo(world.Puck) < game.StickLength) { if (world.Puck.SpeedX * world.Puck.SpeedX + world.Puck.SpeedY * world.Puck.SpeedY < 12 * 12 && world.Puck.OwnerHockeyistId == -1) move.Action = ActionType.TakePuck; else move.Action = ActionType.Strike; } } return; } // 3. Отбор шайбы // наша команда не владеет шайбой if (world.Puck.OwnerPlayerId != MP.Id) { // двигаться к шайбе move.SpeedUp = 1.0D; move.Turn = self.GetAngleTo(world.Puck); // если шайбой никто не владеет и она в пределах клюшки, подобрать if (world.Puck.OwnerHockeyistId == -1 && self.GetDistanceTo(world.Puck) < game.StickLength && Math.Abs(self.GetAngleTo(world.Puck)) <= game.StickSector) { move.Action = ActionType.TakePuck; return; } // если вражеский хоккеист в пределах клюшки, ударить его foreach (Hockeyist h in world.Hockeyists) if (!h.IsTeammate && self.GetDistanceTo(h) < game.StickLength && Math.Abs(self.GetAngleTo(h)) <= game.StickSector) { move.Action = ActionType.Strike; return; } move.Action = ActionType.None; return; } // 4. Атака // наша команда владеет шайбой else { // если хоккеист владеет шайбой if (self.Id == world.Puck.OwnerHockeyistId) { // нужно выбрать и ехать к ударной позиции double[,] XY = new double[4, 2] { { 0.25, 0.30 }, { 0.75, 0.30 }, { 0.25, 0.70 }, { 0.75, 0.70 } }; TargetX = RinkMiddleWidth; TargetY = RinkMiddleHeight; double SumY = 0.0; int cnt = 0; foreach (Hockeyist h in world.Hockeyists) if (!h.IsTeammate && h.Type != HockeyistType.Goalie) { SumY += h.Y; cnt++; } SumY /= cnt; if (SumY > RinkMiddleHeight && OP.NetFront < RinkMiddleWidth) { TargetX = game.RinkRight * XY[0, 0] + game.RinkLeft * (1 - XY[0, 0]); TargetY = game.RinkBottom * XY[0, 1] + game.RinkTop * (1 - XY[0, 1]); } if (SumY > RinkMiddleHeight && OP.NetFront >= RinkMiddleWidth) { TargetX = game.RinkRight * XY[1, 0] + game.RinkLeft * (1 - XY[1, 0]); TargetY = game.RinkBottom * XY[1, 1] + game.RinkTop * (1 - XY[1, 1]); } if (SumY <= RinkMiddleHeight && OP.NetFront < RinkMiddleWidth) { TargetX = game.RinkRight * XY[2, 0] + game.RinkLeft * (1 - XY[2, 0]); TargetY = game.RinkBottom * XY[2, 1] + game.RinkTop * (1 - XY[2, 1]); } if (SumY <= RinkMiddleHeight && OP.NetFront >= RinkMiddleWidth) { TargetX = game.RinkRight * XY[3, 0] + game.RinkLeft * (1 - XY[3, 0]); TargetY = game.RinkBottom * XY[3, 1] + game.RinkTop * (1 - XY[3, 1]); } // около ударной позиции замедлиться, развернуться // и замахнуться в верхнюю или нижнюю штангу if (self.GetDistanceTo(TargetX, TargetY) <= 100) { move.SpeedUp = 0.1D; if (self.Y >= RinkMiddleHeight) { move.Turn = self.GetAngleTo(OP.NetFront, OP.NetTop + 5); if (Math.Abs(GetAngleBetween(world.Puck.X, world.Puck.Y, OP.NetFront, OP.NetTop + 8, self.Angle)) <= Math.PI / 180.0D) { move.Action = ActionType.Swing; return; } } else { move.Turn = self.GetAngleTo(OP.NetFront, OP.NetBottom - 5); if (Math.Abs(GetAngleBetween(world.Puck.X, world.Puck.Y, OP.NetFront, OP.NetBottom - 8, self.Angle)) <= Math.PI / 180.0D) { move.Action = ActionType.Swing; return; } } // если удар не проходит, можно дать пас своему foreach(Hockeyist h in world.Hockeyists) if (h.IsTeammate && h.Id != self.Id && h.Type != HockeyistType.Goalie && Math.Abs(self.GetAngleTo(h)) < Math.PI / 60) { move.Action = ActionType.Pass; move.PassAngle = GetAngleBetween(world.Puck.X, world.Puck.Y, h.X, h.Y, self.Angle); move.PassPower = (10 - Math.Sqrt(self.SpeedX * self.SpeedX + self.SpeedY * self.SpeedY) * Math.Cos(GetAngleBetween(world.Puck.X, world.Puck.Y, h.X, h.Y, self.Angle) - self.GetAngleTo(self.X + self.SpeedX, self.Y + self.SpeedY))) / 15; return; } } // если позиция далеко, ехать дальше move.SpeedUp = 1.0D; move.Action = ActionType.None; move.Turn = self.GetAngleTo(TargetX, TargetY); // если можно забить пасом double TX, TY; TX = OP.NetFront; if (world.Puck.Y <= RinkMiddleHeight) TY = OP.NetBottom - 5; else TY = OP.NetTop + 5; double cos = (TX - world.Puck.X) / world.Puck.GetDistanceTo(TX, TY); double sin = (TY - world.Puck.Y) / world.Puck.GetDistanceTo(TX, TY); double Speed = 14.0 + Math.Sqrt(self.SpeedX * self.SpeedX + self.SpeedY * self.SpeedY) * Math.Cos(GetAngleBetween(world.Puck.X, world.Puck.Y, TX, TY, self.Angle) - self.GetAngleTo(self.X + self.SpeedX, self.Y + self.SpeedY)); double Vx = Speed * cos; double Vy = (Math.Abs(Speed * sin) > game.GoalieMaxSpeed) ? Speed * sin - Math.Sign(sin) * game.GoalieMaxSpeed : 0.0; double x0 = Math.Abs(world.Puck.X - TX); if (world.Puck.Y > OP.NetBottom || world.Puck.Y < OP.NetTop) x0 *= (Math.Abs(OP.NetBottom - OP.NetTop - 2 * self.Radius) / Math.Abs(TY - world.Puck.Y)); double y0 = 0; double tmin = -x0 * Vx / (Vx * Vx + Vy * Vy); double xmin = x0 + Vx * tmin; double ymin = y0 + Vy * tmin; double rmin = Math.Sqrt(xmin * xmin + ymin * ymin); // если можно забить пасом if (rmin >= world.Puck.Radius + self.Radius + 5) if (Math.Abs(GetAngleBetween(world.Puck.X, world.Puck.Y, TX, TY, self.Angle)) <= Math.PI / 3.0D) { move.PassAngle = GetAngleBetween(world.Puck.X, world.Puck.Y, TX, TY, self.Angle); move.PassPower = 1.0D; move.Action = ActionType.Pass; return; } } // хоккеист без шайбы атакует вражеских хоккеистов else { // выбрать ближайщего вражеского игрока и бить клюшкой foreach (Hockeyist h in world.Hockeyists) if (h.IsTeammate == false && h.Type != HockeyistType.Goalie && h.State == HockeyistState.Active) { move.SpeedUp = 1.0D; move.Turn = self.GetAngleTo(h); if (self.GetDistanceTo(h) < game.StickLength) move.Action = ActionType.Strike; else move.Action = ActionType.TakePuck; return; } } } }