1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
const std = @import("std");
pub const Error = error{InvalidInput};
pub var debug = false;
pub var debuglvl: u32 = 0;
pub fn debugfmt(comptime fmt: []const u8, args: anytype) void {
if (debug)
std.debug.print(fmt, args);
}
const part_type = fn (alloc: std.mem.Allocator, input: []u8, args: [][]u8) anyerror!?[]u8;
pub fn main(comptime part1: part_type, comptime part2: part_type, comptime sols: [2]?[]const u8) fn () anyerror!void {
const impl = struct {
fn main() !void {
const envvar = std.os.getenv("AOC_DEBUG");
if (envvar != null) {
debuglvl = try std.fmt.parseInt(u32, envvar.?, 10);
debug = debuglvl != 0;
}
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var heapalloc = gpa.allocator();
const args = try std.process.argsAlloc(heapalloc);
defer heapalloc.free(args);
if (args.len < 2) return;
var filename: []const u8 = std.mem.span("input");
for (std.os.environ) |v| {
const kv = std.mem.span(v);
if (std.mem.indexOfScalar(u8, kv, '=')) |sep| {
if (sep == kv.len - 1) continue;
if (std.mem.eql(u8, kv[0..sep], "AOC_INPUT")) {
filename = kv[sep + 1 ..];
std.debug.print("Using input file: {s}\n", .{filename});
break;
} else if (std.mem.eql(u8, kv[0..sep], "AOCDEBUG")) {
debug = true;
debuglvl = try std.fmt.parseInt(u32, kv[sep + 1 ..], 10);
}
}
}
const file = try std.fs.cwd().openFile(filename, .{});
const text = try file.reader().readAllAlloc(heapalloc, std.math.maxInt(u32));
defer heapalloc.free(text);
var part = try std.fmt.parseInt(u8, args[1], 10);
var answer: ?[]u8 = null;
switch (part) {
1 => answer = try part1(heapalloc, text, args[2..]),
2 => answer = try part2(heapalloc, text, args[2..]),
else => {
std.debug.print("Invalid part number!\n", .{});
std.os.exit(1);
},
}
part = part - 1;
if (answer != null) {
const stdout = std.io.getStdOut().writer();
try std.fmt.format(stdout, "{s}\n", .{answer.?});
if (sols[part] != null and !std.mem.eql(u8, answer.?, sols[part].?)) {
std.debug.print("Invalid answer\n", .{});
std.os.exit(1);
}
heapalloc.free(answer.?);
}
if (sols[part] == null) {
std.debug.print("Missing solution\n", .{});
std.os.exit(1);
}
}
};
return impl.main;
}
pub const Pos = struct {
x: i64,
y: i64,
const Self = @This();
pub fn add(self: Self, other: Self) Self {
return Self{ .x = self.x + other.x, .y = self.y + other.y };
}
pub fn mult(self: Self, val: i64) Self {
return Self{ .x = self.x * val, .y = self.y * val };
}
};
pub const Dir = struct {
pub const East = Pos{ .x = 1, .y = 0 };
pub const West = Pos{ .x = -1, .y = 0 };
pub const South = Pos{ .x = 0, .y = -1 };
pub const North = Pos{ .x = 0, .y = 1 };
pub const Name = enum(u8) { NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3 };
pub const dirs = [_]Pos{ North, East, South, West };
pub fn get(name: Name) Pos {
return dirs[@enumToInt(name)];
}
pub fn nextCW(dir: usize, offset: usize) usize {
return (dir + @intCast(u32, offset)) % @intCast(u32, dirs.len);
}
pub fn nextCCW(dir: usize, offset: usize) usize {
const constrained = offset % dirs.len;
if (dir >= constrained) {
return dir - constrained;
} else {
return dirs.len - (constrained - dir);
}
}
const cos90vs = [_]i32{ 1, 0, -1, 0 };
const sin90vs = [_]i32{ 0, 1, 0, -1 };
pub fn rotCW(pos: Pos, offset: usize) Pos {
const constrained = (4 - offset % 4) % 4;
return Pos{
.x = cos90vs[constrained] * pos.x - sin90vs[constrained] * pos.y,
.y = sin90vs[constrained] * pos.x + cos90vs[constrained] * pos.y,
};
}
pub fn rotCCW(pos: Pos, offset: usize) Pos {
const constrained = offset % 4;
return Pos{
.x = cos90vs[constrained] * pos.x - sin90vs[constrained] * pos.y,
.y = sin90vs[constrained] * pos.x + cos90vs[constrained] * pos.y,
};
}
};
pub fn unwrap(v: anytype) !@TypeOf(v.?) {
if (v == null) return Error.InvalidInput;
return v.?;
}
|