198 lines
6.6 KiB
Zig
198 lines
6.6 KiB
Zig
const std = @import("std");
|
|
|
|
pub fn main() anyerror!void {
|
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
defer arena.deinit();
|
|
var gpa = &arena.allocator;
|
|
|
|
var f = try std.fs.cwd().openFile("input", .{});
|
|
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
|
|
defer gpa.free(contents);
|
|
|
|
var ship = ShipPosition{};
|
|
var it = std.mem.tokenize(contents, "\n");
|
|
while (it.next()) |line| {
|
|
ship.update(line[0], try std.fmt.parseInt(i64, line[1..], 10));
|
|
std.log.debug("After '{}', ship at ({}, {}) facing {}",
|
|
.{line, ship.position[0], ship.position[1], ship.facing});
|
|
}
|
|
std.log.info("Ship is at ({},{}) facing {}. It has travalled {} manhattan distance from start",
|
|
.{ship.position[0], ship.position[1], ship.facing,
|
|
ship.manhattan_distance_from([_]i64{0, 0})});
|
|
|
|
// Part 2
|
|
ship = ShipPosition{};
|
|
it = std.mem.tokenize(contents, "\n");
|
|
while (it.next()) |line| {
|
|
ship.update_part2(line[0], try std.fmt.parseInt(i64, line[1..], 10));
|
|
std.log.debug("After '{}', ship at ({}, {}), with waypoint ({}, {})",
|
|
.{line, ship.position[0], ship.position[1],
|
|
ship.waypoint[0], ship.waypoint[1]});
|
|
}
|
|
std.log.info("Ship is at ({},{}) facing {} and waypoint ({}, {}). It has travalled {} manhattan distance from start",
|
|
.{ship.position[0], ship.position[1], ship.facing,
|
|
ship.waypoint[0], ship.waypoint[1],
|
|
ship.manhattan_distance_from([_]i64{0, 0})});
|
|
}
|
|
|
|
const ShipPosition = struct {
|
|
facing : i64 = 90,
|
|
position : [2]i64 = [_]i64{0, 0},
|
|
waypoint: [2]i64 = [_]i64{10, 1},
|
|
|
|
pub fn update(self: *ShipPosition, command: u8, value: i64) void {
|
|
switch(command) {
|
|
'N' => {
|
|
self.position[1] += value;
|
|
},
|
|
'S' => {
|
|
self.position[1] -= value;
|
|
},
|
|
'E' => {
|
|
self.position[0] += value;
|
|
},
|
|
'W' => {
|
|
self.position[0] -= value;
|
|
},
|
|
'R' => {
|
|
self.facing += value;
|
|
},
|
|
'L' => {
|
|
self.facing -= value;
|
|
},
|
|
'F' => {
|
|
std.log.debug("Facing before moving forward: {}", .{self.facing});
|
|
while (self.facing < 0) {
|
|
self.facing += 360;
|
|
}
|
|
if (self.facing >= 360) {
|
|
self.facing = @intCast(i64, @mod(self.facing, 360));
|
|
}
|
|
std.log.debug("Facing after normalizing, before moving forward: {}",
|
|
.{self.facing});
|
|
var c : u8 = switch(self.facing) {
|
|
0 => 'N',
|
|
90 => 'E',
|
|
180 => 'S',
|
|
270 => 'W',
|
|
else => {
|
|
std.log.warn("Unexpected facing {}", .{self.facing});
|
|
unreachable;
|
|
},
|
|
};
|
|
self.update(c, value);
|
|
},
|
|
else => {
|
|
std.log.warn("Unknown command: '{}'", .{command});
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn manhattan_distance_from(self: *ShipPosition, from: [2]i64) u64 {
|
|
return (std.math.absCast(self.position[0] - from[0])) +
|
|
(std.math.absCast(self.position[1] - from [1]));
|
|
}
|
|
|
|
pub fn update_part2(self: *ShipPosition, command: u8, value: i64) void {
|
|
switch(command) {
|
|
'N' => {
|
|
self.waypoint[1] += value;
|
|
},
|
|
'S' => {
|
|
self.waypoint[1] -= value;
|
|
},
|
|
'E' => {
|
|
self.waypoint[0] += value;
|
|
},
|
|
'W' => {
|
|
self.waypoint[0] -= value;
|
|
},
|
|
'R' => {
|
|
// Rotate around the ship
|
|
self.waypoint = rotate_point(self.waypoint, -value);
|
|
},
|
|
'L' => {
|
|
// Rotate around the ship
|
|
self.waypoint = rotate_point(self.waypoint, value);
|
|
},
|
|
'F' => {
|
|
// For forward value times towards the waypoint.
|
|
self.position[0] += self.waypoint[0] * value;
|
|
self.position[1] += self.waypoint[1] * value;
|
|
// Waypoint stays relative to ship
|
|
//self.waypoint[0] = self.position[0] + self.waypoint[0];
|
|
//self.waypoint[1] = self.position[1] + self.waypoint[1];
|
|
},
|
|
else => {
|
|
std.log.warn("Unknown command: '{}'", .{command});
|
|
},
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
pub fn rotate_point(point: [2]i64, degrees: i64) [2]i64 {
|
|
var radians : f64 = (@intToFloat(f64, degrees) * std.math.pi) / 180.0;
|
|
var old_x = @intToFloat(f64, point[0]);
|
|
var old_y = @intToFloat(f64, point[1]);
|
|
var x : f64 = old_x * std.math.cos(radians) - old_y * std.math.sin(radians);
|
|
var y : f64 = old_y * std.math.cos(radians) + old_x * std.math.sin(radians);
|
|
return [2]i64 {
|
|
@floatToInt(i64, std.math.round(x)),
|
|
@floatToInt(i64, std.math.round(y)),
|
|
};
|
|
}
|
|
|
|
test "part_one" {
|
|
var data = [_][]const u8 {
|
|
"F10",
|
|
"N3",
|
|
"F7",
|
|
"R90",
|
|
"F11",
|
|
};
|
|
var ship = ShipPosition{};
|
|
for (data) |d| {
|
|
ship.update(d[0], try std.fmt.parseInt(i64, d[1..], 10));
|
|
}
|
|
std.testing.expectEqual(ship.position[0], 17);
|
|
std.testing.expectEqual(ship.position[1], -8);
|
|
std.testing.expectEqual(ship.manhattan_distance_from([_]i64{0, 0}), 25);
|
|
}
|
|
|
|
test "part_two" {
|
|
var data = [_][]const u8 {
|
|
"F10",
|
|
"N3",
|
|
"F7",
|
|
"R90",
|
|
"F11",
|
|
};
|
|
var ship = ShipPosition{};
|
|
for (data) |d| {
|
|
ship.update_part2(d[0], try std.fmt.parseInt(i64, d[1..], 10));
|
|
std.log.warn("After '{}', ship at ({}, {}), with waypoint ({}, {})",
|
|
.{d, ship.position[0], ship.position[1],
|
|
ship.waypoint[0], ship.waypoint[1]});
|
|
}
|
|
std.testing.expectEqual(ship.position[0], 214);
|
|
std.testing.expectEqual(ship.position[1], -72);
|
|
std.testing.expectEqual(ship.manhattan_distance_from([_]i64{0, 0}), 286);
|
|
}
|
|
|
|
// test "rotate" {
|
|
// var point = [_]i64 {4,-3};
|
|
// var p = rotate_point(point, 90);
|
|
// std.testing.expectEqual(p[0], 3);
|
|
// std.testing.expectEqual(p[1], 4);
|
|
|
|
// p = rotate_point(point, 180);
|
|
// std.testing.expectEqual(p[0], -4);
|
|
// std.testing.expectEqual(p[1], 3);
|
|
|
|
// p = rotate_point(point, 270);
|
|
// std.testing.expectEqual(p[0], -4);
|
|
// std.testing.expectEqual(p[1], 3);
|
|
|
|
// }
|