private static double GetAdjacencyBonus(Field field, Unit unit, ExecutionOptions options) { double downBonus = options.AdjacencyDownRatio; double sideBonus = options.AdjacencySideRatio; double result = 0; foreach (var m in unit.Members) { if (m.Y < field.Height - 1) { if (field[m.Translate(MoveDirection.SouthEast)]) { result += downBonus; } else { result -= downBonus; } if (field[m.Translate(MoveDirection.SouthWest)]) { result += downBonus; } else { result -= downBonus; } } if (m.X < field.Width - 1 && field[m.Translate(MoveDirection.East)]) result += sideBonus; if (m.X > 0 && field[m.Translate(MoveDirection.West)]) result += sideBonus; } return result; }
/// <summary> /// Initial constructor. /// </summary> public Snapshot(Input input, uint seed) { Field = new Field(input); UnitsQueue = new UnitsQueue(input.Units, seed, input.SourceLength); CurrentUnit = Field.Spawn(UnitsQueue.Get(0)); UnitHistory = new List<Unit> { CurrentUnit }; Score = 0; FieldEstimate = 0; }
private static double CornerCellsBonus(Field field) { double result = 0; if (field[field.Width - 1, field.Height - 1]) result += 1; if (field[0, field.Height - 1]) result += 1; return result; }
/// <summary> /// Copy constructor. /// </summary> internal Snapshot(Snapshot other) { CurrentUnit = other.CurrentUnit; Field = new Field(other.Field); Finished = other.Finished; Score = other.Score; UnitIndex = other.UnitIndex; UnitsQueue = other.UnitsQueue; UnitHistory = new List<Unit>(other.UnitHistory); FieldEstimate = other.FieldEstimate; PrevUnitClearedLines = other.PrevUnitClearedLines; }
private static HashSet<Position> GetFilledCells(Field field) { var result = new HashSet<Position>(); for (var x = 0; x < field.Width; x++) { for (var y = 0; y < field.Height; y++) { if (field[x, y]) { result.Add(new Position(x, y)); } } } return result; }
private static bool HasCollision(Field field, Unit unit) { var filled = GetFilledCells(field); foreach (var member in unit.Members) { if (member.X < 0 || member.Y < 0 || member.X >= field.Width || member.Y >= field.Height) { return true; } if (filled.Contains(member)) { return true; } } return false; }
public void DrawUnit(Field field, Unit unit, int? unitIndex) { var nodeWidth = GetNodeWidth(field.Width); var nodeHeight = GetNodeHeight(field.Height); Draw(field, nodeWidth, nodeHeight); if (unit.Members != null) { var color = HasCollision(field, unit) ? Colors.Red : Colors.Green; // Render unit foreach (var memberPos in unit.Members) { DrawMember(memberPos, nodeWidth, nodeHeight, 16, color, null); } DrawMember(unit.Pivot, nodeWidth, nodeHeight, 24, Colors.Black, unitIndex.HasValue ? unitIndex.Value.ToString() : null); } }
public Field(Field other) { Width = other.Width; Height = other.Height; Cells = other.Cells.ToArray(); }
private void Draw(Field field, double nodeWidth, double nodeHeight) { host.Children.Clear(); var padded = false; var filledHash = GetFilledCells(field); // Render hexs for (var topIdx = 0; topIdx < field.Height; topIdx++) { for (var leftIdx = 0; leftIdx < field.Width; leftIdx++) { DrawHex(leftIdx, topIdx, nodeWidth, nodeHeight, 4, padded, filledHash.Contains(new Position { X = leftIdx, Y = topIdx}) ? Colors.Blue : Colors.LightBlue); } padded = !padded; } }
private static double GetUnitPositionBonus( Field field, Unit unit, ExecutionOptions options) { int minX = unit.GetMinX(); int maxX = unit.GetMaxX(); int minY = unit.GetMinY(); int maxY = unit.GetMaxY(); int depth = field.Height - minY; int width = maxX - maxY; int marginBottom = field.Height - maxY; int center = (maxX + minX) / 2; var attractor = GetBottomOpenPosition(field); double attractorDistance = Math.Abs(attractor.X - unit.Pivot.X); // attractor.DistanceTo(unit.Pivot); double depthPenalty = 0; foreach (var member in unit.Members) { depthPenalty += field.Height - 1 - member.Y; } int edgeBonus = 0; foreach (var position in unit.Members) { if (position.X == 0 || position.X == field.Width - 1) edgeBonus += 1; } double adjacencyBonus = GetAdjacencyBonus(field, unit, options); return edgeBonus * options.EdgeRatio + adjacencyBonus - depthPenalty * options.DepthPenaltyRatio - attractorDistance * options.AttractorRatio; }
private static double GetHiddenHoles(Field field) { int result = 0; for (int y = 0; y < field.Height - 1; y++) { for (int x = 0; x < field.Width - 1; x++) { if (field[x, y] && field[x + 1, y]) { var underCell = new Position(x, y).Translate(MoveDirection.SouthEast); if (!field[underCell]) result++; } } } return result; }
private static double GetFieldEstimate(Field field, ExecutionOptions options) { return CornerCellsBonus(field) * options.CornerCellsBonus - GetHiddenHoles(field) * options.HiddenHolesPenalty; }
/*private static Position GetBottomOpenPosition(Field field) { Position min = new Position(-1, field.Height); for (int x = 0; x < field.Width; x++) { int y = 0; // drop down until cells is empty while (y < field.Height && !field[x, y]) { y++; } if (y <= min.Y) { min = new Position(x, y); } } return min; }*/ private static unsafe Position GetBottomOpenPosition(Field field) { var w = field.Width; var h = field.Height; fixed (byte* ptr = field.Cells) { Position min = new Position(-1, h); for (int x = 0; x < w; x++) { int y = 0; // drop down until cells is empty var offset = x + y * w; var v = ptr[offset >> 3] & (1 << (offset & 7)); while (y < h && v != 0) { y++; } if (y <= min.Y) { min = new Position(x, y); } } return min; } }