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:
parent
eeff1bb041
commit
7e096ec120
105
source/day16.d
105
source/day16.d
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue