1
0
Fork 0
mirror of https://github.com/HenkKalkwater/aoc-2020 synced 2024-11-22 11:05:18 +00:00

Added day 16 part 2

After replacing allowedValues[field] with allowedValues[column] and
ticket[column] with ticket[field] on lines 85 and 87, it works. Why? I don't know.
This commit is contained in:
Chris Josten 2020-12-16 18:21:59 +01:00
parent eeff1bb041
commit 7e096ec120
Signed by: chris
GPG key ID: 1795A594046530AB

View file

@ -1,4 +1,5 @@
import std.conv;
import std.typecons;
import dayutil;
@ -10,16 +11,26 @@ struct Range {
Variant run(int part, File input, bool bigboy, string[] args) {
auto sections = input.byLineCopy.array.splitter!empty.array;
Range[][string] fields = parseFields(sections[0]);
auto tmp = parseFields(sections[0]);
Range[][] fields = tmp[0];
string[] fieldNames = tmp[1];
/*debug foreach(field, name; zip(fields, fieldNames)) {
writeln(name, ": ", field);
}*/
int[] myTicket = sections[1][1].splitter(",").array.map!(to!int).array;
// debug writeln(myTicket);
int[][] tickets = sections[2].drop(1).map!(x => x.splitter(",").array.map!(to!int).array).array;
return Variant(parts!int(part,
() => part1(fields.byValue.joiner.array, tickets)));
return Variant(parts!long(part,
() => part1(fields.joiner.array, tickets),
() => part2(fields, fieldNames, myTicket, tickets)));
}
Range[][string] parseFields(R)(R input) if (isInputRange!R && isSomeString!(ElementType!R)) {
Range[][string] result;
Tuple!(Range[][], string[]) parseFields(R)(R input) if (isInputRange!R && isSomeString!(ElementType!R)) {
string[] fieldNames;
Range[][] result;
foreach(line; input) {
auto split1 = line.splitter(": ").array;
@ -29,16 +40,17 @@ Range[][string] parseFields(R)(R input) if (isInputRange!R && isSomeString!(Elem
return Range(parts[0], parts[1]);
}).array;
result[split1[0]] = ranges;
fieldNames ~= [split1[0]];
result ~= ranges;
}
return result;
return tuple(result, fieldNames);
}
int part1(Range[] allowedValues, int[][] tickets) {
int errorRate = 0;
foreach(number; tickets.joiner()) {
foreach(number; tickets.joiner) {
if (!allowedValues.canFind!((element, needle) => element.start <= needle && needle <= element.end)(number)) {
errorRate += number;
}
@ -46,6 +58,72 @@ int part1(Range[] allowedValues, int[][] tickets) {
}
return errorRate;
}
long part2(Range[][] allowedValues, string[] fieldNames, int[] myTicket, int[][] tickets) {
auto flatValues = allowedValues.joiner.array;
// discard invalid tickets
// debug writeln("Ticket count: ", tickets.length);
int[][] validTickets = tickets.filter!((ticket) {
foreach(number; ticket) {
if (!flatValues.canFind!((element, needle) => element.start <= needle && needle <= element.end)(number)) {
return false;
}
}
return true;
}).array;
validTickets ~= myTicket;
import std.format;
// debug writeln("Valid ticket count: ", validTickets.length);
int[][] candidatesPerField;
candidatesPerField.reserve(fieldNames.length);
foreach(field; 0..fieldNames.length) {
//debug write("Matching ", fieldNames[field], " with: ");
int[] candidates = iota(0, cast(int) fieldNames.length).filter!((column) {
bool result = validTickets.all!(
(ticket) => allowedValues[column]
.canFind!((range, needle) => range.start <= needle
&& needle <= range.end)(ticket[field]));
//debug write(validTickets.map!((t) => t[column]), " (", result, "); ");
return result;
}).array;
//debug writeln();
candidatesPerField ~= [candidates];
}
long result = 1;
immutable string pred = "a.value.length < b.value.length";
auto sortedCandidates = candidatesPerField.enumerate.array.sort!pred;
//debug writeln("Candidates: ", sortedCandidates);
Tuple!(int, string)[] values;
values.reserve(6);
while (sortedCandidates.length > 0) {
ulong index = sortedCandidates.front.index;
int[] candidates = sortedCandidates.front.value;
assert(candidates.length == 1, "Cannot solve this");
int bestCandidate = candidates[0];
// debug writeln(index, " maps to ", fieldNames[bestCandidate]);
if (fieldNames[bestCandidate].startsWith("departure ")) {
result *= myTicket[index];
values ~= tuple(myTicket[index], fieldNames[bestCandidate]);
//debug writeln("Taking ", myTicket[index], "; (result: ", result, ")");
}
sortedCandidates.popFront();
sortedCandidates = sortedCandidates.map!((x) {
x.value = x.value.filter!(y => y != bestCandidate).array;
return x;
}).array.sort!pred;
}
// debug writeln(values);
return result;
}
unittest {
string input = q"EOS
@ -64,11 +142,16 @@ nearby tickets:
EOS";
auto sections = input.lineSplitter.splitter!empty.array;
Range[][string] fields = parseFields(sections[0]);
auto tmp = parseFields(sections[0]);
Range[][] fields = tmp[0];
string[] fieldNames = tmp[1];
assert(fields["class"] == [Range(1,3), Range(5,7)]);
assert(fields[0] == [Range(1,3), Range(5,7)]);
int[] myTicket = sections[1].array[1].splitter(",").array.map!(to!int).array;
int[][] tickets = sections[2].drop(1).map!(x => x.splitter(",").array.map!(to!int).array).array;
assert(part1(fields.byValue.joiner.array, tickets) == 71);
assert(part1(fields.joiner.array, tickets) == 71);
part2(fields, fieldNames, myTicket, tickets);
}