114 lines
3.8 KiB
D
114 lines
3.8 KiB
D
|
module day8.part1;
|
||
|
|
||
|
import std.file;
|
||
|
import std.stdio;
|
||
|
import std.string;
|
||
|
import std.algorithm;
|
||
|
import std.typecons;
|
||
|
import std.array;
|
||
|
import std.conv;
|
||
|
|
||
|
struct Entry {
|
||
|
string[] signalPatterns;
|
||
|
string[] outputValues;
|
||
|
}
|
||
|
|
||
|
Entry[] readEntries(string filename) {
|
||
|
return readText(filename).strip.split("\n")
|
||
|
.map!((line) {
|
||
|
auto parts = line.split("|");
|
||
|
return Entry(parts[0].strip.split(), parts[1].strip.split());
|
||
|
}).array;
|
||
|
}
|
||
|
|
||
|
ulong count1478(Entry[] entries) {
|
||
|
return entries.map!((entry) {
|
||
|
writeln(entry);
|
||
|
return entry.outputValues.filter!(v => v.length == 2 || v.length == 4 || v.length == 3 || v.length == 7).count;
|
||
|
}).sum();
|
||
|
}
|
||
|
|
||
|
int decodeEntry(Entry entry) {
|
||
|
int[string] knownSignals;
|
||
|
string[int] knownSignalsInverse;
|
||
|
|
||
|
void registerKnownSignal(string signal, int digit) {
|
||
|
knownSignals[signal] = digit;
|
||
|
knownSignalsInverse[digit] = signal;
|
||
|
}
|
||
|
|
||
|
// First we register all of the basic signals that will be used to identify others.
|
||
|
foreach (signal; entry.signalPatterns) {
|
||
|
if (signal.length == 2) {
|
||
|
registerKnownSignal(signal, 1);
|
||
|
}
|
||
|
if (signal.length == 3) {
|
||
|
registerKnownSignal(signal, 7);
|
||
|
}
|
||
|
if (signal.length == 4) {
|
||
|
registerKnownSignal(signal, 4);
|
||
|
}
|
||
|
if (signal.length == 7) {
|
||
|
registerKnownSignal(signal, 8);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool matchesCount(string signal, int knownSignal, int requiredMatches = -1) {
|
||
|
int c = 0;
|
||
|
if (requiredMatches == -1) requiredMatches = cast(int) knownSignalsInverse[knownSignal].length;
|
||
|
foreach (segment; signal) {
|
||
|
if (knownSignalsInverse[knownSignal].canFind(segment)) c++;
|
||
|
}
|
||
|
return c == requiredMatches;
|
||
|
}
|
||
|
|
||
|
// Register all other signals using the ones we registered in the first pass.
|
||
|
foreach (signal; entry.signalPatterns) {
|
||
|
if (signal.length == 6) {
|
||
|
if (0 !in knownSignalsInverse && matchesCount(signal, 1) && matchesCount(signal, 7) && matchesCount(signal, 4, 3)) {
|
||
|
registerKnownSignal(signal, 0);
|
||
|
}
|
||
|
if (6 !in knownSignalsInverse && matchesCount(signal, 1, 1) && matchesCount(signal, 4, 3) && matchesCount(signal, 7, 2)) {
|
||
|
registerKnownSignal(signal, 6);
|
||
|
}
|
||
|
if (9 !in knownSignalsInverse && matchesCount(signal, 1) && matchesCount(signal, 4) && matchesCount(signal, 7)) {
|
||
|
registerKnownSignal(signal, 9);
|
||
|
}
|
||
|
}
|
||
|
if (signal.length == 5) {
|
||
|
if (2 !in knownSignalsInverse && matchesCount(signal, 1, 1) && matchesCount(signal, 4, 2) && matchesCount(signal, 7, 2)) {
|
||
|
registerKnownSignal(signal, 2);
|
||
|
}
|
||
|
if (3 !in knownSignalsInverse && matchesCount(signal, 1) && matchesCount(signal, 7) && matchesCount(signal, 4, 3)) {
|
||
|
registerKnownSignal(signal, 3);
|
||
|
}
|
||
|
if (5 !in knownSignalsInverse && matchesCount(signal, 1, 1) && matchesCount(signal, 4, 3) && matchesCount(signal, 7, 2)) {
|
||
|
registerKnownSignal(signal, 5);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool areStringsPermutations(string a, string b) {
|
||
|
if (a.length != b.length) return false;
|
||
|
foreach (c; a) {
|
||
|
if (!b.canFind(c)) return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int[] resultDigits = [];
|
||
|
foreach (outputValue; entry.outputValues) {
|
||
|
foreach (knownSignal, digit; knownSignals) {
|
||
|
if (areStringsPermutations(outputValue, knownSignal)) {
|
||
|
resultDigits ~= digit;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return resultDigits.map!(digit => digit.to!string).joiner().to!int;
|
||
|
}
|
||
|
|
||
|
void sevenSegmentSearch() {
|
||
|
"source/day8/input.txt".readEntries.map!(decodeEntry).sum.writeln;
|
||
|
}
|