public World(int moveIndex, int width, int height, Player[] players, Trooper[] troopers, Bonus[] bonuses, CellType[][] cells, bool[] cellVisibilities) { this.moveIndex = moveIndex; this.width = width; this.height = height; this.players = new Player[players.Length]; Array.Copy(players, this.players, players.Length); this.troopers = new Trooper[troopers.Length]; Array.Copy(troopers, this.troopers, troopers.Length); this.bonuses = new Bonus[bonuses.Length]; Array.Copy(bonuses, this.bonuses, bonuses.Length); this.cells = new CellType[width][]; for (int x = 0; x < width; ++x) { this.cells[x] = new CellType[cells[x].Length]; Array.Copy(cells[x], this.cells[x], cells[x].Length); } this.cellVisibilities = cellVisibilities; }
public int GetShootingPriority(Trooper opponent) { for(var i = 0; i < ShootingPriority.Length; i++) if (opponent.Type == ShootingPriority[i]) return i; throw new InvalidDataException(); }
double GetTeamBonusProfit(Bonus bonus, ref Trooper trooper, bool allowTakeBonus) { // нужен минимальный вес double bestWeight = Inf; foreach (var tr in Team) { double weight = GetShoterPath(tr, bonus, notFilledMap, beginFree: true, endFree: false) * (1 + 0.5 * GetQueuePlace(tr, self.Id == tr.Id && self.ActionPoints >= self.InitialActionPoints)); if (tr.Id != commander.Id || !allowTakeBonus) { var L = GetShoterPath(tr, bonus, map, beginFree: true, endFree: false); weight = L <= 2 && (self.Id != tr.Id || self.ActionPoints/GetMoveCost() >= 2*L) ? weight : Inf; } if (!IsHaveBonus(tr, bonus) && weight < bestWeight) { bestWeight = weight; trooper = tr; } } if (bestWeight >= Inf) return -1; return 1.0 / bestWeight; }
int GetQueuePlace(Trooper trooper, bool MayFirst) { var current = queue.IndexOf(self.Id); for (var idx = current + (MayFirst ? 0 : 1); idx < queue.Count; idx++) if ((long)queue[idx] == trooper.Id) return idx - current + 1; return 1; }
double GetHelperQuality(Trooper tr) { double quality = 1.0 / GetShoterPath(self, tr, notFilledMap, beginFree: true, endFree: true); if (tr.Type == TrooperType.FieldMedic) return quality * 2; if (!tr.IsHoldingMedikit) return -Inf; return quality; }
int GetQueuePlace2(Trooper trooper, bool MayFirst) { for (var i = 0; i < queue.Count; i++) { if (GetTrooper((long)queue[i]) == null) { queue.RemoveAt(i); i--; } } var current = queue.IndexOf(self.Id); for (var idx = current + (MayFirst ? 0 : 1); ; idx++) if ((long)queue[idx % queue.Count] == trooper.Id) return idx - current + 1; }
Point IfTeamBonus(ref Trooper result, bool allowTakeBonus) { var bestPoint = Point.MInf; result = null; foreach (var bonus in Bonuses) { Trooper whose = null; ; double profit = GetTeamBonusProfit(bonus, ref whose, allowTakeBonus); if (profit > bestPoint.profit) { bestPoint = new Point(bonus.X, bonus.Y, profit); result = whose; } } if (bestPoint.profit <= 0) bestPoint = null; return bestPoint; }
Point GoToEncircling(Trooper center, Point goal) { var bestPoint = new Point(0, 0, Inf); double optDanger = self.Type == TrooperType.FieldMedic || self.Type == TrooperType.Sniper ? Inf : -Inf; for (var i = 0; i < Width; i++) { for (var j = 0; j < Height; j++) { if (map[i, j] == 0 || i == self.X && j == self.Y) { if (self.GetDistanceTo(i, j) > 10) // немного ускорит continue; // Нужно чтобы хватило ходов int steps = GetShoterPath(self, new Point(i, j), map, beginFree: true, endFree: true); if (self.ActionPoints / GetMoveCost() >= steps) { // и чтобы не закрывали кратчайший путь: int before = goal == null ? Inf : GetShoterPath(center, goal, map, beginFree:true, endFree: false); map[self.X, self.Y] = 0; map[i, j] = 1; int after = goal == null ? Inf : GetShoterPath(center, goal, map, beginFree: true, endFree: false); map[i, j] = 0; map[self.X, self.Y] = 1; if ((goal == null || after < Inf) && after <= before) { double sum = GetShoterPath(center, new Point(i, j), notFilledMap, beginFree: true, endFree: true); double dang = danger[i, j] + (goal == null ? 0 : goal.GetDistanceTo(i, j) * 0.01); if (sum < bestPoint.profit || EqualF(sum, bestPoint.profit) && (self.Type == TrooperType.FieldMedic || self.Type == TrooperType.Sniper ? (dang < optDanger) : (dang > optDanger)) ) { bestPoint = new Point(i, j, sum); optDanger = dang; } } } } } } return bestPoint.profit >= Inf ? null : bestPoint; }
private double getDanger(Trooper opp, int x, int y, int st, int h) { if (GetPlayer(opp.PlayerId) != null && GetPlayer(opp.PlayerId).IsStrategyCrashed) return 0; // Чтобы не бояться одного снайпера var oppShootingRange = state.opphit.Count(e => e > 0) == 1 && opp.Type == TrooperType.Sniper ? GetVisionRange(opp, Troopers[state.id], state.Stance) : GetShootingRange(opp, opp.Stance); int d = GetDistanceToShoot((int)(oppShootingRange + Eps), opp.X, opp.Y, GetStanceId(opp.Stance), x, y, st); // если он достреливает сразу: if (d == 0) { return 200; } int v; if (world.IsVisible(GetVisionRange(opp, Troopers[state.id], state.Stance), opp.X, opp.Y, opp.Stance, x, y, GetStance(state.Stance))) v = 0; else v = GetDistanceTo((int)(GetVisionRange(opp, Troopers[state.id], state.Stance) + Eps), opp.X, opp.Y, GetStanceId(opp.Stance), x, y, st); double visiblePenalty = 50 * (v == 0 ? 1 : Math.Exp(-v)); var oppAct = opp.InitialActionPoints; if (opp.Type != TrooperType.Scout && opp.Type != TrooperType.Soldier && OpponentCommander != null && OpponentCommander.GetDistanceTo(opp) <= game.CommanderAuraRange) oppAct += game.CommanderAuraBonusActionPoints; // если он подходит и убивает int act = oppAct - d * 2; // TODO: ??? int can = act / opp.ShootCost; double dam = can * opp.StandingDamage; if (dam >= h) return 150 + visiblePenalty; // если он подходит и отнимает жизни // тогда теперь он вынужден отбегать act = oppAct - (d * 2) * 2; // TODO: ??? can = act / opp.ShootCost; dam = Math.Max(0, can * opp.StandingDamage) + visiblePenalty; if (dam <= 0) return 0; return dam; }
public void Move(Trooper self, World world, Game game, Move move) { if (form == null) { thread = new Thread(showWindow); thread.Start(); Thread.Sleep(1000); } var panel = form.panel; var drawArea = new Bitmap(panel.Size.Width, panel.Size.Height); panel.Image = drawArea; Graphics g = Graphics.FromImage(drawArea); Pen pen = new Pen(Brushes.Black); g.DrawLine(pen, 1, 1, 40, 40); this.self = self; this.world = world; this.game = game; this.move = move; InitializeVariables(); ProcessApproximation(); if (world.MoveIndex == 37 && self.Type == TrooperType.Commander) world = world; var allowHill = !CheckShootMe(); if (BonusGoal != null && GetTrooper(MyStrategy.WhoseBonus) == null) BonusGoal = null; if (BonusGoal != null && IsHaveBonus(GetTrooper(MyStrategy.WhoseBonus), GetBonusAt(BonusGoal))) BonusGoal = null; // Карта где медик и снайпер отдельно (map03) // Координаты где собираться: // 18 13 // 11 6 if (MapHash == Lab2Map && world.MoveIndex <= 2 && (self.Type == TrooperType.FieldMedic || self.Type == TrooperType.Sniper) && Opponents.Count() == 0 ) { var rightLower = new Point(18, 14); var leftUpper = new Point(11, 5); var goal = rightLower.GetDistanceTo(self) < leftUpper.GetDistanceTo(self) ? rightLower : leftUpper; var to = GoScouting(goal, goal); if (to != null) { Go(ActionType.Move, to); return; } } if (IfFieldRationNeed()) { Go(ActionType.EatFieldRation); return; } Reached(new Point(self)); if (Opponents.Count() != 0) { AllowTakeBonus = false; // Чтобы знали куда бежать если противник отступит PointGoal = new Point(Opponents[0]); PointGoal.profit = world.MoveIndex; var action = BruteForceDo(); if (action != null) { if (Equal(self, action) && action.Action == ActionType.Move && self.ActionPoints < GetMoveCost()) { Go(ActionType.EndTurn); } else { Go(action.Action, new Point(action.X, action.Y)); } return; } } if (self.Type == TrooperType.FieldMedic) { var ifHelp = IfHelpTeammate(); if (ifHelp != null) { var goal = GetTrooperAt(ifHelp.X, ifHelp.Y); if (goal != null && goal.Hitpoints < goal.MaximalHitpoints && ifHelp.Nearest(self) && game.FieldMedicHealCost <= self.ActionPoints) { Go(ActionType.Heal, ifHelp); return; } if (IsCanMove()) { var to = GoToUnit(self, ifHelp, map, beginFree: true, endFree: true); if (to != null) { Go(ActionType.Move, to); return; } } } } var ifUseMedikit = IfUseMedikit(); if (ifUseMedikit != null) { Go(ActionType.UseMedikit, ifUseMedikit); return; } if (allowHill && IfRequestEnemyDisposition()) { Go(ActionType.RequestEnemyDisposition); return; } // Группировка if ((GetTeamRadius() > MaxTeamRadius && self.Id == commander.Id || GetTeamRadius() > MaxTeamRadius/2 && self.Id != commander.Id) && self.ActionPoints >= GetMoveCost()) { var bestTurn = new Point(0, 0, Inf); for (var i = 0; i < Width; i++) { for (var j = 0; j < Height; j++) { var r = Math.Max(MaxTeamRadius, GetTeamRadius(self.Id, new Point(i, j))); if (r < bestTurn.profit && r < GetTeamRadius()) { bestTurn.Set(i, j, r); } } } if (bestTurn.profit < Inf) { var to = GoScouting(bestTurn, PointGoal ?? (BonusGoal ?? bestTurn)); if (to != null) { Go(ActionType.Move, to); return; } } } Trooper whoseBonus = null; var ifTeamBonus = IfTeamBonus(ref whoseBonus, AllowTakeBonus); if (ifTeamBonus != null && BonusGoal == null && map[ifTeamBonus.X, ifTeamBonus.Y] == 0 && !Equal(ifTeamBonus, self)) { BonusGoal = ifTeamBonus; MyStrategy.WhoseBonus = whoseBonus.Id; } var waitingHelp = false; //allowHill && IfNeedHelp() && self.Type != TrooperType.FieldMedic && GetBestHelper() != null; var allowNothing = true; if (!waitingHelp && IsCanMove() && BonusGoal != null && MyStrategy.WhoseBonus == self.Id) { if (IsCanUpper()) { Go(ActionType.RaiseStance); return; } allowNothing = false; var to = GoScouting(BonusGoal, PointGoal ?? BonusGoal); //GoToUnit(self, BonusGoal, map, beginFree: true, endFree: false); // Если путь до бонуса пока что занят, то все равно идти к нему if (to == null) { to = GoToUnit(self, BonusGoal, notFilledMap, beginFree: true, endFree: true); if (to != null && map[to.X, to.Y] == 0 && self.ActionPoints >= 2 * GetMoveCost(self)) // TODO: ??? { Go(ActionType.Move, to); return; } } else { if (GetTeamRadius(self.Id, to) > MaxTeamRadius && GetTeamRadius() > GetTeamRadius(self.Id, to)) to = GoScouting(new Point(self), PointGoal ?? BonusGoal); Go(ActionType.Move, to); return; } } // Пытаюсь освободить дорогу до бонуса if (IsCanMove() && BonusGoal != null && MyStrategy.WhoseBonus != self.Id) { if (IsCanUpper()) { Go(ActionType.RaiseStance); return; } var bestTurn = SkipPath(GetTrooper(MyStrategy.WhoseBonus), PointGoal ?? BonusGoal); var to = bestTurn == null ? null : GoScouting(bestTurn, PointGoal ?? (BonusGoal ?? new Point(commander)));//GoToUnit(self, bestTurn, map, beginFree: true, endFree: false); if (to == null || Equal(to, self) && self.ActionPoints < GetMoveCost()) // если Equal(to, self)) тоже делаем move, иначе он не дойдет обратно Go(ActionType.EndTurn); else Go(ActionType.Move, to); return; } var ifNothing = IfNothing(); if (allowNothing && ifNothing != null && IsCanMove()) { if (IsCanUpper()) { Go(ActionType.RaiseStance); return; } Point to; if (self.Id == commander.Id) { to = GoToUnit(self, ifNothing, map, beginFree: true, endFree: false); if (GetTeamRadius(self.Id, to) > MaxTeamRadius) to = GoScouting(new Point(self), ifNothing); } else { to = GoScouting(ifNothing, ifNothing); } if (to == null || Equal(self, to) && self.ActionPoints < GetMoveCost()) { if (to == null && changedCommander == -1) { // значит мы застряли // передать коммандование ChangeCommander(); } else { Go(ActionType.EndTurn); return; } } else if (!waitingHelp) { Go(ActionType.Move, to); return; } } Point go = GoScouting(new Point(self), IfNothingCommander() ?? new Point(self)); // подумать что делать if (Equal(self, go) && self.ActionPoints < GetMoveCost()) Go(ActionType.EndTurn); else Go(ActionType.Move, go); }
private Trooper[] ReadTroopers() { int trooperCount = ReadInt(); if (trooperCount < 0) { return null; } Trooper[] troopers = new Trooper[trooperCount]; for (int trooperIndex = 0; trooperIndex < trooperCount; ++trooperIndex) { troopers[trooperIndex] = ReadTrooper(); } return troopers; }
// Основной метод public void Move(Trooper self, World world, Game game, Move move) { if (self.ActionPoints == 0) return; cnt_invoke = 0; m_self = self; m_game = game; m_world = world; m_cells = world.Cells; // Определение игрока-цели Player nearToCentr = null; foreach (Player p in world.Players) if (p.Id != self.PlayerId && p.ApproximateX >= 0 && p.ApproximateY >= 0) if (nearToCentr == null || FindNextStep(self.X, self.Y, nearToCentr.ApproximateX, nearToCentr.ApproximateY, 3).dist > FindNextStep(self.X, self.Y, p.ApproximateX, p.ApproximateY, 3).dist ) nearToCentr = p; if (nearToCentr != null) { targetX = nearToCentr.ApproximateX; targetY = nearToCentr.ApproximateY; } if (m_cellDangerous == null) CellDangerous(); if (targetX == -1 && targetY == -1) { targetX = self.X; targetY = self.Y; } // Запрос цели const double stageDist = 2.5; if (self.GetDistanceTo(targetX, targetY) <= stageDist || world.MoveIndex - moveWithoutEnemy >= 4) { bool CommanderAlive = false; foreach (Trooper tr in world.Troopers) if (tr.IsTeammate && tr.Type == TrooperType.Commander) CommanderAlive = true; if (!CommanderAlive) { targetX = random.Next(world.Width); targetY = random.Next(world.Height); moveWithoutEnemy = world.MoveIndex; } else if (self.Type == TrooperType.Commander && self.ActionPoints >= game.CommanderRequestEnemyDispositionCost) { move.Action = ActionType.RequestEnemyDisposition; moveWithoutEnemy = world.MoveIndex; return; } } // Заполнение списка солдат, определение отсутствия врагов if (self.ActionPoints >= self.InitialActionPoints) m_troopers = new ArrayList(); foreach (Trooper trooper in m_world.Troopers) { if (trooper.IsTeammate == false) moveWithoutEnemy = m_world.MoveIndex; bool isExist = false; for (int i = 0; i < m_troopers.Count; i++) { MyTrooper mt = (MyTrooper)m_troopers[i]; if (mt.Id == trooper.Id && mt.PlayerId == trooper.PlayerId) { isExist = true; m_troopers[i] = new MyTrooper(trooper); break; } } if (!isExist) m_troopers.Add(new MyTrooper(trooper)); } // Выбор оптимального действия Move m = FindNextMove(new MyTrooper(self), new ArrayList(m_world.Players), m_troopers, new ArrayList(m_world.Bonuses)).move; move.Action = m.Action; move.Direction = m.Direction; move.X = m.X; move.Y = m.Y; return; }
bool IfNeedHelp(Trooper self = null) { if (self == null) self = this.self; return self.Hitpoints / (double)self.MaximalHitpoints < 0.8; }
public MyTrooper(Trooper trooper) : base(trooper.Id, trooper.X, trooper.Y) { this.playerId = trooper.PlayerId; this.teammateIndex = trooper.TeammateIndex; this.isTeammate = trooper.IsTeammate; this.type = trooper.Type; this.stance = trooper.Stance; this.hitpoints = trooper.Hitpoints; this.maximalHitpoints = trooper.MaximalHitpoints; this.actionPoints = trooper.ActionPoints; this.initialActionPoints = trooper.InitialActionPoints; this.visionRange = trooper.VisionRange; this.shootingRange = trooper.ShootingRange; this.shootCost = trooper.ShootCost; this.standingDamage = trooper.StandingDamage; this.kneelingDamage = trooper.KneelingDamage; this.proneDamage = trooper.ProneDamage; this.damage = trooper.Damage; this.isHoldingGrenade = trooper.IsHoldingGrenade; this.isHoldingMedikit = trooper.IsHoldingMedikit; this.isHoldingFieldRation = trooper.IsHoldingFieldRation; }
Point GoToUnit(Trooper self, Point to, int[,] map, bool beginFree, bool endFree) { int distance = 0; return GoToUnit(new Point(self), to, map, beginFree, endFree, ref distance); }
Move BruteForceDo() { var fictive = 0; if (queue.Count < Team.Count()) { foreach (var tr in Team) { if (!queue.Contains(tr.Id)) { queue.Add(tr.Id); fictive++; } } } OpponentCommander = Opponents.FirstOrDefault(opp => opp.Type == TrooperType.Commander); state = new State(); state.Position = new Point[Team.Count()]; state.stance = new int[Team.Count()]; state.act = new int[Team.Count()]; state.hit = new int[Team.Count()]; state.medikit = new bool[Team.Count()]; state.grenade = new bool[Team.Count()]; Troopers = new Trooper[Team.Count()]; CommanderId = -1; foreach (var tr in troopers) { if (tr.IsTeammate) { int pos = GetQueuePlace2(tr, true) - 1; state.Position[pos] = new Point(tr); state.stance[pos] = GetStanceId(tr.Stance); state.medikit[pos] = tr.IsHoldingMedikit; state.grenade[pos] = tr.IsHoldingGrenade; Troopers[pos] = tr; if (tr.Type == TrooperType.Commander) CommanderId = pos; } } state.id = 0; state.profit = 0; state.act[0] = Troopers[0].ActionPoints; MyCount = state.Position.Count(); for(var i = 0; i < MyCount; i++) state.hit[i] = Troopers[i].Hitpoints; for (var i = 1; i < Troopers.Count(); i++) state.act[i] = getInitialActionPoints(Troopers[i]); stack = new ArrayList[MyCount]; bestStack = new ArrayList[MyCount]; for (var i = 0; i < MyCount; i++) { stack[i] = new ArrayList(); bestStack[i] = null; } bestProfit = -Inf; counter = 0; OpponentsCount = Opponents.Count(); MyCount = state.Position.Count(); Multiplier = Math.Min(MyCount, 3); state.opphit = new int[OpponentsCount]; probab = new double[OpponentsCount]; for (var i = 0; i < probab.Length; i++) probab[i] = 1.0; for (var i = 0; i < OpponentsCount; i++) { state.opphit[i] = Opponents[i].Hitpoints; // Чтобы уменьшить приоритет стрельбы в "мнимую" цель if (world.MoveIndex - OpponentsMemoryAppearTime[i] > 1) probab[i] /= 2; else if (OpponentsMemoryType[i] == self.Type && world.MoveIndex - OpponentsMemoryAppearTime[i] == 1) probab[i] /= 2; // TODO: можно точнее else if (!(OpponentsMemoryType[i] == self.Type || IsBetween(OpponentsMemoryType[i], self.Type, Opponents[i].Type))) probab[i] /= 2; } dfs_changeStance1(); // remove fictive from queue queue.RemoveRange(queue.Count - fictive, fictive); var move = new Move(); ReduceStack(bestStack[0]); if (bestStack[0].Count == 0) { // EndTurn bestStack[0].Add("at " + self.X + " " + self.Y); } var cmd = ((string)bestStack[0][0]).Split(' '); if (cmd[0] == "st") { // Change stance var ds = int.Parse(cmd[1]); if (ds < 0) move.Action = ActionType.LowerStance; else if (ds > 0) move.Action = ActionType.RaiseStance; else throw new InvalidDataException(); } else if (cmd[0] == "at") { var x = int.Parse(cmd[1]); var y = int.Parse(cmd[2]); var to = bestStack[0].Count == 1 ? GoScouting(new Point(x, y), new Point(Opponents[0]), changeStanceAllow: true) : GoToUnit(self, new Point(x, y), map, beginFree: true, endFree: false); if (to.X == -1) move.Action = to.Y == -1 ? ActionType.LowerStance : ActionType.RaiseStance; else { move.Action = ActionType.Move; move.X = to.X; move.Y = to.Y; } } else if (cmd[0] == "sh") { var x = int.Parse(cmd[1]); var y = int.Parse(cmd[2]); move.Action = ActionType.Shoot; move.X = x; move.Y = y; } else if (cmd[0] == "med") { var to = new Point(int.Parse(cmd[1]), int.Parse(cmd[2])); move.Action = ActionType.UseMedikit; move.X = to.X; move.Y = to.Y; } else if (cmd[0] == "gr") { var to = new Point(int.Parse(cmd[1]), int.Parse(cmd[2])); move.Action = ActionType.ThrowGrenade; move.X = to.X; move.Y = to.Y; } else if (cmd[0] == "heal") { var to = new Point(int.Parse(cmd[1]), int.Parse(cmd[2])); move.Action = ActionType.Heal; move.X = to.X; move.Y = to.Y; } else { throw new NotImplementedException(cmd.ToString()); } return move; }
bool IsHaveBonus(Trooper self, Bonus bonus) { return bonus != null && IsHaveBonus(self, bonus.Type); }
Point SkipPath(Trooper center, Point goal) { // В первую очередь минимизировать путь center до goal var bestPoint = new Point(0, 0, Inf); double minPenalty = Inf; for (var i = 0; i < Width; i++) { for (var j = 0; j < Height; j++) { if (map[i, j] == 0 || i == self.X && j == self.Y) { if (self.GetDistanceTo(i, j) > 10) // немного ускорит continue; // Нужно чтобы хватило ходов int steps = GetShoterPath(self, new Point(i, j), map, beginFree: true, endFree: true); if (self.ActionPoints / GetMoveCost() >= steps) { // и чтобы не закрывали кратчайший путь: map[self.X, self.Y] = 0; map[i, j] = 1; int after = GetShoterPath(center, goal, map, beginFree: true, endFree: false); map[i, j] = 0; map[self.X, self.Y] = 1; double penalty = GetShoterPath(center, new Point(i, j), notFilledMap, beginFree: true, endFree: true); penalty += 2*Math.Max(0, goal.GetDistanceTo(center) - goal.GetDistanceTo(i, j) + 1); if (after < bestPoint.profit || EqualF(after, bestPoint.profit) && penalty < minPenalty) { bestPoint = new Point(i, j, after); minPenalty = penalty; } } } } } return bestPoint.profit >= Inf ? null : bestPoint; }
bool IsHaveBonus(Trooper self, BonusType bonus) { if (bonus == BonusType.Medikit) return self.IsHoldingMedikit; if (bonus == BonusType.Grenade) return self.IsHoldingGrenade; if (bonus == BonusType.FieldRation) return self.IsHoldingFieldRation; throw new InvalidDataException(); }
int getInitialActionPoints(Trooper tr) { var points = tr.InitialActionPoints; if (CommanderId != -1 && tr.GetDistanceTo(state.Position[CommanderId].X, state.Position[CommanderId].Y) <= game.CommanderAuraRange) points += game.CommanderAuraBonusActionPoints; return points; }
int GetShoterPath(Trooper self, Point to, int[,] map, bool beginFree, bool endFree) { int distance = 0; GoToUnit(new Point(self), to, map, beginFree, endFree, ref distance); return distance; }