Partial solution to 21-1
Got the ability to generate a set of directional-pushes that lead to a numerical input. Now we "just" need to do the same thing for directional-to-directional, then plumb them together, then we're done. Easy, right? :P
This commit is contained in:
parent
36abfed74c
commit
ba85344b3d
355
solutions/21.zig
355
solutions/21.zig
@ -3,6 +3,77 @@ const util = @import("util.zig");
|
|||||||
const Point = util.Point;
|
const Point = util.Point;
|
||||||
const expect = std.testing.expect;
|
const expect = std.testing.expect;
|
||||||
|
|
||||||
|
fn shortestDirectionalPushesToEnterNumericSequence(numericSequence: []const u8, allocator: std.mem.Allocator) []const []const u8 {
|
||||||
|
var cur_number: u8 = 10;
|
||||||
|
var sequences_so_far = std.StringHashMap(void).init(allocator);
|
||||||
|
defer sequences_so_far.deinit();
|
||||||
|
sequences_so_far.put(allocator.dupe(u8, &.{}) catch unreachable, {}) catch unreachable;
|
||||||
|
|
||||||
|
var new_candidate_sequences = std.StringHashMap(void).init(allocator);
|
||||||
|
defer new_candidate_sequences.deinit();
|
||||||
|
|
||||||
|
for (numericSequence) |c| {
|
||||||
|
std.debug.print("Consuming {c} from numericSequence\n", .{c});
|
||||||
|
const numericSequenceCharAsNumber = numericSequenceCharToNumber(c);
|
||||||
|
const moves = shortestSequencesToMoveNumericFromAToB(cur_number, numericSequenceCharAsNumber, allocator);
|
||||||
|
std.debug.print("DEBUG - moves are:\n", .{});
|
||||||
|
for (moves) |move| {
|
||||||
|
printDirectionSeqAsDirections(move);
|
||||||
|
std.debug.print("\n", .{});
|
||||||
|
}
|
||||||
|
const movesWithEnter = appendSequencesWith(moves, 65, allocator);
|
||||||
|
std.debug.print("And with a trailing `A`, they are:\n", .{});
|
||||||
|
for (movesWithEnter) |move| {
|
||||||
|
printDirectionSeqAsDirections(move);
|
||||||
|
std.debug.print("\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
var seq_it = sequences_so_far.keyIterator();
|
||||||
|
while (seq_it.next()) |seq_so_far| {
|
||||||
|
for (movesWithEnter) |new_moves| {
|
||||||
|
std.debug.print("About to concat these moves:", .{});
|
||||||
|
printDirectionSeqAsDirections(seq_so_far.*);
|
||||||
|
std.debug.print(", ", .{});
|
||||||
|
printDirectionSeqAsDirections(new_moves);
|
||||||
|
std.debug.print("\n", .{});
|
||||||
|
new_candidate_sequences.put(util.concatString(seq_so_far.*, new_moves) catch unreachable, {}) catch unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (movesWithEnter) |new_moves| {
|
||||||
|
allocator.free(new_moves);
|
||||||
|
}
|
||||||
|
allocator.free(movesWithEnter);
|
||||||
|
|
||||||
|
// At this point, `new_candidate_sequences` contains all the new aggregated sequences - so, transfer them to
|
||||||
|
// `sequences_so_far`.
|
||||||
|
// TODO - not sure if I should be trimming to shortest _here_, or only at the end.
|
||||||
|
cur_number = numericSequenceCharAsNumber;
|
||||||
|
|
||||||
|
sequences_so_far.clearRetainingCapacity();
|
||||||
|
var cands_it = new_candidate_sequences.keyIterator();
|
||||||
|
while (cands_it.next()) |next| {
|
||||||
|
sequences_so_far.put(next.*, {}) catch unreachable;
|
||||||
|
}
|
||||||
|
new_candidate_sequences.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = std.ArrayList([]const u8).init(allocator);
|
||||||
|
var seq_it = sequences_so_far.keyIterator();
|
||||||
|
while (seq_it.next()) |next| {
|
||||||
|
response.append(next.*) catch unreachable;
|
||||||
|
}
|
||||||
|
return response.toOwnedSlice() catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translates from "the Unicode number _of_ the number" to "the actual number" (or, from A=>10)
|
||||||
|
fn numericSequenceCharToNumber(numericSequenceChar: u8) u8 {
|
||||||
|
return switch (numericSequenceChar) {
|
||||||
|
48...57 => numericSequenceChar - 48,
|
||||||
|
65 => 10,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Use `10` to represent `A`
|
// Use `10` to represent `A`
|
||||||
// If we wanted, we could introduce a `rotate` function to, say, define `1->6` in terms of `7->2` - but I think that's
|
// If we wanted, we could introduce a `rotate` function to, say, define `1->6` in terms of `7->2` - but I think that's
|
||||||
// over-abstraction.
|
// over-abstraction.
|
||||||
@ -20,33 +91,33 @@ fn shortestSequencesToMoveNumericFromAToB(a: u8, b: u8, allocator: std.mem.Alloc
|
|||||||
allocator.free(sequencesForBToA);
|
allocator.free(sequencesForBToA);
|
||||||
return op.toOwnedSlice() catch unreachable;
|
return op.toOwnedSlice() catch unreachable;
|
||||||
}
|
}
|
||||||
// God bless https://stackoverflow.com/a/77248553 for showing me how to initialize a slice of slices!
|
// Taking inspiration from https://ziggit.dev/t/how-to-free-or-identify-a-slice-literal/8188/3
|
||||||
return switch (a) {
|
return switch (a) {
|
||||||
0 => switch (b) {
|
0 => switch (b) {
|
||||||
1 => &.{&.{ '^', '<' }},
|
1 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '^', '<' }) catch unreachable}) catch unreachable,
|
||||||
2 => &.{&.{'^'}},
|
2 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'^'}) catch unreachable}) catch unreachable,
|
||||||
3 => &.{ &.{ '^', '>' }, &.{ '>', '^' } },
|
3 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^' }) catch unreachable }) catch unreachable,
|
||||||
4 => &.{ &.{ '^', '^', '<' }, &.{ '^', '<', '^' } },
|
4 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '^', '<', '^' }) catch unreachable }) catch unreachable,
|
||||||
5 => &.{&.{ '^', '^' }},
|
5 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '^', '^' }) catch unreachable}) catch unreachable,
|
||||||
6 => &.{ &.{ '^', '^', '>' }, &.{ '^', '>', '^' }, &.{ '>', '^', '^' } },
|
6 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '^', '>', '^' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^', '^' }) catch unreachable }) catch unreachable,
|
||||||
7 => {
|
7 => {
|
||||||
const twoToSeven = shortestSequencesToMoveNumericFromAToB(2, 7, allocator);
|
const twoToSeven = shortestSequencesToMoveNumericFromAToB(2, 7, allocator);
|
||||||
return prependSequencesWith(twoToSeven, '^', allocator);
|
return prependSequencesWith(twoToSeven, '^', allocator);
|
||||||
},
|
},
|
||||||
8 => &.{&.{ '^', '^', '^' }},
|
8 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '^', '^', '^' }) catch unreachable}) catch unreachable,
|
||||||
9 => &.{ &.{ '^', '^', '^', '>' }, &.{ '^', '^', '>', '^' }, &.{ '^', '>', '^', '^' }, &.{ '>', '^', '^', '^' } },
|
9 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '^', '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '^', '^', '>', '^' }) catch unreachable, allocator.dupe(u8, &.{ '^', '>', '^', '^' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^', '^', '^' }) catch unreachable }) catch unreachable,
|
||||||
10 => &.{&.{'>'}},
|
10 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'>'}) catch unreachable}) catch unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
1 => switch (b) {
|
1 => switch (b) {
|
||||||
0 => &.{&.{ '>', 'V' }},
|
0 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '>', 'v' }) catch unreachable}) catch unreachable,
|
||||||
2 => &.{&.{'>'}},
|
2 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'>'}) catch unreachable}) catch unreachable,
|
||||||
3 => &.{&.{ '>', '>' }},
|
3 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '>', '>' }) catch unreachable}) catch unreachable,
|
||||||
4 => &.{&.{'^'}},
|
4 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'^'}) catch unreachable}) catch unreachable,
|
||||||
5 => &.{ &.{ '^', '>' }, &.{ '>', '^' } },
|
5 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^' }) catch unreachable }) catch unreachable,
|
||||||
6 => &.{ &.{ '^', '>', '>' }, &.{ '>', '^', '>' }, &.{ '>', '>', '^' } },
|
6 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '>', '>' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '>', '>', '^' }) catch unreachable }) catch unreachable,
|
||||||
7 => &.{&.{ '^', '^' }},
|
7 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '^', '^' }) catch unreachable}) catch unreachable,
|
||||||
8 => &.{ &.{ '^', '^', '>' }, &.{ '^', '>', '^' }, &.{ '>', '^', '^' } },
|
8 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '^', '>', '^' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^', '^' }) catch unreachable }) catch unreachable,
|
||||||
9 => {
|
9 => {
|
||||||
const fourToNine = shortestSequencesToMoveNumericFromAToB(4, 9, allocator);
|
const fourToNine = shortestSequencesToMoveNumericFromAToB(4, 9, allocator);
|
||||||
const fourBasedMoves = prependSequencesWith(fourToNine, '^', allocator);
|
const fourBasedMoves = prependSequencesWith(fourToNine, '^', allocator);
|
||||||
@ -55,24 +126,24 @@ fn shortestSequencesToMoveNumericFromAToB(a: u8, b: u8, allocator: std.mem.Alloc
|
|||||||
const twoBasedMoves = prependSequencesWith(twoToNine, '>', allocator);
|
const twoBasedMoves = prependSequencesWith(twoToNine, '>', allocator);
|
||||||
return joinSlices(fourBasedMoves, twoBasedMoves, allocator);
|
return joinSlices(fourBasedMoves, twoBasedMoves, allocator);
|
||||||
},
|
},
|
||||||
10 => &.{ &.{ '>', '>', 'V' }, &.{ '>', 'V', '>' } },
|
10 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '>', '>', 'v' }) catch unreachable, allocator.dupe(u8, &.{ '>', 'v', '>' }) catch unreachable }) catch unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
2 => switch (b) {
|
2 => switch (b) {
|
||||||
3 => &.{&.{'>'}},
|
3 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'>'}) catch unreachable}) catch unreachable,
|
||||||
4 => &.{ &.{ '^', '<' }, &.{ '<', '^' } },
|
4 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^' }) catch unreachable }) catch unreachable,
|
||||||
5 => &.{&.{'^'}},
|
5 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'^'}) catch unreachable}) catch unreachable,
|
||||||
6 => &.{ &.{ '^', '>' }, &.{ '>', '^' } },
|
6 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^' }) catch unreachable }) catch unreachable,
|
||||||
7 => &.{ &.{ '^', '^', '<' }, &.{ '^', '<', '^' }, &.{ '<', '^', '^' } },
|
7 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '^', '<', '^' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^', '^' }) catch unreachable }) catch unreachable,
|
||||||
8 => &.{&.{ '^', '^' }},
|
8 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '^', '^' }) catch unreachable}) catch unreachable,
|
||||||
9 => &.{ &.{ '^', '^', '>' }, &.{ '^', '>', '^' }, &.{ '>', '^', '^' } },
|
9 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '^', '>', '^' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^', '^' }) catch unreachable }) catch unreachable,
|
||||||
10 => &.{ &.{ '>', 'V' }, &.{ 'V', '>' } },
|
10 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '>', 'v' }) catch unreachable, allocator.dupe(u8, &.{ 'v', '>' }) catch unreachable }) catch unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
3 => switch (b) {
|
3 => switch (b) {
|
||||||
4 => &.{ &.{ '^', '<', '<' }, &.{ '<', '^', '<' }, &.{ '<', '<', '^' } },
|
4 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '<', '<' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '<', '<', '^' }) catch unreachable }) catch unreachable,
|
||||||
5 => &.{ &.{ '^', '<' }, &.{ '<', '^' } },
|
5 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^' }) catch unreachable }) catch unreachable,
|
||||||
6 => &.{&.{'^'}},
|
6 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'^'}) catch unreachable}) catch unreachable,
|
||||||
7 => {
|
7 => {
|
||||||
const sixToSeven = shortestSequencesToMoveNumericFromAToB(6, 7, allocator);
|
const sixToSeven = shortestSequencesToMoveNumericFromAToB(6, 7, allocator);
|
||||||
const sixBasedMoves = prependSequencesWith(sixToSeven, '^', allocator);
|
const sixBasedMoves = prependSequencesWith(sixToSeven, '^', allocator);
|
||||||
@ -81,20 +152,90 @@ fn shortestSequencesToMoveNumericFromAToB(a: u8, b: u8, allocator: std.mem.Alloc
|
|||||||
const twoBasedMoves = prependSequencesWith(twoToSeven, '<', allocator);
|
const twoBasedMoves = prependSequencesWith(twoToSeven, '<', allocator);
|
||||||
return joinSlices(sixBasedMoves, twoBasedMoves, allocator);
|
return joinSlices(sixBasedMoves, twoBasedMoves, allocator);
|
||||||
},
|
},
|
||||||
8 => &.{ &.{ '^', '^', '<' }, &.{ '^', '<', '^' }, &.{ '<', '^', '^' } },
|
8 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '^', '<', '^' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^', '^' }) catch unreachable }) catch unreachable,
|
||||||
9 => &.{&.{ '^', '^' }},
|
9 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '^', '^' }) catch unreachable}) catch unreachable,
|
||||||
10 => &.{&.{'V'}},
|
10 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'v'}) catch unreachable}) catch unreachable,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
4 => switch (b) {
|
||||||
|
5 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'>'}) catch unreachable}) catch unreachable,
|
||||||
|
6 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '>', '>' }) catch unreachable}) catch unreachable,
|
||||||
|
7 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'^'}) catch unreachable}) catch unreachable,
|
||||||
|
8 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '>', '^' }) catch unreachable, allocator.dupe(u8, &.{ '^', '>' }) catch unreachable }) catch unreachable,
|
||||||
|
9 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '>', '>' }) catch unreachable, allocator.dupe(u8, &.{ '>', '^', '>' }) catch unreachable, allocator.dupe(u8, &.{ '^', '>', '>' }) catch unreachable }) catch unreachable,
|
||||||
|
10 => {
|
||||||
|
const fiveToA = shortestSequencesToMoveNumericFromAToB(5, 10, allocator);
|
||||||
|
const fiveBasedMoves = prependSequencesWith(fiveToA, '>', allocator);
|
||||||
|
|
||||||
|
const oneToA = shortestSequencesToMoveNumericFromAToB(1, 10, allocator);
|
||||||
|
const oneBasedMoves = prependSequencesWith(oneToA, 'v', allocator);
|
||||||
|
return joinSlices(fiveBasedMoves, oneBasedMoves, allocator);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
5 => switch (b) {
|
||||||
|
6 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'>'}) catch unreachable}) catch unreachable,
|
||||||
|
7 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^' }) catch unreachable }) catch unreachable,
|
||||||
|
8 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'^'}) catch unreachable}) catch unreachable,
|
||||||
|
9 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '^', '>' }) catch unreachable}) catch unreachable,
|
||||||
|
10 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ 'v', 'v', '>' }) catch unreachable, allocator.dupe(u8, &.{ 'v', '>', 'v' }) catch unreachable, allocator.dupe(u8, &.{ '>', 'v', 'v' }) catch unreachable }) catch unreachable,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
6 => switch (b) {
|
||||||
|
7 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '<', '<' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '^', '<', '<' }) catch unreachable }) catch unreachable,
|
||||||
|
8 => allocator.dupe([]u8, &.{ allocator.dupe(u8, &.{ '^', '<' }) catch unreachable, allocator.dupe(u8, &.{ '<', '^' }) catch unreachable }) catch unreachable,
|
||||||
|
9 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'^'}) catch unreachable}) catch unreachable,
|
||||||
|
10 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ 'v', 'v' }) catch unreachable}) catch unreachable,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
7 => switch (b) {
|
||||||
|
8 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'>'}) catch unreachable}) catch unreachable,
|
||||||
|
9 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ '>', '>' }) catch unreachable}) catch unreachable,
|
||||||
|
10 => {
|
||||||
|
const eightToA = shortestSequencesToMoveNumericFromAToB(8, 10, allocator);
|
||||||
|
const eightBasedMoves = prependSequencesWith(eightToA, '>', allocator);
|
||||||
|
|
||||||
|
const fourToA = shortestSequencesToMoveNumericFromAToB(4, 10, allocator);
|
||||||
|
const fourBasedMoves = prependSequencesWith(fourToA, 'v', allocator);
|
||||||
|
return joinSlices(eightBasedMoves, fourBasedMoves, allocator);
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
8 => switch (b) {
|
8 => switch (b) {
|
||||||
// 10 => &.{&.{'V'}},
|
9 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{'>'}) catch unreachable}) catch unreachable,
|
||||||
10 => &.{ &.{ 'V', 'V', 'V', '>' }, &.{ 'V', 'V', '>', 'V' }, &.{ 'V', '>', 'V', 'V' }, &.{ '>', 'V', 'V', 'V' } },
|
10 => {
|
||||||
|
const nineToA = shortestSequencesToMoveNumericFromAToB(9, 10, allocator);
|
||||||
|
const nineBasedMoves = prependSequencesWith(nineToA, '>', allocator);
|
||||||
|
|
||||||
|
const fiveToA = shortestSequencesToMoveNumericFromAToB(5, 10, allocator);
|
||||||
|
const fiveBasedMoves = prependSequencesWith(fiveToA, 'v', allocator);
|
||||||
|
return joinSlices(nineBasedMoves, fiveBasedMoves, allocator);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
9 => switch (b) {
|
||||||
|
10 => allocator.dupe([]u8, &.{allocator.dupe(u8, &.{ 'v', 'v', 'v' }) catch unreachable}) catch unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need to make these via a separate function rather than using the `&.{&.{...}}` syntax, because the latter doesn't use
|
||||||
|
// an allocator and so attempts to `free` them will give bus errors.
|
||||||
|
// This language is _really_ awkward sometimes...
|
||||||
|
fn makeSliceOfSlices(strings: []const []const u8, allocator: std.mem.Allocator) [][]u8 {
|
||||||
|
var op = std.ArrayList([]u8).init(allocator);
|
||||||
|
for (strings) |string| {
|
||||||
|
var slice = allocator.alloc(u8, string.len) catch unreachable;
|
||||||
|
for (string, 0..) |c, i| {
|
||||||
|
slice[i] = c;
|
||||||
|
}
|
||||||
|
op.append(slice) catch unreachable;
|
||||||
|
}
|
||||||
|
return op.toOwnedSlice() catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
// To save having to type out _all_ the options above, only type out the ones where the number is increasing, then
|
// To save having to type out _all_ the options above, only type out the ones where the number is increasing, then
|
||||||
// observe that "moving from A to B" is the same as "moving from B to A in reverse" - that is, taking the sequence of
|
// observe that "moving from A to B" is the same as "moving from B to A in reverse" - that is, taking the sequence of
|
||||||
// moves in reverse, and doing the opposite of each of them
|
// moves in reverse, and doing the opposite of each of them
|
||||||
@ -104,9 +245,9 @@ fn invertASequence(sequence: []const u8, allocator: std.mem.Allocator) []u8 {
|
|||||||
while (i > 0) : (i -= 1) {
|
while (i > 0) : (i -= 1) {
|
||||||
switch (sequence[i - 1]) {
|
switch (sequence[i - 1]) {
|
||||||
'>' => op.append('<') catch unreachable,
|
'>' => op.append('<') catch unreachable,
|
||||||
'^' => op.append('V') catch unreachable,
|
'^' => op.append('v') catch unreachable,
|
||||||
'<' => op.append('>') catch unreachable,
|
'<' => op.append('>') catch unreachable,
|
||||||
'V' => op.append('^') catch unreachable,
|
'v' => op.append('^') catch unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,6 +262,8 @@ fn joinSlices(a: []const []const u8, b: []const []const u8, allocator: std.mem.A
|
|||||||
for (b) |seq| {
|
for (b) |seq| {
|
||||||
op.append(seq) catch unreachable;
|
op.append(seq) catch unreachable;
|
||||||
}
|
}
|
||||||
|
allocator.free(a);
|
||||||
|
allocator.free(b);
|
||||||
return op.toOwnedSlice() catch unreachable;
|
return op.toOwnedSlice() catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +276,24 @@ fn prependSequencesWith(seqs: []const []const u8, prefix: u8, allocator: std.mem
|
|||||||
new_seq[j + 1] = c;
|
new_seq[j + 1] = c;
|
||||||
}
|
}
|
||||||
resp[i] = new_seq;
|
resp[i] = new_seq;
|
||||||
|
allocator.free(seq);
|
||||||
}
|
}
|
||||||
|
allocator.free(seqs);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn appendSequencesWith(seqs: []const []const u8, suffix: u8, allocator: std.mem.Allocator) [][]u8 {
|
||||||
|
const resp = allocator.alloc([]u8, seqs.len) catch unreachable;
|
||||||
|
for (seqs, 0..) |seq, i| {
|
||||||
|
var new_seq = allocator.alloc(u8, seq.len + 1) catch unreachable;
|
||||||
|
for (seq, 0..) |c, j| {
|
||||||
|
new_seq[j] = c;
|
||||||
|
}
|
||||||
|
new_seq[seq.len] = suffix;
|
||||||
|
resp[i] = new_seq;
|
||||||
|
allocator.free(seq);
|
||||||
|
}
|
||||||
|
allocator.free(seqs);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,9 +306,12 @@ const NumericRobot = struct {
|
|||||||
switch (m) {
|
switch (m) {
|
||||||
'^' => self.pos.y += 1,
|
'^' => self.pos.y += 1,
|
||||||
'>' => self.pos.x += 1,
|
'>' => self.pos.x += 1,
|
||||||
'V' => self.pos.y -= 1,
|
'v' => self.pos.y -= 1,
|
||||||
'<' => self.pos.x -= 1,
|
'<' => self.pos.x -= 1,
|
||||||
else => unreachable,
|
else => {
|
||||||
|
std.debug.print("Encountered unparsable move {}\n", .{m});
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,38 +328,128 @@ const NumericRobot = struct {
|
|||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pointForNumber(number: u8) Point {
|
||||||
|
return switch (number) {
|
||||||
|
0 => Point{ .x = 1, .y = 0 },
|
||||||
|
1...9 => {
|
||||||
|
const x = (number - 1) % 3;
|
||||||
|
const y = @divFloor(number - 1, 3) + 1;
|
||||||
|
return Point{ .x = x, .y = y };
|
||||||
|
},
|
||||||
|
10 => Point{ .x = 2, .y = 0 },
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn numberForPoint(point: Point) u8 {
|
||||||
|
if (point.y > 0 and point.y < 4 and point.x >= 0 and point.x < 3) {
|
||||||
|
return 3 * (point.y - 1) + point.x + 1;
|
||||||
|
}
|
||||||
|
if (point.y == 0) {
|
||||||
|
switch (point.x) {
|
||||||
|
1 => return 0,
|
||||||
|
2 => return 10,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn makeZeroToOneSequenceDirectly(allocator: std.mem.Allocator) [][]const u8 {
|
||||||
|
var op = std.ArrayList([]const u8).init(allocator);
|
||||||
|
op.append("hello") catch unreachable;
|
||||||
|
return op.toOwnedSlice() catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn printDirectionSeqAsDirections(seq: []const u8) void {
|
||||||
|
for (seq) |c| {
|
||||||
|
std.debug.print("{c}", .{c});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Basic Movement" {
|
test "Basic Movement" {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
const seqs = shortestSequencesToMoveNumericFromAToB(0, 7, allocator);
|
var seqs = shortestSequencesToMoveNumericFromAToB(0, 7, allocator);
|
||||||
for (seqs) |seq| {
|
for (seqs) |seq| {
|
||||||
var robot = NumericRobot{ .pos = Point{ .x = 1, .y = 0 } };
|
var robot = NumericRobot{ .pos = Point{ .x = 1, .y = 0 } };
|
||||||
robot.process(seq) catch unreachable;
|
robot.process(seq) catch unreachable;
|
||||||
try expect(std.meta.eql(robot.pos, Point{ .x = 0, .y = 3 }));
|
try expect(std.meta.eql(robot.pos, Point{ .x = 0, .y = 3 }));
|
||||||
allocator.free(seq); // TODO - I could probably do some fancy shenanigans with `errdefer` here (and elsewhere)
|
allocator.free(seq); // TODO - I could probably do some fancy shenanigans with `errdefer` here (and elsewhere)
|
||||||
}
|
}
|
||||||
allocator.free(seqs);
|
allocator.free(seqs); // I don't know why this is necessary!? I'm re-allocating to it on the next line :shrug:
|
||||||
|
|
||||||
// I don't know why, but reusing `seqs` leads to Memory Leaks, even when (AFAICT) everything is freed.
|
seqs = shortestSequencesToMoveNumericFromAToB(7, 0, allocator);
|
||||||
const new_seqs = shortestSequencesToMoveNumericFromAToB(7, 0, allocator);
|
for (seqs) |seq| {
|
||||||
for (new_seqs) |seq| {
|
|
||||||
var robot = NumericRobot{ .pos = Point{ .x = 0, .y = 3 } };
|
var robot = NumericRobot{ .pos = Point{ .x = 0, .y = 3 } };
|
||||||
robot.process(seq) catch unreachable;
|
robot.process(seq) catch unreachable;
|
||||||
try expect(std.meta.eql(robot.pos, Point{ .x = 1, .y = 0 }));
|
try expect(std.meta.eql(robot.pos, Point{ .x = 1, .y = 0 }));
|
||||||
allocator.free(seq);
|
allocator.free(seq);
|
||||||
}
|
}
|
||||||
allocator.free(new_seqs);
|
allocator.free(seqs);
|
||||||
|
|
||||||
const newer_seqs = shortestSequencesToMoveNumericFromAToB(0, 1, allocator);
|
seqs = shortestSequencesToMoveNumericFromAToB(0, 1, allocator);
|
||||||
for (newer_seqs) |seq| {
|
for (seqs) |seq| {
|
||||||
// var robot = NumericRobot{ .pos = Point{ .x = 2, .y = 0 } };
|
var robot = NumericRobot{ .pos = Point{ .x = 1, .y = 0 } };
|
||||||
// robot.process(seq) catch unreachable;
|
robot.process(seq) catch unreachable;
|
||||||
// try expect(std.meta.eql(robot.pos, Point{ .x = 1, .y = 3 }));
|
const expected_point = Point{ .x = 0, .y = 1 };
|
||||||
|
try expect(std.meta.eql(robot.pos, expected_point));
|
||||||
allocator.free(seq);
|
allocator.free(seq);
|
||||||
}
|
}
|
||||||
allocator.free(newer_seqs);
|
allocator.free(seqs);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Exhaustive Movement test" {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
for (0..11) |i| {
|
||||||
|
for (0..11) |j| {
|
||||||
|
const i_as_u8: u8 = @intCast(i);
|
||||||
|
const j_as_u8: u8 = @intCast(j);
|
||||||
|
const seqs = shortestSequencesToMoveNumericFromAToB(i_as_u8, j_as_u8, allocator);
|
||||||
|
for (seqs) |seq| {
|
||||||
|
var robot = NumericRobot{ .pos = NumericRobot.pointForNumber(i_as_u8) };
|
||||||
|
robot.process(seq) catch unreachable;
|
||||||
|
try expect(std.meta.eql(robot.pos, NumericRobot.pointForNumber(j_as_u8)));
|
||||||
|
allocator.free(seq);
|
||||||
|
}
|
||||||
|
allocator.free(seqs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Shortest sequences for first level of indirection" {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
const sequences = shortestDirectionalPushesToEnterNumericSequence("029A", allocator);
|
||||||
|
defer allocator.free(sequences);
|
||||||
|
// for readable output, uncomment the lines below
|
||||||
|
// ---------
|
||||||
|
// for (sequences) |seq| {
|
||||||
|
// printDirectionSeqAsDirections(seq);
|
||||||
|
// std.debug.print("\n", .{});
|
||||||
|
// // Not sure why we don't need to `allocator.free(seq)` here :shrug:
|
||||||
|
// }
|
||||||
|
// ---------
|
||||||
|
const targetSequence = allocator.dupe(u8, &.{ '<', 'A', '^', 'A', '>', '^', '^', 'A', 'v', 'v', 'v', 'A' }) catch unreachable;
|
||||||
|
defer allocator.free(targetSequence);
|
||||||
|
var foundTargetSequence = false;
|
||||||
|
for (sequences) |seq| {
|
||||||
|
if (std.mem.eql(u8, seq, targetSequence)) {
|
||||||
|
foundTargetSequence = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
std.debug.print("Found the following sequence: ", .{});
|
||||||
|
printDirectionSeqAsDirections(seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try expect(foundTargetSequence);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user