const std = @import("std");
const Str = []const u8;
const INPUT = "cqjxjnds";
pub fn first(allocator: std.mem.Allocator) !Str {
var input: [INPUT.len]u8 = undefined;
for (INPUT) |ch, idx| {
input[idx] = ch;
}
return std.fmt.allocPrint(allocator, "{s}", .{nextPw(&input)});
}
pub fn second(allocator: std.mem.Allocator) !Str {
var input: [INPUT.len]u8 = undefined;
for (INPUT) |ch, idx| {
input[idx] = ch;
}
_ = nextPw(&input);
// move the pw forward
movePw(&input);
return std.fmt.allocPrint(allocator, "{s}", .{nextPw(&input)});
}
test "day11a" {
const res = try first(std.testing.allocator);
defer std.testing.allocator.free(res);
try std.testing.expectEqualStrings("cqjxxyzz", res);
}
test "day11b" {
const res = try second(std.testing.allocator);
defer std.testing.allocator.free(res);
try std.testing.expectEqualStrings("cqkaabcc", res);
}
fn nextPw(in: []u8) Str {
// change the first disallowed char in advance
for (in) |*ch, idx| {
switch (ch.*) {
'i', 'o', 'l' => {
ch.* = ch.* + 1;
idx += 1;
while (idx < in.len) : (idx += 1) {
in[idx] = 'a';
}
break;
},
else => {},
}
}
while (true) {
if (checkPw(in)) return in;
movePw(in);
}
unreachable;
}
test "nextPw" {
var input: [8]u8 = .{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
try std.testing.expectEqualStrings("abcdffaa", nextPw(&input));
input = .{ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n' };
try std.testing.expectEqualStrings("ghjaabcc", nextPw(&input));
}
fn movePw(in: []u8) void {
var idx: usize = 8;
while (idx > 0) : (idx -= 1) {
if (in[idx - 1] == 'z') {
in[idx - 1] = 'a';
} else {
in[idx - 1] = in[idx - 1] + 1;
break;
}
}
}
fn checkPw(in: Str) bool {
if (in.len < 3) return false;
var straight: bool = false;
var st_start: u8 = in[0];
var doubles: usize = 0;
var db_prev: u8 = in[0];
var overlap: bool = false;
var idx: usize = 1;
while (idx < in.len) : (idx += 1) {
switch (in[idx]) {
'i', 'o', 'l' => return false,
else => {
// check straight
if (!straight and idx != in.len - 1) {
if (in[idx] - 1 == st_start and in[idx + 1] - 2 == st_start) {
straight = true;
} else {
st_start = in[idx];
}
}
// check doubles
if (doubles < 2 and !overlap) {
// std.debug.print("{}: {c} {c}\n", .{ idx, db_prev, in[idx] });
if (in[idx] == db_prev) {
doubles += 1;
overlap = true;
}
} else {
overlap = false;
}
db_prev = in[idx];
},
}
}
// std.debug.print("{s}: {} {}\n", .{ in, straight, doubles });
return straight and (doubles > 1);
}
test "checkPw" {
try std.testing.expectEqual(false, checkPw("hijklmmn"));
try std.testing.expectEqual(false, checkPw("abbceffg"));
try std.testing.expectEqual(false, checkPw("abbcegjk"));
try std.testing.expectEqual(false, checkPw("abcdefgh"));
try std.testing.expectEqual(true, checkPw("abcdffaa"));
try std.testing.expectEqual(false, checkPw("ghijklmn"));
try std.testing.expectEqual(true, checkPw("ghjaabcc"));
}