|
|
@ -104,14 +104,59 @@ fn readNumber(comptime T: type, line: []const u8, index: *usize) T { |
|
|
|
return if (is_negative) (0 - result) else result; |
|
|
|
return if (is_negative) (0 - result) else result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn GenericTerrain(comptime CoordinateType: type, comptime height: CoordinateType, comptime width: CoordinateType, comptime CellType: type) type { |
|
|
|
fn Coordinates(comptime CoordinateType: type) type { |
|
|
|
return struct { |
|
|
|
return struct { |
|
|
|
const Self = @This(); |
|
|
|
const Self = @This(); |
|
|
|
x: CoordinateType, |
|
|
|
x: CoordinateType, |
|
|
|
y: CoordinateType, |
|
|
|
y: CoordinateType, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn isSameX(self: *const Self, other: Self) bool { |
|
|
|
|
|
|
|
return self.x == other.x; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn approachX(self: *Self, other: Self) void { |
|
|
|
|
|
|
|
if (self.x < other.x) { |
|
|
|
|
|
|
|
self.x += 1; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
self.x -= 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn isSameY(self: *const Self, other: Self) bool { |
|
|
|
|
|
|
|
return self.y == other.y; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn approachY(self: *Self, other: Self) void { |
|
|
|
|
|
|
|
if (self.y < other.y) { |
|
|
|
|
|
|
|
self.y += 1; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
self.y -= 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn GenericTerrain(comptime CoordinateType: type, comptime height: CoordinateType, comptime width: CoordinateType, comptime CellType: type) type { |
|
|
|
|
|
|
|
return struct { |
|
|
|
|
|
|
|
const Self = @This(); |
|
|
|
|
|
|
|
coordinates: Coordinates(CoordinateType), |
|
|
|
cells: [height][width]CellType, |
|
|
|
cells: [height][width]CellType, |
|
|
|
fn initZeroes() Self { |
|
|
|
fn initZeroes() Self { |
|
|
|
return .{ .x = height / 2, .y = width / 2, .cells = std.mem.zeroes([height][width]CellType) }; |
|
|
|
return .{ |
|
|
|
|
|
|
|
.coordinates = .{ |
|
|
|
|
|
|
|
.x = height / 2, |
|
|
|
|
|
|
|
.y = width / 2, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
.cells = std.mem.zeroes([height][width]CellType), |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn getCurrentCell(self: *const Self) CellType { |
|
|
|
|
|
|
|
return self.cells[self.coordinates.x][self.coordinates.y]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn setCurrentCell(self: *Self, value: CellType) void { |
|
|
|
|
|
|
|
self.cells[self.coordinates.x][self.coordinates.y] = value; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
@ -126,10 +171,7 @@ const TerrainCoordinate = u16; |
|
|
|
|
|
|
|
|
|
|
|
const Terrain = GenericTerrain(TerrainCoordinate, 1024, 1024, CellStatus); |
|
|
|
const Terrain = GenericTerrain(TerrainCoordinate, 1024, 1024, CellStatus); |
|
|
|
|
|
|
|
|
|
|
|
const FloodTask = struct { |
|
|
|
const TerrainCoordinates = Coordinates(TerrainCoordinate); |
|
|
|
x: TerrainCoordinate, |
|
|
|
|
|
|
|
y: TerrainCoordinate, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Direction = enum(u8) { |
|
|
|
const Direction = enum(u8) { |
|
|
|
Right = 0, |
|
|
|
Right = 0, |
|
|
@ -140,24 +182,26 @@ const Direction = enum(u8) { |
|
|
|
|
|
|
|
|
|
|
|
const Command = packed struct(u32) { |
|
|
|
const Command = packed struct(u32) { |
|
|
|
direction: Direction, |
|
|
|
direction: Direction, |
|
|
|
length: u24, |
|
|
|
_: u8 = 0, |
|
|
|
|
|
|
|
length: u16, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
fn floodTerrain(terrain: *Terrain) void { |
|
|
|
fn floodTerrain(terrain: *Terrain) void { |
|
|
|
var queue_mem: [65_536]FloodTask = undefined; |
|
|
|
var queue_mem: [65_536]TerrainCoordinates = undefined; |
|
|
|
var tasks = RingQueueWrapper(FloodTask, queue_mem.len).init(&queue_mem); |
|
|
|
var tasks = RingQueueWrapper(TerrainCoordinates, queue_mem.len).init(&queue_mem); |
|
|
|
|
|
|
|
|
|
|
|
tasks.add(.{ .x = 0, .y = 0 }); |
|
|
|
tasks.add(.{ .x = 0, .y = 0 }); |
|
|
|
|
|
|
|
|
|
|
|
while (!tasks.isEmpty()) { |
|
|
|
while (!tasks.isEmpty()) { |
|
|
|
const task = tasks.take(); |
|
|
|
const task = tasks.take(); |
|
|
|
const x = task.x; |
|
|
|
terrain.coordinates = task; |
|
|
|
const y = task.y; |
|
|
|
|
|
|
|
//std.debug.print("Processing task for {d},{d} (current status: {any})\n", .{ x, y, terrain.*.cells[x][y] }); |
|
|
|
//std.debug.print("Processing task for {d},{d} (current status: {any})\n", .{ x, y, terrain.*.cells[x][y] }); |
|
|
|
if (terrain.*.cells[x][y] == .Default) { |
|
|
|
if (terrain.getCurrentCell() == .Default) { |
|
|
|
terrain.*.cells[x][y] = .NotDug; |
|
|
|
terrain.setCurrentCell(.NotDug); |
|
|
|
//std.debug.print("Marked {d},{d} as NotDug\n", .{ x, y }); |
|
|
|
//std.debug.print("Marked {d},{d} as NotDug\n", .{ x, y }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const x = task.x; |
|
|
|
|
|
|
|
const y = task.y; |
|
|
|
if (x > 0) { |
|
|
|
if (x > 0) { |
|
|
|
tasks.add(.{ .x = x - 1, .y = y }); |
|
|
|
tasks.add(.{ .x = x - 1, .y = y }); |
|
|
|
} |
|
|
|
} |
|
|
@ -194,43 +238,38 @@ fn solveForTerrain(terrain: *Terrain) usize { |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn dig(terrain: *Terrain, command: Command) void { |
|
|
|
fn getTargetCoordinates(coordinates: TerrainCoordinates, command: Command) TerrainCoordinates { |
|
|
|
const target_x = switch (command.direction) { |
|
|
|
return .{ |
|
|
|
.Right => terrain.*.x + command.length, |
|
|
|
.x = switch (command.direction) { |
|
|
|
.Left => terrain.*.x - command.length, |
|
|
|
.Right => coordinates.x + command.length, |
|
|
|
.Up, .Down => terrain.*.x, |
|
|
|
.Left => coordinates.x - command.length, |
|
|
|
}; |
|
|
|
.Up, .Down => coordinates.x, |
|
|
|
|
|
|
|
}, |
|
|
|
const target_y = switch (command.direction) { |
|
|
|
.y = switch (command.direction) { |
|
|
|
.Down => terrain.*.y + command.length, |
|
|
|
.Down => coordinates.y + command.length, |
|
|
|
.Up => terrain.*.y - command.length, |
|
|
|
.Up => coordinates.y - command.length, |
|
|
|
.Left, .Right => terrain.*.y, |
|
|
|
.Left, .Right => coordinates.y, |
|
|
|
|
|
|
|
}, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
while (terrain.*.x != target_x) { |
|
|
|
|
|
|
|
if (terrain.*.x < target_x) { |
|
|
|
|
|
|
|
terrain.*.x += 1; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
terrain.*.x -= 1; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
terrain.*.cells[terrain.*.x][terrain.*.y] = .Dug; |
|
|
|
fn dig(terrain: *Terrain, command: Command) void { |
|
|
|
} |
|
|
|
const target = getTargetCoordinates(terrain.*.coordinates, command); |
|
|
|
|
|
|
|
|
|
|
|
while (terrain.*.y != target_y) { |
|
|
|
while (!terrain.*.coordinates.isSameX(target)) { |
|
|
|
if (terrain.*.y < target_y) { |
|
|
|
terrain.*.coordinates.approachX(target); |
|
|
|
terrain.*.y += 1; |
|
|
|
terrain.*.setCurrentCell(.Dug); |
|
|
|
} else { |
|
|
|
|
|
|
|
terrain.*.y -= 1; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
terrain.*.cells[terrain.*.x][terrain.*.y] = .Dug; |
|
|
|
while (!terrain.*.coordinates.isSameY(target)) { |
|
|
|
|
|
|
|
terrain.*.coordinates.approachY(target); |
|
|
|
|
|
|
|
terrain.*.setCurrentCell(.Dug); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn parseCommand(command: []const u8) Command { |
|
|
|
fn parseCommand(command: []const u8) Command { |
|
|
|
var index: usize = 2; |
|
|
|
var index: usize = 2; |
|
|
|
const length = readNumber(u24, command, &index); |
|
|
|
const length = readNumber(u16, command, &index); |
|
|
|
const direction: Direction = switch (command[0]) { |
|
|
|
const direction: Direction = switch (command[0]) { |
|
|
|
'R' => .Right, |
|
|
|
'R' => .Right, |
|
|
|
'L' => .Left, |
|
|
|
'L' => .Left, |
|
|
|