private static IEnumerable<Vector> GetElements(Map map, Predicate<MapCell> predicate) { for(int i = 0; i < map.Width; i++) for(int j = 0; j < map.Height; j++) if(predicate(map.GetCell(i, j))) yield return new Vector(i, j); }
private void Update(Map newMap) { var robotFailed = false; var activeMoves = new SortedSet<Tuple<Vector, Vector, MapCell>>(new TupleVectorComparer()); foreach (var rockPos in activeRocks.Concat(newMap.activeRocks).Distinct()) { var cell = newMap.GetCell(rockPos); var rockMove = TryToMoveRock(rockPos, cell, newMap); if (rockMove == null) continue; var newRockPos = rockPos.Add(rockMove); if (cell == MapCell.LambdaRock && newMap.GetCell(newRockPos.Sub(new Vector(0, 1))) != MapCell.Empty) activeMoves.Add(Tuple.Create(rockPos, newRockPos, MapCell.Lambda)); else activeMoves.Add(Tuple.Create(rockPos, newRockPos, cell)); } newMap.GrowthLeft--; if (newMap.GrowthLeft == 0) { newMap.GrowthLeft = newMap.Growth; foreach (var beardPos in newMap.Beard) for (var x = -1; x <= 1; x++) for (var y = -1; y <= 1; y++) { var newBeardPos = beardPos.Add(new Vector(x, y)); if (newMap.GetCell(newBeardPos) == MapCell.Empty) activeMoves.Add(Tuple.Create(beardPos, newBeardPos, MapCell.Beard)); } } var newActiveRocks = new SortedSet<Vector>(new VectorComparer()); foreach (var activeMove in activeMoves) { var fromPos = activeMove.Item1; var toPos = activeMove.Item2; var fromCell = newMap.GetCell(fromPos); var toCell = newMap.GetCell(toPos); if (fromCell.IsRock()) { if (!toCell.IsRock()) newActiveRocks.Add(toPos); newMap.field = newMap.SetCell(toPos, activeMove.Item3); newMap.field = newMap.SetCell(fromPos, MapCell.Empty); robotFailed |= IsRobotKilledByRock(toPos.X, toPos.Y, newMap); CheckNearRocks(newActiveRocks, fromPos.X, fromPos.Y, newMap); newMap.Beard.Remove(toPos); } else if(fromCell == MapCell.Beard) { newMap.field = newMap.SetCell(toPos, MapCell.Beard); newMap.Beard.Add(toPos); } } newMap.activeRocks = newActiveRocks; if (newMap.TotalLambdaCount == newMap.LambdasGathered) newMap.field = newMap.SetCell(Lift, MapCell.OpenedLift); robotFailed |= IsRobotKilledByFlood(newMap); if (robotFailed) newMap.State = CheckResult.Fail; }
private static Vector TryToMoveRock(Vector p, MapCell xyCell, Map mapToUse) { int x = p.X; int y = p.Y; if (xyCell.IsRock()) { var upCell = mapToUse.GetCell(x, y - 1); if (upCell == MapCell.Empty) { return new Vector(0, -1); } if (upCell.IsRock() && mapToUse.GetCell(x + 1, y) == MapCell.Empty && mapToUse.GetCell(x + 1, y - 1) == MapCell.Empty) { return new Vector(1, -1); } if (upCell.IsRock() && (mapToUse.GetCell(x + 1, y) != MapCell.Empty || mapToUse.GetCell(x + 1, y - 1) != MapCell.Empty) && mapToUse.GetCell(x - 1, y) == MapCell.Empty && mapToUse.GetCell(x - 1, y - 1) == MapCell.Empty) { return new Vector(-1, -1); } if (upCell == MapCell.Lambda && mapToUse.GetCell(x + 1, y) == MapCell.Empty && mapToUse.GetCell(x + 1, y - 1) == MapCell.Empty) { return new Vector(1, -1); } } return null; }
private static bool IsRobotKilledByRock(int x, int y, Map mapToUse) { return mapToUse.GetCell(x, y - 1) == MapCell.Robot; }
private static void CheckNearRocks(SortedSet<Vector> updateableRocks, int x, int y, Map mapToUse) { for (var rockX = x - 1; rockX <= x + 1; rockX++) for (var rockY = y; rockY <= y + 1; rockY++) { var rockPos = new Vector(rockX, rockY); if (TryToMoveRock(rockPos, mapToUse.GetCell(rockPos), mapToUse) != null) updateableRocks.Add(rockPos); } }
private RobotMove FindMovableRock(Map map) { var left = new Vector(-1, 0); var right = new Vector(1, 0); var up = new Vector(0, 1); var leftRobot = map.Robot.Add(left); var rightRobot = map.Robot.Add(right); var upRobot = map.Robot.Add(up); var leftCheck = map.GetCell(leftRobot) != MapCell.Wall && map.IsSafeMove(map.Robot, map.Robot.Add(left), 1, map.WaterproofLeft); var rightCheck = map.GetCell(rightRobot) != MapCell.Wall && map.IsSafeMove(map.Robot, map.Robot.Add(right), 1, map.WaterproofLeft); if (map.GetCell(leftRobot).IsRock() && map.GetCell(leftRobot.Add(left)) == MapCell.Empty && leftCheck) return RobotMove.Left; if (map.GetCell(rightRobot).IsRock() && map.GetCell(rightRobot.Add(right)) == MapCell.Empty && rightCheck) return RobotMove.Right; if (map.GetCell(upRobot).IsRock() && map.GetCell(leftRobot).IsMovable() && leftCheck) return RobotMove.Left; if (map.GetCell(upRobot).IsRock() && map.GetCell(rightRobot).IsMovable() && rightCheck) return RobotMove.Right; var waveRun = new WaveRun(map, map.Robot); moveRockTarget = waveRun.EnumerateTargets( (lmap, position, used) => { if (lmap.GetCell(position.Add(up)).IsRock() && (lmap.GetCell(position.Add(left)).IsMovable() || lmap.GetCell(position.Add(right)).IsMovable())) return true; if (lmap.GetCell(position).IsMovable() && lmap.GetCell(position.Add(left)).IsRock() && lmap.GetCell(position.Add(left).Add(left)).IsRockMovable()) return true; if (lmap.GetCell(position).IsMovable() && lmap.GetCell(position.Add(right)).IsRock() && lmap.GetCell(position.Add(right).Add(right)).IsRockMovable()) return true; if (lmap.GetCell(position) == MapCell.Earth && lmap.GetCell(position.Add(right)).IsRock() && lmap.GetCell(position.Add(right).Add(right)) != MapCell.Wall && !lmap.GetCell(position.Add(right).Add(right)).IsRock()) return true; if (lmap.GetCell(position) == MapCell.Earth && lmap.GetCell(position.Add(left)).IsRock() && lmap.GetCell(position.Add(right).Add(right)) != MapCell.Wall && !lmap.GetCell(position.Add(right).Add(right)).IsRock()) return true; return false; }).FirstOrDefault(); if(moveRockTarget == null) return RobotMove.Abort; return moveRockTarget.Item2.Any() ? moveRockTarget.Item2.Peek() : RobotMove.Abort; }
private Tuple<Vector, Stack<RobotMove>> FindBestTarget(Map map, bool checkBestIsNotBad = true) { var waveRun = new WaveRun(map, map.Robot, checkBestIsNotBad ? 400000 : 1000); Tuple<Vector, Stack<RobotMove>> result = null; if(checkBestIsNotBad) { var orderedMoves = waveRun .EnumerateTargets((lmap, pos, stepNumber) => lmap.GetCell(pos) == MapCell.Lambda || (lmap.LambdasGathered != lmap.TotalLambdaCount && lmap.GetCell(pos) == MapCell.Razor)) .Where(tuple => specialTargetType != SpecialTargetType.Banned || specialTarget == null || (tuple.Item1.X != specialTarget.X && tuple.Item1.Y != specialTarget.Y)) .Take(9) .OrderBy(t => CalculateTargetBadness(t, map)).ToArray(); result = orderedMoves.FirstOrDefault(); } else result = waveRun.EnumerateTargets((lmap, pos, stepNumber) => lmap.GetCell(pos) == MapCell.Lambda || (lmap.LambdasGathered != lmap.TotalLambdaCount && lmap.GetCell(pos) == MapCell.Razor)).FirstOrDefault(); if(result != null) return result; if(waveRun.Lift != null && map.GetCell(waveRun.Lift.Item1) == MapCell.OpenedLift) return waveRun.Lift; return null; }