|
|
|
@ -119,6 +119,39 @@ fn readNumber(comptime T: type, line: []const u8, index: *usize) T { |
|
|
|
|
return if (is_negative) (0 - result) else result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn readHexNumber(comptime T: type, line: []const u8, index: *usize) T { |
|
|
|
|
var result: T = 0; |
|
|
|
|
while (index.* < line.len and line[index.*] == ' ') : (index.* += 1) {} |
|
|
|
|
|
|
|
|
|
var is_negative = false; |
|
|
|
|
if (index.* < line.len and line[index.*] == '-') { |
|
|
|
|
is_negative = true; |
|
|
|
|
index.* += 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std.debug.assert(index.* < line.len); |
|
|
|
|
|
|
|
|
|
while (index.* < line.len) : (index.* += 1) { |
|
|
|
|
const char = line[index.*]; |
|
|
|
|
switch (char) { |
|
|
|
|
'0'...'9' => { |
|
|
|
|
result = result * 16 + (char - '0'); |
|
|
|
|
}, |
|
|
|
|
'a'...'f' => { |
|
|
|
|
result = result * 16 + 10 + (char - 'a'); |
|
|
|
|
}, |
|
|
|
|
'A'...'F' => { |
|
|
|
|
result = result * 16 + 10 + (char - 'A'); |
|
|
|
|
}, |
|
|
|
|
else => { |
|
|
|
|
break; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return if (is_negative) (0 - result) else result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn Coordinates(comptime CoordinateType: type) type { |
|
|
|
|
return struct { |
|
|
|
|
const Self = @This(); |
|
|
|
@ -184,7 +217,7 @@ const CellStatus = enum(u2) { |
|
|
|
|
|
|
|
|
|
const TerrainCoordinate = u16; |
|
|
|
|
|
|
|
|
|
const Terrain = GenericTerrain(TerrainCoordinate, 1024, 1024, CellStatus); |
|
|
|
|
const Terrain = GenericTerrain(TerrainCoordinate, 2048, 2048, CellStatus); |
|
|
|
|
|
|
|
|
|
const TerrainCoordinates = Coordinates(TerrainCoordinate); |
|
|
|
|
|
|
|
|
@ -195,12 +228,14 @@ const Direction = enum(u8) { |
|
|
|
|
Up = 3, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const RawCoordinate = u32; |
|
|
|
|
|
|
|
|
|
const RawCommand = packed struct(u32) { |
|
|
|
|
direction: Direction, |
|
|
|
|
length: u24, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const RawCoordinates = Coordinates(u24); |
|
|
|
|
const RawCoordinates = Coordinates(RawCoordinate); |
|
|
|
|
|
|
|
|
|
fn floodTerrain(terrain: *Terrain) void { |
|
|
|
|
var queue_mem: [65_536]TerrainCoordinates = undefined; |
|
|
|
@ -238,7 +273,7 @@ fn floodTerrain(terrain: *Terrain) void { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn getTargetRawCoordinates(coordinates: RawCoordinates, command: RawCommand) RawCoordinates { |
|
|
|
|
return @TypeOf(coordinates){ |
|
|
|
|
return RawCoordinates{ |
|
|
|
|
.x = switch (command.direction) { |
|
|
|
|
.Right => coordinates.x + command.length, |
|
|
|
|
.Left => coordinates.x - command.length, |
|
|
|
@ -252,8 +287,8 @@ fn getTargetRawCoordinates(coordinates: RawCoordinates, command: RawCommand) Raw |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn getCoordinate(known_values: []const u24, raw_coordinate: u24) TerrainCoordinate { |
|
|
|
|
const maybe_index = std.sort.binarySearch(u24, raw_coordinate, known_values, {}, Order(u24).order); |
|
|
|
|
fn getCoordinate(known_values: []const RawCoordinate, raw_coordinate: RawCoordinate) TerrainCoordinate { |
|
|
|
|
const maybe_index = std.sort.binarySearch(RawCoordinate, raw_coordinate, known_values, {}, Order(RawCoordinate).order); |
|
|
|
|
return @as(TerrainCoordinate, @intCast(maybe_index.?)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -263,12 +298,12 @@ fn solveForCommands(raw_commands: []const RawCommand) usize { |
|
|
|
|
.x = start_value, |
|
|
|
|
.y = start_value, |
|
|
|
|
}; |
|
|
|
|
var known_values = StackList(u24, u16, 2048).init(); |
|
|
|
|
var known_values = StackList(RawCoordinate, u16, 2048).init(); |
|
|
|
|
known_values.addUnique(0); |
|
|
|
|
known_values.addUnique(start_value - 1); |
|
|
|
|
known_values.addUnique(start_value); |
|
|
|
|
known_values.addUnique(start_value + 1); |
|
|
|
|
known_values.addUnique(std.math.maxInt(u24)); |
|
|
|
|
known_values.addUnique(std.math.maxInt(RawCoordinate)); |
|
|
|
|
for (raw_commands) |raw_command| { |
|
|
|
|
raw_coordinates = getTargetRawCoordinates(raw_coordinates, raw_command); |
|
|
|
|
known_values.addUnique(raw_coordinates.x - 1); |
|
|
|
@ -279,7 +314,7 @@ fn solveForCommands(raw_commands: []const RawCommand) usize { |
|
|
|
|
known_values.addUnique(raw_coordinates.y + 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std.sort.heap(u24, known_values.getMutableSlice(), {}, std.sort.asc(u24)); |
|
|
|
|
std.sort.heap(RawCoordinate, known_values.getMutableSlice(), {}, std.sort.asc(RawCoordinate)); |
|
|
|
|
|
|
|
|
|
var known_values_slice = known_values.getSlice(); |
|
|
|
|
|
|
|
|
@ -331,17 +366,19 @@ fn solveForCommands(raw_commands: []const RawCommand) usize { |
|
|
|
|
|
|
|
|
|
fn parseCommand(command: []const u8) RawCommand { |
|
|
|
|
var index: usize = 2; |
|
|
|
|
const length = readNumber(u24, command, &index); |
|
|
|
|
const direction: Direction = switch (command[0]) { |
|
|
|
|
'R' => .Right, |
|
|
|
|
'L' => .Left, |
|
|
|
|
'U' => .Up, |
|
|
|
|
'D' => .Down, |
|
|
|
|
_ = readNumber(u8, command, &index); |
|
|
|
|
index += 3; |
|
|
|
|
const value = readHexNumber(u24, command, &index); |
|
|
|
|
const direction: Direction = switch (value % 16) { |
|
|
|
|
0 => .Right, |
|
|
|
|
1 => .Down, |
|
|
|
|
2 => .Left, |
|
|
|
|
3 => .Up, |
|
|
|
|
else => unreachable, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
return .{ |
|
|
|
|
.length = length, |
|
|
|
|
.length = value / 16, |
|
|
|
|
.direction = direction, |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|