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