Part1
const std = @import("std");
pub fn ndigits(number: usize) usize {
if (number == 0) {
return 1;
}
const lognumber = std.math.log10_int(number);
return lognumber + 1;
}
test "ndigits" {
try std.testing.expectEqual(1, ndigits(0));
try std.testing.expectEqual(1, ndigits(1));
try std.testing.expectEqual(1, ndigits(9));
try std.testing.expectEqual(2, ndigits(10));
try std.testing.expectEqual(2, ndigits(90));
try std.testing.expectEqual(3, ndigits(100));
try std.testing.expectEqual(3, ndigits(999));
try std.testing.expectEqual(4, ndigits(1000));
try std.testing.expectEqual(4, ndigits(9999));
}
pub fn validID(id: usize) bool {
const ndig = ndigits(id);
if (@mod(ndig, 2) != 0) {
return true;
}
const filter = std.math.powi(usize, 10, ndig / 2) catch {
unreachable;
};
const head = id / filter;
const tail = @mod(id, filter);
return head != tail;
}
test "validID" {
try std.testing.expectEqual(true, validID(1));
try std.testing.expectEqual(true, validID(111));
try std.testing.expectEqual(true, validID(11111));
try std.testing.expectEqual(false, validID(11));
try std.testing.expectEqual(false, validID(22));
try std.testing.expectEqual(false, validID(6464));
try std.testing.expectEqual(false, validID(222222));
try std.testing.expectEqual(false, validID(1188511885));
try std.testing.expectEqual(false, validID(38593859));
try std.testing.expectEqual(true, validID(12));
try std.testing.expectEqual(true, validID(32));
try std.testing.expectEqual(true, validID(6364));
try std.testing.expectEqual(true, validID(212222));
try std.testing.expectEqual(true, validID(1178511885));
try std.testing.expectEqual(true, validID(38593858));
}
pub fn main() !void {
var dba = std.heap.DebugAllocator(.{}){};
defer _ = dba.deinit();
const allocator = dba.allocator();
var stdout_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
var stderr_buffer: [1024]u8 = undefined;
var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
const stderr = &stderr_writer.interface;
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len < 2) {
try stderr.print("Usage: {s} <filename>\n", .{args[0]});
try stderr.flush();
return error.InvalidArguments;
}
const filename = args[1];
const file = try std.fs.cwd().openFile(filename, .{});
defer file.close();
const file_size = try file.getEndPos();
const input = try allocator.alloc(u8, file_size);
defer allocator.free(input);
const bytes_read = try file.readAll(input);
if (bytes_read != file_size) {
try stderr.print("Warning: Read {d} bytes but expected {d}\n", .{ bytes_read, file_size });
}
var sum: usize = 0;
var lines = std.mem.tokenizeScalar(u8, input, '\n');
while (lines.next()) |line| {
var ranges = std.mem.tokenizeScalar(u8, line, ',');
while (ranges.next()) |range| {
var fields = std.mem.tokenizeScalar(u8, range, '-');
const lower = try std.fmt.parseInt(usize, fields.next().?, 10);
const upper = try std.fmt.parseInt(usize, fields.next().?, 10);
for (lower..upper + 1) |id| {
if (!validID(id)) {
//std.debug.print("{s} -> {d}\n", .{ range, id });
sum += id;
}
}
}
}
try stdout.print("Sum of invalid IDs: {d}\n", .{sum});
try stdout.flush();
}
Part2
const std = @import("std");
pub fn ndigits(number: usize) usize {
if (number == 0) {
return 1;
}
const lognumber = std.math.log10_int(number);
return lognumber + 1;
}
test "ndigits" {
try std.testing.expectEqual(1, ndigits(0));
try std.testing.expectEqual(1, ndigits(1));
try std.testing.expectEqual(1, ndigits(9));
try std.testing.expectEqual(2, ndigits(10));
try std.testing.expectEqual(2, ndigits(90));
try std.testing.expectEqual(3, ndigits(100));
try std.testing.expectEqual(3, ndigits(999));
try std.testing.expectEqual(4, ndigits(1000));
try std.testing.expectEqual(4, ndigits(9999));
}
pub fn validID(id: usize) bool {
const ndig = ndigits(id);
if (ndigits(id) == 1) {
return true;
}
//std.log.warn("{d}: len={d}:", .{ id, ndig });
for (1..ndig / 2 + 1) |tfilterlen| {
const filterlen = ndig / 2 + 1 - tfilterlen;
if (@mod(ndig, filterlen) != 0) {
continue;
}
const filter_tail = std.math.powi(usize, 10, filterlen) catch {
unreachable;
};
const tail = @mod(id, filter_tail);
//std.log.warn(" filterl={d}, tail={d}", .{ filter_tail, tail });
var valid = false;
for (2..ndig / filterlen + 1) |igroup| {
const filter_head = std.math.powi(usize, filter_tail, igroup) catch {
unreachable;
};
const filter_headl = std.math.powi(usize, filter_tail, igroup - 1) catch {
unreachable;
};
const head = @mod(id, filter_head) / filter_headl;
//std.log.warn(" filterh={d}, head={d}", .{ filter_head, head });
if (head != tail) {
valid = true;
}
}
if (!valid) {
return false;
}
}
return true;
}
test "validID" {
try std.testing.expectEqual(true, validID(1));
try std.testing.expectEqual(true, validID(123456));
try std.testing.expectEqual(false, validID(11));
try std.testing.expectEqual(false, validID(22));
try std.testing.expectEqual(false, validID(6464));
try std.testing.expectEqual(false, validID(222222));
try std.testing.expectEqual(false, validID(1188511885));
try std.testing.expectEqual(false, validID(38593859));
try std.testing.expectEqual(false, validID(12341234));
try std.testing.expectEqual(false, validID(123123123));
try std.testing.expectEqual(false, validID(1212121212));
try std.testing.expectEqual(false, validID(1111111));
try std.testing.expectEqual(true, validID(12));
try std.testing.expectEqual(true, validID(32));
try std.testing.expectEqual(true, validID(6364));
try std.testing.expectEqual(true, validID(212222));
try std.testing.expectEqual(true, validID(1178511885));
try std.testing.expectEqual(true, validID(38593858));
try std.testing.expectEqual(true, validID(1138138));
}
pub fn main() !void {
var dba = std.heap.DebugAllocator(.{}){};
defer _ = dba.deinit();
const allocator = dba.allocator();
var stdout_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
var stderr_buffer: [1024]u8 = undefined;
var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
const stderr = &stderr_writer.interface;
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len < 2) {
try stderr.print("Usage: {s} <filename>\n", .{args[0]});
try stderr.flush();
return error.InvalidArguments;
}
const filename = args[1];
const file = try std.fs.cwd().openFile(filename, .{});
defer file.close();
const file_size = try file.getEndPos();
const input = try allocator.alloc(u8, file_size);
defer allocator.free(input);
const bytes_read = try file.readAll(input);
if (bytes_read != file_size) {
try stderr.print("Warning: Read {d} bytes but expected {d}\n", .{ bytes_read, file_size });
}
var sum: usize = 0;
var lines = std.mem.tokenizeScalar(u8, input, '\n');
while (lines.next()) |line| {
var ranges = std.mem.tokenizeScalar(u8, line, ',');
while (ranges.next()) |range| {
var fields = std.mem.tokenizeScalar(u8, range, '-');
const lower = try std.fmt.parseInt(usize, fields.next().?, 10);
const upper = try std.fmt.parseInt(usize, fields.next().?, 10);
for (lower..upper + 1) |id| {
if (!validID(id)) {
//std.debug.print("{s} -> {d}\n", .{ range, id });
sum += id;
}
}
}
}
try stdout.print("Sum of invalid IDs: {d}\n", .{sum});
try stdout.flush();
}