mirror of
https://github.com/MorizzG/aoc-2024.git
synced 2025-12-06 04:22:43 +00:00
day 3 done
also fixed up a bunch of stuff on day 1 and day 2
This commit is contained in:
parent
61d7d0f486
commit
ec56f69ecd
11 changed files with 1907 additions and 330 deletions
|
|
@ -1,91 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
// Although this function looks imperative, note that its job is to
|
|
||||||
// declaratively construct a build graph that will be executed by an external
|
|
||||||
// runner.
|
|
||||||
pub fn build(b: *std.Build) void {
|
|
||||||
// Standard target options allows the person running `zig build` to choose
|
|
||||||
// what target to build for. Here we do not override the defaults, which
|
|
||||||
// means any target is allowed, and the default is native. Other options
|
|
||||||
// for restricting supported target set are available.
|
|
||||||
const target = b.standardTargetOptions(.{});
|
|
||||||
|
|
||||||
// Standard optimization options allow the person running `zig build` to select
|
|
||||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
|
||||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
|
||||||
|
|
||||||
const lib = b.addStaticLibrary(.{
|
|
||||||
.name = "Day01",
|
|
||||||
// In this case the main source file is merely a path, however, in more
|
|
||||||
// complicated build scripts, this could be a generated file.
|
|
||||||
.root_source_file = b.path("src/root.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
// This declares intent for the library to be installed into the standard
|
|
||||||
// location when the user invokes the "install" step (the default step when
|
|
||||||
// running `zig build`).
|
|
||||||
b.installArtifact(lib);
|
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "Day01",
|
|
||||||
.root_source_file = b.path("src/main.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
// This declares intent for the executable to be installed into the
|
|
||||||
// standard location when the user invokes the "install" step (the default
|
|
||||||
// step when running `zig build`).
|
|
||||||
b.installArtifact(exe);
|
|
||||||
|
|
||||||
// This *creates* a Run step in the build graph, to be executed when another
|
|
||||||
// step is evaluated that depends on it. The next line below will establish
|
|
||||||
// such a dependency.
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
|
|
||||||
// By making the run step depend on the install step, it will be run from the
|
|
||||||
// installation directory rather than directly from within the cache directory.
|
|
||||||
// This is not necessary, however, if the application depends on other installed
|
|
||||||
// files, this ensures they will be present and in the expected location.
|
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
|
||||||
|
|
||||||
// This allows the user to pass arguments to the application in the build
|
|
||||||
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
|
||||||
if (b.args) |args| {
|
|
||||||
run_cmd.addArgs(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This creates a build step. It will be visible in the `zig build --help` menu,
|
|
||||||
// and can be selected like this: `zig build run`
|
|
||||||
// This will evaluate the `run` step rather than the default, which is "install".
|
|
||||||
const run_step = b.step("run", "Run the app");
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
|
||||||
|
|
||||||
// Creates a step for unit testing. This only builds the test executable
|
|
||||||
// but does not run it.
|
|
||||||
const lib_unit_tests = b.addTest(.{
|
|
||||||
.root_source_file = b.path("src/root.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
|
|
||||||
|
|
||||||
const exe_unit_tests = b.addTest(.{
|
|
||||||
.root_source_file = b.path("src/main.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
|
||||||
|
|
||||||
// Similar to creating the run step earlier, this exposes a `test` step to
|
|
||||||
// the `zig build --help` menu, providing a way for the user to request
|
|
||||||
// running the unit tests.
|
|
||||||
const test_step = b.step("test", "Run unit tests");
|
|
||||||
test_step.dependOn(&run_lib_unit_tests.step);
|
|
||||||
test_step.dependOn(&run_exe_unit_tests.step);
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
.{
|
|
||||||
// This is the default name used by packages depending on this one. For
|
|
||||||
// example, when a user runs `zig fetch --save <url>`, this field is used
|
|
||||||
// as the key in the `dependencies` table. Although the user can choose a
|
|
||||||
// different name, most users will stick with this provided value.
|
|
||||||
//
|
|
||||||
// It is redundant to include "zig" in this name because it is already
|
|
||||||
// within the Zig package namespace.
|
|
||||||
.name = "Day01",
|
|
||||||
|
|
||||||
// This is a [Semantic Version](https://semver.org/).
|
|
||||||
// In a future version of Zig it will be used for package deduplication.
|
|
||||||
.version = "0.0.0",
|
|
||||||
|
|
||||||
// This field is optional.
|
|
||||||
// This is currently advisory only; Zig does not yet do anything
|
|
||||||
// with this value.
|
|
||||||
//.minimum_zig_version = "0.11.0",
|
|
||||||
|
|
||||||
// This field is optional.
|
|
||||||
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
|
||||||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
|
||||||
// Once all dependencies are fetched, `zig build` no longer requires
|
|
||||||
// internet connectivity.
|
|
||||||
.dependencies = .{
|
|
||||||
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
|
|
||||||
//.example = .{
|
|
||||||
// // When updating this field to a new URL, be sure to delete the corresponding
|
|
||||||
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
|
||||||
// // the new URL.
|
|
||||||
// .url = "https://example.com/foo.tar.gz",
|
|
||||||
//
|
|
||||||
// // This is computed from the file contents of the directory of files that is
|
|
||||||
// // obtained after fetching `url` and applying the inclusion rules given by
|
|
||||||
// // `paths`.
|
|
||||||
// //
|
|
||||||
// // This field is the source of truth; packages do not come from a `url`; they
|
|
||||||
// // come from a `hash`. `url` is just one of many possible mirrors for how to
|
|
||||||
// // obtain a package matching this `hash`.
|
|
||||||
// //
|
|
||||||
// // Uses the [multihash](https://multiformats.io/multihash/) format.
|
|
||||||
// .hash = "...",
|
|
||||||
//
|
|
||||||
// // When this is provided, the package is found in a directory relative to the
|
|
||||||
// // build root. In this case the package's hash is irrelevant and therefore not
|
|
||||||
// // computed. This field and `url` are mutually exclusive.
|
|
||||||
// .path = "foo",
|
|
||||||
|
|
||||||
// // When this is set to `true`, a package is declared to be lazily
|
|
||||||
// // fetched. This makes the dependency only get fetched if it is
|
|
||||||
// // actually used.
|
|
||||||
// .lazy = false,
|
|
||||||
//},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Specifies the set of files and directories that are included in this package.
|
|
||||||
// Only files and directories listed here are included in the `hash` that
|
|
||||||
// is computed for this package. Only files listed here will remain on disk
|
|
||||||
// when using the zig package manager. As a rule of thumb, one should list
|
|
||||||
// files required for compilation plus any license(s).
|
|
||||||
// Paths are relative to the build root. Use the empty string (`""`) to refer to
|
|
||||||
// the build root itself.
|
|
||||||
// A directory listed here means that all files within, recursively, are included.
|
|
||||||
.paths = .{
|
|
||||||
"build.zig",
|
|
||||||
"build.zig.zon",
|
|
||||||
"src",
|
|
||||||
// For example...
|
|
||||||
//"LICENSE",
|
|
||||||
//"README.md",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
// // Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
|
|
||||||
// std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
|
|
||||||
|
|
||||||
// // stdout is for the actual output of your application, for example if you
|
|
||||||
// // are implementing gzip, then only the compressed bytes should be sent to
|
|
||||||
// // stdout, not any debugging messages.
|
|
||||||
// const stdout_file = std.io.getStdOut().writer();
|
|
||||||
// var bw = std.io.bufferedWriter(stdout_file);
|
|
||||||
// const stdout = bw.writer();
|
|
||||||
|
|
||||||
// try stdout.print("Run `zig build test` to run the tests.\n", .{});
|
|
||||||
|
|
||||||
// try bw.flush(); // don't forget to flush!
|
|
||||||
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
||||||
const alloc = gpa.allocator();
|
|
||||||
|
|
||||||
try part1(alloc);
|
|
||||||
try part2(alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn range(comptime n: u32) [n]usize {
|
|
||||||
var array: [n]usize = undefined;
|
|
||||||
|
|
||||||
for (0.., &array) |i, *elem| {
|
|
||||||
elem.* = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argsort_cmp(comptime T: type, comptime lessThanFn: fn (ctx: void, lhs: T, rhs: T) bool) (fn ([]T, usize, usize) bool) {
|
|
||||||
return struct {
|
|
||||||
fn cmp(array: []T, left_idx: usize, right_idx: usize) bool {
|
|
||||||
return lessThanFn({}, array[left_idx], array[right_idx]);
|
|
||||||
}
|
|
||||||
}.cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn part1(alloc: std.mem.Allocator) !void {
|
|
||||||
const filename = "input1.txt";
|
|
||||||
|
|
||||||
const num_lines = 1_000;
|
|
||||||
|
|
||||||
const file = try std.fs.cwd().openFile(filename, .{});
|
|
||||||
defer file.close();
|
|
||||||
|
|
||||||
var left_list: [num_lines]u32 = undefined;
|
|
||||||
var right_list: [num_lines]u32 = undefined;
|
|
||||||
|
|
||||||
const file_reader = file.reader();
|
|
||||||
var buf_reader = std.io.BufferedReader(4096, @TypeOf(file_reader)){ .unbuffered_reader = file_reader };
|
|
||||||
|
|
||||||
const reader = std.io.Reader(@TypeOf(&buf_reader), std.fs.File.Reader.Error, @TypeOf(buf_reader).read){ .context = &buf_reader };
|
|
||||||
|
|
||||||
var line_buf = std.ArrayList(u8).init(alloc);
|
|
||||||
defer line_buf.deinit();
|
|
||||||
|
|
||||||
for (0..(num_lines + 1)) |i| {
|
|
||||||
reader.streamUntilDelimiter(line_buf.writer(), '\n', 4096) catch |err| switch (err) {
|
|
||||||
error.EndOfStream => break,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
|
|
||||||
const left = try std.fmt.parseUnsigned(u32, line_buf.items[0..5], 10);
|
|
||||||
const right = try std.fmt.parseUnsigned(u32, line_buf.items[8..13], 10);
|
|
||||||
|
|
||||||
left_list[i] = left;
|
|
||||||
right_list[i] = right;
|
|
||||||
|
|
||||||
try line_buf.resize(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var left_idxs = range(num_lines);
|
|
||||||
var right_idxs = range(num_lines);
|
|
||||||
|
|
||||||
std.debug.assert(left_list.len == left_idxs.len);
|
|
||||||
std.debug.assert(right_list.len == right_idxs.len);
|
|
||||||
|
|
||||||
for (0..1000) |i| {
|
|
||||||
std.debug.assert(left_idxs[i] == i);
|
|
||||||
std.debug.assert(right_idxs[i] == i);
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmp = argsort_cmp(u32, std.sort.asc(u32));
|
|
||||||
|
|
||||||
std.mem.sort(usize, &left_idxs, @as([]u32, &left_list), cmp);
|
|
||||||
std.mem.sort(usize, &right_idxs, @as([]u32, &right_list), cmp);
|
|
||||||
|
|
||||||
for (0..(num_lines - 1)) |i| {
|
|
||||||
std.debug.assert(left_list[left_idxs[i]] <= left_list[left_idxs[i + 1]]);
|
|
||||||
std.debug.assert(right_list[right_idxs[i]] <= right_list[right_idxs[i + 1]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sum: u64 = 0;
|
|
||||||
|
|
||||||
for (left_idxs, right_idxs) |left_idx, right_idx| {
|
|
||||||
sum += @abs(@as(i64, left_list[left_idx]) - @as(i64, right_list[right_idx]));
|
|
||||||
}
|
|
||||||
|
|
||||||
std.debug.print("Day 1, part 1: {}\n", .{sum});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn part2(alloc: std.mem.Allocator) !void {
|
|
||||||
const filename = "input1.txt";
|
|
||||||
|
|
||||||
const num_lines = 1_000;
|
|
||||||
|
|
||||||
const file = try std.fs.cwd().openFile(filename, .{});
|
|
||||||
defer file.close();
|
|
||||||
|
|
||||||
var left_list: [num_lines]u32 = undefined;
|
|
||||||
|
|
||||||
var right_map = std.AutoHashMap(u32, u32).init(alloc);
|
|
||||||
defer right_map.deinit();
|
|
||||||
|
|
||||||
const file_reader = file.reader();
|
|
||||||
var buf_reader = std.io.BufferedReader(4096, @TypeOf(file_reader)){ .unbuffered_reader = file_reader };
|
|
||||||
|
|
||||||
const reader = std.io.Reader(@TypeOf(&buf_reader), std.fs.File.Reader.Error, @TypeOf(buf_reader).read){ .context = &buf_reader };
|
|
||||||
|
|
||||||
var line_buf = std.ArrayList(u8).init(alloc);
|
|
||||||
defer line_buf.deinit();
|
|
||||||
|
|
||||||
for (0..(num_lines + 1)) |i| {
|
|
||||||
reader.streamUntilDelimiter(line_buf.writer(), '\n', 4096) catch |err| switch (err) {
|
|
||||||
error.EndOfStream => break,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
|
|
||||||
const left = try std.fmt.parseUnsigned(u32, line_buf.items[0..5], 10);
|
|
||||||
const right = try std.fmt.parseUnsigned(u32, line_buf.items[8..13], 10);
|
|
||||||
|
|
||||||
left_list[i] = left;
|
|
||||||
|
|
||||||
if (right_map.get(right)) |count| {
|
|
||||||
try right_map.put(right, count + 1);
|
|
||||||
} else {
|
|
||||||
try right_map.put(right, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try line_buf.resize(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sum: u64 = 0;
|
|
||||||
|
|
||||||
for (left_list) |x| {
|
|
||||||
if (right_map.get(x)) |count| {
|
|
||||||
sum += count * x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std.debug.print("Day 1, part 2: {}\n", .{sum});
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const testing = std.testing;
|
|
||||||
|
|
||||||
export fn add(a: i32, b: i32) i32 {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "basic add functionality" {
|
|
||||||
try testing.expect(add(3, 7) == 10);
|
|
||||||
}
|
|
||||||
227
day1.zig
Normal file
227
day1.zig
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const utils = @import("utils.zig");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
// // Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
|
||||||
|
// std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
|
||||||
|
|
||||||
|
// // stdout is for the actual output of your application, for example if you
|
||||||
|
// // are implementing gzip, then only the compressed bytes should be sent to
|
||||||
|
// // stdout, not any debugging messages.
|
||||||
|
// const stdout_file = std.io.getStdOut().writer();
|
||||||
|
// var bw = std.io.bufferedWriter(stdout_file);
|
||||||
|
// const stdout = bw.writer();
|
||||||
|
|
||||||
|
// try stdout.print("Run `zig build test` to run the tests.\n", .{});
|
||||||
|
|
||||||
|
// try bw.flush(); // don't forget to flush!
|
||||||
|
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
const filename = "inputs/day1.txt";
|
||||||
|
|
||||||
|
{
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part1(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.io.getStdOut().writer().print("Day 1, part 1: {}\n", .{result});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part2(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.io.getStdOut().writer().print("Day 1, part 1: {}\n", .{result});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rangeConst(comptime n: usize) [n]usize {
|
||||||
|
var array: [n]usize = undefined;
|
||||||
|
|
||||||
|
for (0.., &array) |i, *elem| {
|
||||||
|
elem.* = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn range(alloc: std.mem.Allocator, n: usize) ![]usize {
|
||||||
|
var array = try alloc.alloc(usize, n);
|
||||||
|
|
||||||
|
for (0..n) |i| {
|
||||||
|
array[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argsort_cmp(comptime T: type, comptime lessThanFn: fn (ctx: void, lhs: T, rhs: T) bool) (fn ([]const T, usize, usize) bool) {
|
||||||
|
return struct {
|
||||||
|
fn cmp(array: []const T, left_idx: usize, right_idx: usize) bool {
|
||||||
|
return lessThanFn({}, array[left_idx], array[right_idx]);
|
||||||
|
}
|
||||||
|
}.cmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
||||||
|
var left_list = std.ArrayList(u32).init(alloc);
|
||||||
|
var right_list = std.ArrayList(u32).init(alloc);
|
||||||
|
defer left_list.deinit();
|
||||||
|
defer right_list.deinit();
|
||||||
|
|
||||||
|
var line_reader = utils.lineReader(alloc, reader);
|
||||||
|
defer line_reader.deinit();
|
||||||
|
|
||||||
|
while (try line_reader.next()) |line| {
|
||||||
|
var number_parser = utils.numberParser(u32, line);
|
||||||
|
|
||||||
|
const left = (try number_parser.next()).?;
|
||||||
|
const right = (try number_parser.next()).?;
|
||||||
|
|
||||||
|
std.debug.assert((try number_parser.next()) == null);
|
||||||
|
|
||||||
|
try left_list.append(left);
|
||||||
|
try right_list.append(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
const num_lines = left_list.items.len;
|
||||||
|
|
||||||
|
std.debug.assert(right_list.items.len == num_lines);
|
||||||
|
|
||||||
|
const left_idxs = try range(alloc, num_lines);
|
||||||
|
const right_idxs = try range(alloc, num_lines);
|
||||||
|
defer alloc.free(left_idxs);
|
||||||
|
defer alloc.free(right_idxs);
|
||||||
|
|
||||||
|
std.debug.assert(left_list.items.len == left_idxs.len);
|
||||||
|
std.debug.assert(right_list.items.len == right_idxs.len);
|
||||||
|
|
||||||
|
for (0..num_lines) |i| {
|
||||||
|
std.debug.assert(left_idxs[i] == i);
|
||||||
|
std.debug.assert(right_idxs[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cmp = argsort_cmp(u32, std.sort.asc(u32));
|
||||||
|
|
||||||
|
std.mem.sort(usize, left_idxs, left_list.items, cmp);
|
||||||
|
std.mem.sort(usize, right_idxs, right_list.items, cmp);
|
||||||
|
|
||||||
|
for (0..(num_lines - 1)) |i| {
|
||||||
|
std.debug.assert(left_list.items[left_idxs[i]] <= left_list.items[left_idxs[i + 1]]);
|
||||||
|
std.debug.assert(right_list.items[right_idxs[i]] <= right_list.items[right_idxs[i + 1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sum: u64 = 0;
|
||||||
|
|
||||||
|
for (left_idxs, right_idxs) |left_idx, right_idx| {
|
||||||
|
sum += @abs(@as(i64, left_list.items[left_idx]) - @as(i64, right_list.items[right_idx]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
||||||
|
var left_list = std.ArrayList(u32).init(alloc);
|
||||||
|
defer left_list.deinit();
|
||||||
|
|
||||||
|
var right_map = std.AutoHashMap(u32, u32).init(alloc);
|
||||||
|
defer right_map.deinit();
|
||||||
|
|
||||||
|
var line_reader = utils.lineReader(alloc, reader);
|
||||||
|
defer line_reader.deinit();
|
||||||
|
|
||||||
|
while (try line_reader.next()) |line| {
|
||||||
|
var number_parser = utils.numberParser(u32, line);
|
||||||
|
|
||||||
|
const left = (try number_parser.next()).?;
|
||||||
|
const right = (try number_parser.next()).?;
|
||||||
|
|
||||||
|
try left_list.append(left);
|
||||||
|
|
||||||
|
if (right_map.get(right)) |count| {
|
||||||
|
try right_map.put(right, count + 1);
|
||||||
|
} else {
|
||||||
|
try right_map.put(right, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sum: u64 = 0;
|
||||||
|
|
||||||
|
for (left_list.items) |x| {
|
||||||
|
if (right_map.get(x)) |count| {
|
||||||
|
sum += count * x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part1 example" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const example =
|
||||||
|
\\3 4
|
||||||
|
\\4 3
|
||||||
|
\\2 5
|
||||||
|
\\1 3
|
||||||
|
\\3 9
|
||||||
|
\\3 3
|
||||||
|
;
|
||||||
|
|
||||||
|
var stream = std.io.fixedBufferStream(example);
|
||||||
|
|
||||||
|
const result = try part1(alloc, stream.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part1 input" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const filename = "inputs/day1.txt";
|
||||||
|
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part1(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 1506483);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part2 example" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const example =
|
||||||
|
\\3 4
|
||||||
|
\\4 3
|
||||||
|
\\2 5
|
||||||
|
\\1 3
|
||||||
|
\\3 9
|
||||||
|
\\3 3
|
||||||
|
;
|
||||||
|
|
||||||
|
var stream = std.io.fixedBufferStream(example);
|
||||||
|
|
||||||
|
const result = try part2(alloc, stream.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part2 input" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const filename = "inputs/day1.txt";
|
||||||
|
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part2(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 23126924);
|
||||||
|
}
|
||||||
240
day2.zig
Normal file
240
day2.zig
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const utils = @import("utils.zig");
|
||||||
|
|
||||||
|
fn Chain(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
slice1: []const T,
|
||||||
|
slice2: []const T,
|
||||||
|
|
||||||
|
fn len(self: *const @This()) usize {
|
||||||
|
return self.slice1.len + self.slice2.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(self: *const @This(), i: usize) T {
|
||||||
|
var idx = i;
|
||||||
|
|
||||||
|
if (idx < self.slice1.len) {
|
||||||
|
return self.slice1[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
idx -= self.slice1.len;
|
||||||
|
|
||||||
|
if (idx < self.slice2.len) {
|
||||||
|
return self.slice2[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
const filename = "inputs/day2.txt";
|
||||||
|
|
||||||
|
{
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part1(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.io.getStdOut().writer().print("Day 2, part 1: {}\n", .{result});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part2(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.io.getStdOut().writer().print("Day 2, part 2: {}\n", .{result});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check(report: []const i32) bool {
|
||||||
|
var window = std.mem.window(i32, report, 2, 1);
|
||||||
|
|
||||||
|
if (report[0] < report[1]) {
|
||||||
|
while (window.next()) |x| {
|
||||||
|
std.debug.assert(x.len == 2);
|
||||||
|
|
||||||
|
const diff = x[1] - x[0];
|
||||||
|
|
||||||
|
if (diff < 1 or diff > 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (report[0] > report[1]) {
|
||||||
|
while (window.next()) |x| {
|
||||||
|
std.debug.assert(x.len == 2);
|
||||||
|
|
||||||
|
const diff = x[0] - x[1];
|
||||||
|
|
||||||
|
if (diff < 1 or diff > 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_with_skip(report: []const i32, skip_idx: usize) bool {
|
||||||
|
const chain = Chain(i32){ .slice1 = report[0..skip_idx], .slice2 = report[skip_idx + 1 ..] };
|
||||||
|
|
||||||
|
if (chain.get(0) < chain.get(1)) {
|
||||||
|
for (0..(chain.len() - 1)) |i| {
|
||||||
|
const diff = chain.get(i + 1) - chain.get(i);
|
||||||
|
|
||||||
|
if (diff < 1 or diff > 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (chain.get(0) > chain.get(1)) {
|
||||||
|
for (0..(chain.len() - 1)) |i| {
|
||||||
|
const diff = chain.get(i) - chain.get(i + 1);
|
||||||
|
|
||||||
|
if (diff < 1 or diff > 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(alloc: std.mem.Allocator, reader: anytype) !u32 {
|
||||||
|
var line_reader = utils.lineReader(alloc, reader);
|
||||||
|
defer line_reader.deinit();
|
||||||
|
|
||||||
|
var report = std.ArrayList(i32).init(alloc);
|
||||||
|
defer report.deinit();
|
||||||
|
|
||||||
|
var num_safe_reports: u32 = 0;
|
||||||
|
|
||||||
|
while (try line_reader.next()) |line| {
|
||||||
|
report.clearRetainingCapacity();
|
||||||
|
|
||||||
|
var number_parser = utils.numberParser(i32, line);
|
||||||
|
|
||||||
|
while (try number_parser.next()) |n| {
|
||||||
|
try report.append(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check(report.items)) {
|
||||||
|
num_safe_reports += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_safe_reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(alloc: std.mem.Allocator, reader: anytype) !u32 {
|
||||||
|
var line_reader = utils.lineReader(alloc, reader);
|
||||||
|
defer line_reader.deinit();
|
||||||
|
|
||||||
|
var report = std.ArrayList(i32).init(alloc);
|
||||||
|
defer report.deinit();
|
||||||
|
|
||||||
|
var num_safe_reports: u32 = 0;
|
||||||
|
|
||||||
|
report_loop: while (try line_reader.next()) |line| {
|
||||||
|
report.clearRetainingCapacity();
|
||||||
|
|
||||||
|
// var it = std.mem.tokenizeScalar(u8, line, ' ');
|
||||||
|
|
||||||
|
var number_parser = utils.numberParser(i32, line);
|
||||||
|
|
||||||
|
while (try number_parser.next()) |n| {
|
||||||
|
try report.append(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (report.items.len < 2) {
|
||||||
|
return error.ReportTooSmall;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check(report.items)) {
|
||||||
|
num_safe_reports += 1;
|
||||||
|
} else {
|
||||||
|
for (0..report.items.len) |skip_idx| {
|
||||||
|
if (check_with_skip(report.items, skip_idx)) {
|
||||||
|
num_safe_reports += 1;
|
||||||
|
continue :report_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_safe_reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part1 example" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const example =
|
||||||
|
\\7 6 4 2 1
|
||||||
|
\\1 2 7 8 9
|
||||||
|
\\9 7 6 2 1
|
||||||
|
\\1 3 2 4 5
|
||||||
|
\\8 6 4 4 1
|
||||||
|
\\1 3 6 7 9
|
||||||
|
;
|
||||||
|
|
||||||
|
var stream = std.io.fixedBufferStream(example);
|
||||||
|
|
||||||
|
const result = try part1(alloc, stream.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part1 input" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const filename = "inputs/day2.txt";
|
||||||
|
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part1(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 549);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part2 example" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const example =
|
||||||
|
\\7 6 4 2 1
|
||||||
|
\\1 2 7 8 9
|
||||||
|
\\9 7 6 2 1
|
||||||
|
\\1 3 2 4 5
|
||||||
|
\\8 6 4 4 1
|
||||||
|
\\1 3 6 7 9
|
||||||
|
;
|
||||||
|
|
||||||
|
var stream = std.io.fixedBufferStream(example);
|
||||||
|
|
||||||
|
const result = try part2(alloc, stream.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part2 input" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const filename = "inputs/day2.txt";
|
||||||
|
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part2(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 589);
|
||||||
|
}
|
||||||
282
day3.zig
Normal file
282
day3.zig
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const utils = @import("utils.zig");
|
||||||
|
|
||||||
|
const isDigit = std.ascii.isDigit;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
const filename = "inputs/day3.txt";
|
||||||
|
|
||||||
|
{
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part1(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.io.getStdOut().writer().print("Day 2, part 1: {}\n", .{result});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part2(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.io.getStdOut().writer().print("Day 2, part 2: {}\n", .{result});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
||||||
|
const input = try reader.readAllAlloc(alloc, std.math.maxInt(u64));
|
||||||
|
defer alloc.free(input);
|
||||||
|
|
||||||
|
const mul_prefix = "mul(";
|
||||||
|
|
||||||
|
std.debug.assert(mul_prefix.len == 4);
|
||||||
|
|
||||||
|
var total: u64 = 0;
|
||||||
|
|
||||||
|
var idx: usize = 0;
|
||||||
|
var i: usize = 0;
|
||||||
|
|
||||||
|
outer: while (idx < input.len) : (idx += @max(i, 1)) {
|
||||||
|
const rest = input[idx..];
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while (i < mul_prefix.len) : (i += 1) {
|
||||||
|
if (rest[i] != mul_prefix[i]) {
|
||||||
|
continue :outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse first number
|
||||||
|
|
||||||
|
var start: usize = i;
|
||||||
|
|
||||||
|
// next char must be a digit
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume up to 2 more digits
|
||||||
|
for (0..2) |_| {
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// already validated we're parsing a valid number
|
||||||
|
const left = std.fmt.parseUnsigned(u32, rest[start..i], 10) catch unreachable;
|
||||||
|
|
||||||
|
if (rest[i] != ',') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume ','
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
// parse second number
|
||||||
|
|
||||||
|
start = i;
|
||||||
|
|
||||||
|
// next char must be a digit
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume up to 2 more digits
|
||||||
|
for (0..2) |_| {
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// already validated we're parsing a valid number
|
||||||
|
const right = std.fmt.parseUnsigned(u32, rest[start..i], 10) catch unreachable;
|
||||||
|
|
||||||
|
if (rest[i] != ')') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume ')'
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
total += left * right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
||||||
|
const input = try reader.readAllAlloc(alloc, std.math.maxInt(u64));
|
||||||
|
defer alloc.free(input);
|
||||||
|
|
||||||
|
// std.debug.print("{s}\n", .{input});
|
||||||
|
|
||||||
|
// var tok_it = std.mem.tokenizeSequence(u8, input, "mul(");
|
||||||
|
|
||||||
|
const mul_prefix = "mul(";
|
||||||
|
const do = "do()";
|
||||||
|
const dont = "don't()";
|
||||||
|
|
||||||
|
var total: u64 = 0;
|
||||||
|
|
||||||
|
var idx: usize = 0;
|
||||||
|
var i: usize = 0;
|
||||||
|
|
||||||
|
var enabled = true;
|
||||||
|
|
||||||
|
outer: while (idx < input.len) : (idx += @max(i, 1)) {
|
||||||
|
const rest = input[idx..];
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
if (!enabled) {
|
||||||
|
while (i < do.len) : (i += 1) {
|
||||||
|
if (rest[i] != do[i]) {
|
||||||
|
continue :outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rest[i] == 'd') {
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
while (i < do.len) : (i += 1) {
|
||||||
|
if (rest[i] != dont[i]) {
|
||||||
|
continue :outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < mul_prefix.len) : (i += 1) {
|
||||||
|
if (rest[i] != mul_prefix[i]) {
|
||||||
|
continue :outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse first number
|
||||||
|
|
||||||
|
var start: usize = i;
|
||||||
|
|
||||||
|
// next char must be a digit
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume up to 2 more digits
|
||||||
|
for (0..2) |_| {
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// already validated we're parsing a valid number
|
||||||
|
const left = std.fmt.parseUnsigned(u32, rest[start..i], 10) catch unreachable;
|
||||||
|
|
||||||
|
if (rest[i] != ',') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume ','
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
// parse second number
|
||||||
|
|
||||||
|
start = i;
|
||||||
|
|
||||||
|
// next char must be a digit
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume up to 2 more digits
|
||||||
|
for (0..2) |_| {
|
||||||
|
if (isDigit(rest[i])) {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// already validated we're parsing a valid number
|
||||||
|
const right = std.fmt.parseUnsigned(u32, rest[start..i], 10) catch unreachable;
|
||||||
|
|
||||||
|
if (rest[i] != ')') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume ')'
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
total += left * right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part1 example" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const example = "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))";
|
||||||
|
|
||||||
|
var stream = std.io.fixedBufferStream(example);
|
||||||
|
|
||||||
|
const result = try part1(alloc, stream.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 161);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part1 input" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const filename = "inputs/day3.txt";
|
||||||
|
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part1(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 156388521);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part2 example" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const example = "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))";
|
||||||
|
|
||||||
|
var stream = std.io.fixedBufferStream(example);
|
||||||
|
|
||||||
|
const result = try part2(alloc, stream.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part2 input" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const filename = "inputs/day3.txt";
|
||||||
|
|
||||||
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||||||
|
defer file_reader.deinit();
|
||||||
|
|
||||||
|
const result = try part2(alloc, file_reader.reader());
|
||||||
|
|
||||||
|
try std.testing.expect(result == 75920122);
|
||||||
|
}
|
||||||
1000
inputs/day2.txt
Normal file
1000
inputs/day2.txt
Normal file
File diff suppressed because it is too large
Load diff
6
inputs/day3.txt
Normal file
6
inputs/day3.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
where(536,162)~'what()what()how(220,399){ mul(5,253);mul(757,101)$where()@why()who()&when()from()mul(394,983)why()!&'how()mul(924,201)] mul(44,185)[]what()?${{}#,mul(116,356):~(from()]<why()mul(792,23)<+)%%'::mul(389,401)where()why()~{^@->when()'mul(557,491)<+select()]'mul(584,228)don't()*?#how()'where()&;@mul(58,115),where()?why()]]+:>mul(263,869)# %()from()[>mul(820,89);;#?when(),mul(553,296)where()(what()-mul(846,467){mul(436,71)}@$mul(553,611)do()where()<^select():+*'mul(411,428)-]?mul(722,379)}%'who(),>mul(471,731)*)+/what()@mul(729,484)/mul(672,572)'mul(375,937)who() ~how()%who()select()<mul(549,213)#/where()]mul(177,863)] {'],{'mul(486,207):+^select()mul(917,38) where()^why()@/-mul(255,420); ?mul(67,558)mul(141,261)(what()&{select()+mul(834,258)/>>;>don't(){mul(117,155)what()['why()}mul(946,797)why())^);where()%;}mul(387,438)'))mul(691,206)]when()+%>select()mul(182,238)how()' mul(522,434)where()mul(22,857)%mul(134,598)mul(689,301)-why()mul(7,725)^select()<,how()'%mul(632,167)}?*how()!mul(328,251)+mul(168,813)who()^when()why()mul(696,552)where()where()mul(177,527)%}$]%}from()]mul(600,612)select()&<&mul(5,789)<how()</)why()when()mul(935,875)where()+who()where()<&how()@mul(997,248)how()what()&who()^$]mul(59,285)mul(325,40)!#why(985,321);%mul(83,845)where()?$select()@(<(mul(463,456)>where()*/{who()why()do()*[when()}^]when()/mul(327,459)/&where()(mul(227,420)@(:[do()>mul(696,517)*mul(843,490)from(638,892)why()how()who()@mul(653,546)?how()when()^&]why()?mul(121,726)[where()-]}^?)>/mul(792,224)%+what()-/+mul(835,136)!{!'@)do()what()@#:*$*from()$mul(597,336)-?+^<']^]mul(222,657)('select()#!what()!mul(501,306):~+~@#'from()++mul(660,306)who()how();mul(884,257)why()when()what();:&$:!mul(180,820)]%who()-who()%(mul(770,324)~&]:?-mul(9,372 $)mul(987,378)from()select()where()mul(248,646)who(601,171)select()/>%[{$-mul(185,819) what() + :mul(442,907)--*)who()mul(541where(884,926)$mul(549,388)&^why(37,524)!?]!?from()don't()select(),%+ ?when(975,750)%}who()mul(262,401)<,/,from()mul(139,806)!;**);%+^;mul(76,978)'(what(){/mul!select()!mul(990,777)mul(188,545)(!what()/from()mul(272,32)from()^why()+#*mul(977,807):/^mul(266,744)select()from()*^<mul(800,207) /how()? ,mul(941,211),when()')mul(825,702),when()%~-;,?mul(883,307) where()%>select()!!,&who()mul(225,754)from()^#%^mul(513,969)why():mul(288,8)'who(331,621)@~~!@&mul(738,701)how()'@ where()don't(){>&>what()why()#(mul(744,683)@-from(498,125)when()don't()mul(773select()$mul(919,685)+where()mul(305,573)how()how(563,86)+,}who()~mul(291,852)%^from()mul(647,3)$+&:^-+/who()'mul(174,156){(mul(590select() -~*when()#^[mul(679,740)${;mul(463,30)$; (when()mul(875,270)who()/^#;~]!{mul(890(mul(224,108)#:!@mul <>^ where(),&<mul(486,524)who()who()#don't();)*-@:mul(452how()%-}*/where()*<@mul(613,459)where()}^'{mul(780,865)?;mul(365,535),%;,$how(),what()~]mul(622,700);don't()%who()who()mul(623,125)['how()} who()]don't()-where()!->who()^-$}mul(752,792)select() #/!how()@mul(213,376)(do()[why()%>?mul(771,799)^{&:/mul(382,131)how()^)}mul(412,25)?]]&^select()what()(mul(616,919)~}who()# ){who()when(263,342)^mul(946,363)
|
||||||
|
}?~who()select()-mul(316,505)&%*how()mul(363,589)>?%-:)where()~{{mul(38,452)select()%>[{]%>%mul(445,9)select()select()where()who(809,10)select()'&mul(505,640):>where()--mul(899,766)^where(){from()<mul(485,214)%]mul(469,95)$how(){why()+}mul(545,577)*why()who()from()@%who()$){mul(625,950)select()*mul(830,164)what()when()#!mul(530,4)don't()^mul(880,160)(?mul(508,717)$^why(14,313)when()~}who()mul(593,3)+mul(754,735)-#<(:}~{)mul(791,731)mul(718,434) [{$who()$'~select()how()mul%why(685,710)(/mul(458,943)select()/[[who()]/select()#%mul(454,66)+mul(521,460)/(when()+select(22,809){-'mul(206,53)when():)mul(420,119)+'%<mul(923,828)%~?mul(81,459)## ~*/!mul(266,160),-what()()}why()$(mul(634,181)mul(302,872)^@[when()}(#$*who()mul(831,161<@who()who()[;mul(947,843)/what()select()who()don't()~'@,'%;>@*mul(954,818)<{]$select(491,929)$mul(469,330);,'mul(709,381)>mul(692,607)select()(]/?don't()~from()what()<-&'[from()mul(20,147)who()&why()$(mul(482how(887,305)<&#how()!<[&/mul(964,713)~what(){what()^}}select()mul(37'**)]$what())mul(573,765)?where()#where()mul(861,190)what()what():~#?mul(149,843)<,-mul(705:^^~mul(134,719)})mul(22,371):}'<who()['{~[mul(672,177)}why()what()[+}how()mul(686!mul(484,84)(how()%(select()$%{select()#mul(857,111)mul<mul(11,521)$:mul(7,128)who()mul(614,497)why()when()]}from()how()!?do()mul(866,725)why()^^/+]%%mul(731,948)mul(33,176)when()]^-from()%mul(398,672)>when()how()}how()&do()-!mul(148,678)mul(801,30) what(),</^do()mul(510,36){^from()*<~(#}mul(283,696)mul(559,572)from()where()mul(762,321)*from()/mul(909,480)>mul&{?mul(184,545){}#select(448,839)+~+mul(986,322) what())/!<+mul(581,609)where()who()how()/mul(434,891))mul(728,525)[,'@@+mul(552,165);^:>)where() '?mul(23,400)mul(167,183)/*how() how()why()*mul(157,343)!?when()@;(~?mul(796,355)where()~<:$mul(312,781)<from()where()%who()mul(216,896)^+don't(),select()where(634,528)mul(9,285)]^why(508,561):who()(/]from()mul(718,986)]~]{^'*^mul(545,895)+what()%)%from()who()( %mul(722,572)select()+$,?&mul(107,209)$>{why()who()-:mul(440,283)select()how()how()mul(288,757)@how()mul(421,123)mul(589,921)how())?>) mul(455,905)-# who()mul(955,7-select();>when()mul(599,748):*!!##!>-(mul(273,990):{)!:mul(974,159)why(451,105)where()-$mul(696,260)~{ mul(216,455);when(912,287){mul(928,316)from()'#select()+who()> mul(890,212)[(why()/;mul(766,534)why()*>]select()why()from()from()mul(170,736)&when()#}mul(645,679))-where()$% mul(864,397)when()&%#mul(155,481))from()[-mul(160,707)mul(807,746)/where(779,210)mul(261,877)'[,$:what()mul(922,680)#what(972,646),how()where()%when()((why()mul(894,377)&]how()why(755,527)mul(48,266)(when()$what()mul(361,771)}select()[)mul(332,827)who()$^:)$>do()*;@[mul(690,51)?$mul(55,840)>[^,'#from()mul(863,343)@select()$mul(425,648)^why(208,282)mul(763,181)from()mul(794,818)+]''(^]mul(213,528):( ~'*^don't()!what()(mul(314,669)*,^!++!!,mul(641,237)](mul(440,591)}*mul(460,11)where()^*mul(708,915)</%<why()-mul(138,409)^&[?mul(275,464)
|
||||||
|
?>where(911,272)'mul(894,309)~+%@#}@#why()mul(330,296)what()mul(707,884)mul;&}<{>where()$why()]mul(609,787)*!/@who()+!,mul(342,89)::from()}#from()]:,/mul(102,723)select()^@when()who()mul(903,945)don't(),^)what()]mul(80,130)~+~[&@^,<mul(790,996)@]what(),<how()}(select()don't()why(){>from()<,mul(983,403);why()mul(936,199)&+:*who()@why()from():<mul]/$~/do(){what(),:%;%(;mul(502,753)-/from()(&mul(104,293),?)*mul(318,737)select()$%+>+~mul(402,74)!>how()}+mul(642,782)mul(714,667)+])mul(925,432,]~>mul(283,331)why()/*where()where()select()when()mul(243,952)/?{!!(mul(915,41);>(when()$#%mul(947,866)where()mul(221,297) select()>where()select()^$%mul(332,570)%]]mul(158,640)]don't()what(145,439)where() /-what()~ mul(800,255)mul(262,849)>}what()(how()why()^when()>mul(531,160)>(!;;from()mul(204,760)mul(513,132) ]why(657,793)[;>@[who()mul(884,112)-#/mul(29,581),when()[)'}:&mul(252,198)<<what()$['mul(919,291){select()select()]mul(239,410) do()mul(970,327)$when()-do()*!]&mul(851,279)select()how()where(){ # 'mul(159,479)} where()'-do()'select() !/who()select()'+{mul(692,852)who(105,599)??)mul(332,725)how(){mul(487,272)do()*:?why()-'mul(428,736)who(713,892)>select()?where()}$,~mul(814,493)!^where()?who() ][why()mul(654,203):&{]where()($[mul(635,667)%${}&$',mul(427,557) ~[{ %-mul(924,456)from(){^select()how()+mul(91,270)-<;>>don't()$?how()#<>{;mul(388how()?)mul(437,372),what()^/} !?when(423,466)-mul(413,767)+%!select()mul(404,30)]-,:when()when()mul(83,621)$mul(163,330)*when()!$?^^)${do()mul(836,70)how(146,272)*<-(+who(75,343)>}mul(326,92)]~())$(-!mul(377,382)mul(183,94)why()when()&from()don't();who()(? ?where()<<mul(908,788)who()-#[?mul(959,866)}>from()!;+?why()mul(766,106)how()*@;$mul(26,169)what()why()mul(407,336)select()mul(781,609)mul(567,131)%[when()<}mul(842,16)+(-~*}why(75,75)((mul(404,299)'];('select()&}(>mul(980,817),mul(759,27)when()$'mul(816,327)*&how()where()?*how(410,340)^mul(10,377)[mul#-<(+@mul(60,556)what()%;from() '%why()who()mul(71,194)]]@mul(54,618)when()['select()+(who()(~mul(615,986)] /how():+(&~mul(360,511)&how()don't()where()who()mul(387,887)?where()}#/what()what() mul(565,98)-!^?where()from(516,387)-}where()mul(852,909)~@where()%%why()}&-mul(964,784)#mul(351,184):)&mul(752,380)>mul(565,263));]mul(176,301)>^mul(724,532){how()~*,,{-mul(983,550){[select()>)mul(512}(]}-why()/why()mul(942,275),why()how()$;how()who()-?mul(111,602)where() ,)/{mul(647,51when()mul(752,155)]])]%/select()select(601,543)how(422,122)-mul(327,205)mul(108,233)select()how():do()},- when():mul(436,39) ?>:why()when()how()<mul(10,524){:~do();{?where()mul(523,67)[@[}({who()$mul(167,645)mul(305,169)$how() why()^,when()))mul(940,645),$(mul(964,882)[]? <@>@?mul(544,861)]when()% mul(171,396)$who()@'mul(98,466)-why()+-~#mul(202,977)mul(65,156)what()mul(916,837)select()']?>*$'>}mul(248,949)}']%who()where(44,472)&;why()how(272,628)don't()%):,where()select()what()how()when()%mul(119,722)*when()/'[?mul(235,988):what()($?}$how()-mul(401,478)#:why()'{}what()#mul(760,203)<;#[:mul(594,881)%#<mul(401,886)what():,:&(who(130,871)how()%don't()mul(647,315)^who()when()(mul(146,838)where(){~when()when()when())) who()mul(578,112)'%what()}who()mul(949,792)
|
||||||
|
> (when()[where()/#!/usr/bin/perl,@;mul(794,217)select():'])select()mul(801,192)why()&]why()/:]*#mul(319,363^:]when()^?[when()do()!%!/:#^select()mul(189,908what():mul(439,753)~+>mul(889,297)$#-select()$mul(665,576)/@do()when()@@<*?mul(783,215)how()%what()where(259,619)(who()((mul(101,739)@from():,)?'who()-when()mul(935,345)why():,~:[;why();mul(344,351)#from()who()where()~)when()what()/mul(349,325)?%*~~-select()]mul(677,728)from()$mul(34,791)when()/what()(mul(162,982)%+!why()!how())when()mul(352,740))%when()why()mul(409,310)mul(969,23)what()when()(>[who()why() @mul(6,54)>-what()from(58,461)'mul(465,807)(mul(526,458)how()}{:;*[&mul(396,93)([]who()]*mul(719,44)?what()}mul(144[}&'#,where()mul(404,362)[$/who()^mul(402,634)-who()<what(),mul(620,339)$mul(261,803)*what()$;&&)mul(494what()#<<-mul(644,769)when()what()[]]^-^';mul+don't()$who()>+mul(210,882)~select(){+where()mul(113,5)/]mul(686,939)why()why()?$?where()mul(893,419)how()mul(522,816)why()'&];don't()mul(564,983)),mul(752,484)~}<how()~^where()?[*mul(84,307);^)]mul(486,387){$mul(437,187)-}(/where(189,211)+where()}mul(61,751)^*:mul(479,564)-+!,[)from()?@$mul(370,558)when(556,327)@when()what()@]%$~who()mul(79,777)]&(-,don't()[#?~mul(2,290)!'*^-don't()(#from()'mul(509,224){}+how()@ where()&mul(439,15)/do());&&^]select(130,812)mul>!from(),mul(794,228)mul(666,12)!>[who()why()%:mul(942,336),%^%don't()mul(974,403)}()<^{@ mul(34~?')+ ^where()what(438,775)mul(398,351)%;#<when()-~;where()mul(237,706)select()how(){;[+:who()-,mul(73,367)'<mul(258,509)[[?mul(734,571)select()?[mul(677,408);{;?,!~:select();mul(273,622))/^mul(213,14)^%*why()]select()-mul(785,933)mul(875,534)}mul(273,704)%where()*when():{::;[mul(403,147)/<$'!,;mul(575,503)?!{))[why()~$;mul(719,207)~*]why()mul(324,720)from())#;/}mul(553,685)how(332,401)!why()!mul(530,711){what(),])/!from()who(560,911)mul(952,650)&what()mul(987,390@what()*+^do()]what()]~&mul(92,809};from()&)^where()$^>*mul(608,425)-how();what(581,569)/}(where()mul(657,344)mul(952,983):mul(563,153))##~*<('who(910,367)mul(597,553)]) +}&/,mul(42,25)^-where()- {&?>mul(243,985)(where()what()mul(748,181)why()<*how()~ ]why()mul(513,836)^mul(528,931)^from()%mul(394,906)>&what()why()}select()mul(748,101)@{:mul(588,99)+^<]select()what()mul(762,499)*who()}mul(115,70)::$%>}mul(358,497)*$%how()mul(4from()>!]*>$)#how()from()don't()[{when()#where()why()where()why()mul(673,980)who(449,344)/@mul(632,452)from()where()*how()}?)][[mul(827,726)@~from()-mul(248,669)mul(745,698){mul(701<:how()what()mul(507,429)}when(638,137)mul(205,534)what(),{mul(98,543)do(),/*</;;<-;mul(47,166/from()~select()/$(mul(324,444))%[,],,mul(300@when(),why()where()how()why()(why()*@mul(504,369)*']%!mul(272,976);?}how()&]#from()'from()mul(380,961)mul(701,103)what()who()mul(57,637)!#when()'%{do()?*!from()<[>when()mul(242,591)#where()+mul(727,599);who()mul(127,428)'why()[';mul(731,342)%:$who()<what()]^mul(601,697){{%:[*mul(603,37)}?mul(937,728)[mul(305,102)?:who()@%^$mul(296,72)-!how()[select()]+%mul(132,763)mul(97,481)select()-mul(454,506)mul(814,106) !&}^^>what()$+do()*mul(739,211):'' !what()?,&]mul(87,206)+,who()>/&^~select(648,639)<mul(442,17)what()[-where()mul(452,266)why()how()#%[>!,mul(262,674)
|
||||||
|
,+who():mul(327,845)/ >@[>@}}mul(86,371)!~&&~how(79,334)mul(637,103)why()mul(358,845)-#~?why(243,672)select()+why()from()~mul(216,782)&mul(111,955)<?why()@ who()-^mul(791,328);how() %+]mul(946,620)why();+;how()~<]mul(623,64):<'<mul(986,415)#)[/(where()mul;*[({,-?#)#mul(38,403)^mul(91,193)who(573,63)select()'<!what() :why()mul(464,529)}(]>;what()~mul(677,376)select()when()mul(576,14)!}mul(70,850)^::select()what()mul(705,544)how(707,500)-where()how()what()mul(830,398)who()!do()mul(626,675)+where()<}who():mul(574,508)!;mul(306,829)&+)>what()@<{[~mul(795who()#*'where()who()?mul(548,420)*) %:when()when()mul(332,202)when()'where()^mul(72,648)]mul(866,929)mul(444,217}#mul(563,200)*select(581,639)!}who()/how()$mul(584,32)select(27,591)[#'mul(401,424)>,),mul(781&select()do()}what()#what()@what()<;mul(897,939)+where(),why()%mulhow()%where(203,705)mul(389,118)-what()select()&how())*@ <mul(146,178)%select()*why();mul(386,610)why()where()+why()?$how()mul(278[(where()who() (from()*[mul(178,632)@how()(mul(822,859)mul(774,887)!(} select()>$mul(316,546);]when()^-mul(730when()why()'+:*mul(433,570);-/]:select()(*#who()mul(12,582)[from()(how()!who()?)&,mul(474,681)mul(288,311)mul(281,240what()select()<when()<mul(934,466)%+%@where()^+{mul(628,780)how()@select()mul(813,147)!do()from(486,200)->{!mul(564,631)@'<[how()mul(972,373)mul(188,118)mul(630,960),/mul(105,916)how()#/mul(215,263)when():mul(257,474)[what()mul(565,99)*mul(195,386)[mul(695,513)from()#mulhow()mul(354,472)%-^when()%:}mul(420,822)]&mul(409,240)@where()!mul(65,591)mul(2,270)-]))from()mul(895,507){-what()^?#~ mul(13,268):why(919,274)]mul(37,808)}])why()+#+mul(19,585)from()how()%:$(where()mul(457,746)]mul(715,809)]+mul(542,65)@/):how(169,336)?when()~mul(871,498)]/{~~who()mul(438,984)what()from(289,777)/*}:*$%mul(176,297)&mul(404,56))mul(617,647)!when(){^what()why()}<^mul(412,110)where())#how()#;where()%&,mul(158,588) ~ from()'-^[select()mul(383,762)mul(215,479)%/:where()#[)who(567,411)mul(618,506)'from()}/how() )'~{mul(597,824)mul(130,88)when()-*how(891,580)mul(673,686);what()';,mul(404,486)-:when():&:$/??mul(335,183)/select()#why()what()who(396,219)mul(209,514)->)when()>;!>/from()mul(290,830) /what()~,mul(127,362)[%select()!mul(218,584)**}%'where()mul(806,757)when()>select()!why(343,900)(mul(416,926),&don't()#mul(140,136)(^mul(586,293)'from()~;)$mul(465,127)mul(50,37)select()from()how() )when()@/select()when()mul(268,549)~from()#)]why()^;?mul(928,48)where()&!mul(238,685)(/,mul(868,701)'* why()what()how()<%<-mul(147,775)(%%from();;mul(485,402){select()~,%]^mul(497,239)why()(mul(483,579)!mul(633,187)from(){how()'-[;$-mul(351,722)from()mul(376,405)mul(773,301)mul(714,478)&'&( mul(15,892)from()/when()}/^<who()'mul(7,951),from()'how()?*%don't()?$+what()#mul(430,674from()mul(503,262)]*,>;>#,mul(416,32)~?@(<what(984,491)@mul(97from()<<>*>'when():who()where()mul(550,92)mul(706,856){from()*from()mul(129,641)*from())where()mul(361,904)>why()mul(556,900)#/;,how()?mul(820,572)
|
||||||
|
where()#{*,!?:$mul(204,279)what()!{ what()mul(117,94)!select()>:mul(665,432)#don't()!!<!? mul(50,841)how()+~!]when(545,106)],%mul(69,679)how());how()#mul}$select()mul(29,553)when()+mul(242,498)?select(420,93)mul(879,710(mul(658,290)))+,-&mul(806,363)(#&]^+/?mul(462,199)mul(67,623)from()/{~^<}}when()mul(329,771);{]*#>]{mulwhen()'<how()]*what()>+{mul(533,772)why(708,386)mul(985,538)how()where()<%@;*mul(541,123)*/when()do()*@mul(689,5)]from()]~{@<[mul(624,102)how()*select()['?what()},;mul(689,339)when(),from()where()how(741,43)what()when()mul(976,335)$^mul(488,361)how()'?*$:don't()-/>%:why():from()+mul(273,731)?$?*what(312,921);{->mul(258,938)'mul(744,815)~!who()>[who()@(who()mul@select()when()&mul(244,475)@mul(642,298)'>when()+from()<{mul(73,293)do()what()}??when()from()mul(989,486)what()^mul(353,226)?%where()}]%,mul(452,316):~mul(156,967)?!mul(19,394)!,},when()<@mul-[</>>,mul(174,673):>#mul(874,712)from()])what(),'@how(667,413)(;mul(241,907)mul(320,563#{how()(mul(124,628)^!select()from(935,468)@when()when()<who(491,64)(mul(125,59)when()*!:where()why()~why()mul(804,677)where(307,856))]!*~mul(879,424)from():$''@;mul(884,639)*?[who()what()^$mul(734,624)?how(521,975)>-'how(466,423);mul(279,559)why()!$what(){:{why()from()mul(649,790);,?%&'/why()^&mul(534,924)>-!?when(){~$mul(158,17?#mul(968,123)what()who()>mul(250,420)mul(337,422)}(how()>-{*- do()+(}~(,>who()mul(76,293);mul(293,210)*+?mul(438,928)]%~,%/#@[mul(183,794)+how() ;>}who()mul(332,416),why(801,76),+%don't())select(){where()what();-who()-mul(606,374)mul(534,560)$:~who()/ )%mul(51,112)%[<]<select()?<mul(471,577)who()!when(523,517)@%*{how()mul(52,512)mul(310,351);*!*what()-?#mul(617,189)^?when()/mul(936,553)& <':'&select()[mul(373,275)mul(892,327)++how(627,5)^&^'/@$mul(186,664)'why(672,157)?*?mul(878,211)%>;-(mul(713,297)how()mul(865,283)when()?[!;from()^%mul(852,418)mul(981,822)+&/{from()}{]what(134,416)when()mul(106,954)@who()>]why(){')&mul(638,435))! where(256,980)/from()?mul(742,736)mul(178,260)!select()do()!~mul(235,409)mul(4,876)&#:/how()how())mul(779,7)who()[]mul(257,563)who()from()mul(269,328):don't()^;?who()&how() mul(940,691)*'+how()%&mul(207,615)mul(22,730)}){;what(777,379)~who()~!mul(304,887)!$how()mul(897,888)?>*when()]/mul(28,168)when()+^:*}>mul(383,29)mul(467,873)@/-, <from(522,355)<^mul(670,942)])?^why()where()do()mul(152,343);$>]-from()%*mul(520,584)-how()(select()>^{$:<mul(585,847)select()how():'mul(205,503) }[why()mul(480,92)mul(439,908)?when()from()+[where()mul(190,679)#?@}<$mul(756,714) $*(!>(][-mul(866,764):[@,;?<mul(258,363)*>*}*@]when()mul(702,803)mul(417,62)from()-mul(405,512){)]/from()&mul(680,378)from()mul(272,215)-<when() how()}/mul(342,699):$mul(230,407)},~^what(),don't() what()mul(579,949)mul(32,967)why(833,463)^!when()[&-when()@mul(778,295)-where()why()]from()what() why()mul(872,242)where()~@?what()do():+/[when()'^mul(272,456)select()@@&[from()why()why()!mul(656,911)^mul(369,320)[%who(918,33)mul(430,762)don't()*,)>mul(678,155)]:why()who()@/how():@mul(327,946)!#when()+mul(484,853)!+?
|
||||||
152
utils.zig
Normal file
152
utils.zig
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
// pub const LineReader = struct {
|
||||||
|
// const FileReader = std.fs.File.Reader;
|
||||||
|
// const BufferedReader = std.io.BufferedReader(4096, FileReader);
|
||||||
|
// const Reader = std.io.Reader(*BufferedReader, std.fs.File.Reader.Error, BufferedReader.read);
|
||||||
|
|
||||||
|
// alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
// file: std.fs.File,
|
||||||
|
|
||||||
|
// line_buf: std.ArrayList(u8),
|
||||||
|
|
||||||
|
// buf_reader: *BufferedReader,
|
||||||
|
// reader: Reader,
|
||||||
|
|
||||||
|
// pub fn init(alloc: std.mem.Allocator, filename: []const u8) !LineReader {
|
||||||
|
// const file = try std.fs.cwd().openFile(filename, .{});
|
||||||
|
|
||||||
|
// const file_reader = file.reader();
|
||||||
|
|
||||||
|
// const buf_reader = try alloc.create(BufferedReader);
|
||||||
|
// buf_reader.* = std.io.bufferedReader(file_reader);
|
||||||
|
|
||||||
|
// const reader: Reader = Reader{ .context = buf_reader };
|
||||||
|
|
||||||
|
// const line_buf = std.ArrayList(u8).init(alloc);
|
||||||
|
|
||||||
|
// return .{
|
||||||
|
// .alloc = alloc,
|
||||||
|
// .file = file,
|
||||||
|
// .line_buf = line_buf,
|
||||||
|
// .buf_reader = buf_reader,
|
||||||
|
// .reader = reader,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn deinit(self: *LineReader) void {
|
||||||
|
// self.file.close();
|
||||||
|
|
||||||
|
// self.line_buf.deinit();
|
||||||
|
|
||||||
|
// self.alloc.destroy(self.buf_reader);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn next(self: *LineReader) !?[]u8 {
|
||||||
|
// self.line_buf.clearRetainingCapacity();
|
||||||
|
|
||||||
|
// self.reader.streamUntilDelimiter(self.line_buf.writer(), '\n', 4096) catch |err| switch (err) {
|
||||||
|
// error.EndOfStream => return null,
|
||||||
|
// else => return err,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return self.line_buf.items;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
pub const FileReader = struct {
|
||||||
|
const BufferedReader = std.io.BufferedReader(4096, std.fs.File.Reader);
|
||||||
|
const Reader = std.io.Reader(*BufferedReader, std.fs.File.Reader.Error, BufferedReader.read);
|
||||||
|
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
file: std.fs.File,
|
||||||
|
|
||||||
|
buf_reader_ptr: *BufferedReader,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, filename: []const u8) !FileReader {
|
||||||
|
const file = try std.fs.cwd().openFile(filename, .{});
|
||||||
|
|
||||||
|
const file_reader = file.reader();
|
||||||
|
|
||||||
|
const buf_reader_ptr = try alloc.create(BufferedReader);
|
||||||
|
buf_reader_ptr.* = std.io.bufferedReader(file_reader);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.file = file,
|
||||||
|
.buf_reader_ptr = buf_reader_ptr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: FileReader) void {
|
||||||
|
self.file.close();
|
||||||
|
|
||||||
|
self.alloc.destroy(self.buf_reader_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reader(self: FileReader) Reader {
|
||||||
|
return Reader{ .context = self.buf_reader_ptr };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn LineReader(comptime ReaderType: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
reader: ReaderType,
|
||||||
|
|
||||||
|
line_buf: std.ArrayList(u8),
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, reader: ReaderType) Self {
|
||||||
|
const line_buf = std.ArrayList(u8).init(alloc);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.reader = reader,
|
||||||
|
.line_buf = line_buf,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.line_buf.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: *Self) !?[]u8 {
|
||||||
|
self.line_buf.clearRetainingCapacity();
|
||||||
|
|
||||||
|
self.reader.streamUntilDelimiter(self.line_buf.writer(), '\n', 4096) catch |err| switch (err) {
|
||||||
|
error.EndOfStream => if (self.line_buf.items.len == 0) {
|
||||||
|
// the first time we get an EndOfStream we return the content of the line_buf,
|
||||||
|
// the second time we're finished
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
|
||||||
|
return self.line_buf.items;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lineReader(alloc: std.mem.Allocator, reader: anytype) LineReader(@TypeOf(reader)) {
|
||||||
|
return LineReader(@TypeOf(reader)).init(alloc, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn NumberParser(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
token_it: std.mem.TokenIterator(u8, .scalar),
|
||||||
|
|
||||||
|
pub fn next(self: *@This()) !?T {
|
||||||
|
if (self.token_it.next()) |tok| {
|
||||||
|
return try std.fmt.parseUnsigned(T, tok, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn numberParser(comptime T: type, input: []const u8) NumberParser(T) {
|
||||||
|
return NumberParser(T){ .token_it = std.mem.tokenizeScalar(u8, input, ' ') };
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue