mirror of
https://github.com/HenkKalkwater/aoc-2020
synced 2024-12-22 16:35: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:
parent
eeff1bb041
commit
7e096ec120
105
source/day16.d
105
source/day16.d
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue