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.conv;
import std.typecons;
import dayutil; import dayutil;
@ -10,16 +11,26 @@ struct Range {
Variant run(int part, File input, bool bigboy, string[] args) { Variant run(int part, File input, bool bigboy, string[] args) {
auto sections = input.byLineCopy.array.splitter!empty.array; 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; int[][] tickets = sections[2].drop(1).map!(x => x.splitter(",").array.map!(to!int).array).array;
return Variant(parts!int(part, return Variant(parts!long(part,
() => part1(fields.byValue.joiner.array, tickets))); () => part1(fields.joiner.array, tickets),
() => part2(fields, fieldNames, myTicket, tickets)));
} }
Range[][string] parseFields(R)(R input) if (isInputRange!R && isSomeString!(ElementType!R)) { Tuple!(Range[][], string[]) parseFields(R)(R input) if (isInputRange!R && isSomeString!(ElementType!R)) {
Range[][string] result; string[] fieldNames;
Range[][] result;
foreach(line; input) { foreach(line; input) {
auto split1 = line.splitter(": ").array; 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]); return Range(parts[0], parts[1]);
}).array; }).array;
result[split1[0]] = ranges; fieldNames ~= [split1[0]];
result ~= ranges;
} }
return result; return tuple(result, fieldNames);
} }
int part1(Range[] allowedValues, int[][] tickets) { int part1(Range[] allowedValues, int[][] tickets) {
int errorRate = 0; int errorRate = 0;
foreach(number; tickets.joiner()) { foreach(number; tickets.joiner) {
if (!allowedValues.canFind!((element, needle) => element.start <= needle && needle <= element.end)(number)) { if (!allowedValues.canFind!((element, needle) => element.start <= needle && needle <= element.end)(number)) {
errorRate += number; errorRate += number;
} }
@ -46,6 +58,72 @@ int part1(Range[] allowedValues, int[][] tickets) {
} }
return errorRate; 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 { unittest {
string input = q"EOS string input = q"EOS
@ -64,11 +142,16 @@ nearby tickets:
EOS"; EOS";
auto sections = input.lineSplitter.splitter!empty.array; 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; 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);
} }