AdventOfCode2023/day_5/solution.d

159 lines
4.8 KiB
D
Raw Permalink Normal View History

2023-12-05 14:45:29 +00:00
import std.file;
import std.string;
import std.conv;
import std.algorithm;
import std.stdio;
import std.array;
import std.format;
import std.ascii;
bool rangesOverlap(long startA, long endA, long startB, long endB) {
return (startA <= endB && startB <= endA) || (startB <= endA && startA <= endB);
}
struct Mapping {
long destinationRangeStart, sourceRangeStart, length;
long sourceRangeEnd() const {
return sourceRangeStart + length - 1;
}
long destinationRangeEnd() const {
return destinationRangeStart + length - 1;
}
long diff() const {
return destinationRangeStart - sourceRangeStart;
}
bool containsSourceValue(long value) {
return value >= sourceRangeStart && value <= sourceRangeEnd;
}
bool containsDestinationValue(long value) {
return value >= destinationRangeStart && value <= destinationRangeEnd;
}
long map(long value) {
if (containsSourceValue(value)) return value + diff;
return value;
}
long unmap(long value) {
if (containsDestinationValue(value)) return value - diff;
return value;
}
bool destinationOverlapsWithOtherSource(Mapping other) {
return rangesOverlap(destinationRangeStart, destinationRangeEnd, other.sourceRangeStart, other.sourceRangeEnd);
}
/// Failed attempt to optimize this solution.
Mapping[] combine(Mapping second) {
if (!destinationOverlapsWithOtherSource(second)) return [this, second];
long overlapStart = destinationRangeStart >= second.sourceRangeStart
? destinationRangeStart
: second.sourceRangeStart;
long overlapEnd = destinationRangeEnd <= second.sourceRangeEnd
? destinationRangeEnd
: second.sourceRangeEnd;
writefln!"Combining mapping %s and %s. Overlap: [%d, %d]"(this, second, overlapStart, overlapEnd);
Mapping[] combination;
return combination;
}
}
struct Almanac {
long[] seeds;
Mapping[][] mappings;
}
Almanac parseAlmanac(string filename) {
string[] lines = File(filename).byLineCopy().array;
Almanac a;
a.seeds = lines[0].split(":")[1].split.map!(to!long).array;
Mapping[] currentMapping;
for (int i = 2; i < lines.length; i++) {
if (lines[i].length == 0 || !isDigit(lines[i][0])) {
if (currentMapping.length > 0) a.mappings ~= currentMapping;
currentMapping = [];
} else {
Mapping m;
formattedRead(lines[i], "%d %d %d", m.destinationRangeStart, m.sourceRangeStart, m.length);
currentMapping ~= m;
}
}
if (currentMapping.length > 0) a.mappings ~= currentMapping;
return a;
}
/// A failed attempt to optimize this!
Mapping[] combineMappingSets(Mapping[] firstSet, Mapping[] secondSet) {
Mapping[] result;
foreach (Mapping first; firstSet) {
foreach (Mapping second; secondSet) {
if (first.destinationOverlapsWithOtherSource(second)) {
}
}
}
return result;
}
void part1() {
Almanac a = parseAlmanac("input.txt");
long minValue = 1_000_000_000;
foreach (long seed; a.seeds) {
long value = seed;
foreach (Mapping[] mappingSet; a.mappings) {
bool mapped = false;
foreach (Mapping mapping; mappingSet) {
if (mapping.containsSourceValue(value)) {
value = mapping.map(value);
mapped = true;
break;
}
}
}
minValue = min(minValue, value);
}
writeln(minValue);
}
void part2() {
import std.parallelism;
Almanac a = parseAlmanac("input.txt");
long[][] seedRanges;
for (int i = 0; i < a.seeds.length; i+=2) {
long seedRangeStart = a.seeds[i];
long seedRangeLength = a.seeds[i+1];
seedRanges ~= [seedRangeStart, seedRangeLength];
writefln!"Mapping %d seeds starting from %d."(seedRangeLength, seedRangeStart);
}
foreach (long[] seedRange; parallel(seedRanges)) {
long minValue = 1_000_000_000_000;
const long seedCount = seedRange[1];
for (long seed = seedRange[0]; seed < seedRange[0] + seedCount; seed++) {
long value = seed;
foreach (Mapping[] mappingSet; a.mappings) {
bool mapped = false;
foreach (Mapping mapping; mappingSet) {
if (mapping.containsSourceValue(value)) {
value = mapping.map(value);
mapped = true;
break;
}
}
}
minValue = min(minValue, value);
}
writefln!"Done searching %d seeds, local min = %d"(seedCount, minValue);
}
}
void main() {
part1();
part2();
}