aoc/day12/src/main.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);
// }