138 lines
4.7 KiB
C#
138 lines
4.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using Common;
|
|
using static Common.SegmentDisplay;
|
|
using static Common.Permutation;
|
|
|
|
class PartTwo {
|
|
private static readonly HashSet<int>[] VALID_POSITIONS = {
|
|
new HashSet<int>() {0, 1, 2, 4, 5, 6},
|
|
new HashSet<int>() {2, 5},
|
|
new HashSet<int>() {0, 2, 3, 4, 6},
|
|
new HashSet<int>() {0, 2, 3, 5, 6},
|
|
new HashSet<int>() {1, 2, 3, 5},
|
|
new HashSet<int>() {0, 1, 3, 5, 6},
|
|
new HashSet<int>() {0, 1, 3, 4, 5, 6},
|
|
new HashSet<int>() {0, 2, 5},
|
|
new HashSet<int>() {0, 1, 2, 3, 4, 5, 6},
|
|
new HashSet<int>() {0, 1, 2, 3, 5, 6},
|
|
};
|
|
|
|
public static void Main(string[] args) {
|
|
var seg_display = new SegmentDisplay(args[0]);
|
|
|
|
var output_sum = seg_display.Wirings.Sum(w => OutputNumber(w));
|
|
|
|
Console.WriteLine(output_sum);
|
|
}
|
|
|
|
private static int OutputNumber(Wiring wiring) {
|
|
var inputs = wiring.Inputs.OrderBy(x => x.Count).ToList();
|
|
var digit = 0;
|
|
|
|
if (Analyze(inputs).GetValue(out var segments)) {
|
|
var digit_idx = wiring.Outputs.Count - 1;
|
|
|
|
foreach (var output in wiring.Outputs) {
|
|
var segment_digit = GetOutputDigit(output, segments);
|
|
|
|
digit += segment_digit * (int)Math.Pow(10, digit_idx);
|
|
|
|
digit_idx--;
|
|
}
|
|
}
|
|
|
|
return digit;
|
|
}
|
|
|
|
private static int GetOutputDigit(HashSet<char> output, Dictionary<char, int> segments) {
|
|
var mapped_output = output.Select(v => segments[v]);
|
|
|
|
switch (output.Count) {
|
|
case 2: return 1;
|
|
case 3: return 7;
|
|
case 4: return 4;
|
|
case 7: return 8;
|
|
case 5:
|
|
foreach (var n in new[]{2, 3, 5}) {
|
|
if (!VALID_POSITIONS[n].Except(mapped_output).Any()) return n;
|
|
}
|
|
break;
|
|
case 6:
|
|
foreach (var n in new[]{0, 6, 9}) {
|
|
if (!VALID_POSITIONS[n].Except(mapped_output).Any()) return n;
|
|
}
|
|
break;
|
|
default:
|
|
throw new Exception("Invalid output length");
|
|
}
|
|
|
|
throw new Exception("No valid mapping for output");
|
|
}
|
|
|
|
private static Option<Dictionary<char, int>> Analyze(IEnumerable<HashSet<char>> inputs) {
|
|
return Analyze(inputs, new Dictionary<char, int>());
|
|
}
|
|
|
|
private static Option<Dictionary<char, int>> Analyze(
|
|
IEnumerable<HashSet<char>> inputs,
|
|
Dictionary<char, int> segments
|
|
) {
|
|
if (!inputs.Any()) return new Option<Dictionary<char, int>>.Some(segments);
|
|
|
|
var input = inputs.First();
|
|
var segment_count = input.Count;
|
|
var unmapped_input = input.Except(segments.Keys);
|
|
var mapped_input = input.Intersect(segments.Keys).Select(v => segments[v]);
|
|
|
|
switch (segment_count) {
|
|
case 2: return Analyze(1, unmapped_input, mapped_input, inputs, segments);
|
|
case 3: return Analyze(7, unmapped_input, mapped_input, inputs, segments);
|
|
case 4: return Analyze(4, unmapped_input, mapped_input, inputs, segments);
|
|
case 7: return new Option<Dictionary<char, int>>.Some(segments);
|
|
case 5:
|
|
foreach (var n in new[]{2, 3, 5}) {
|
|
var retval = Analyze(n, unmapped_input.ToList(), mapped_input.ToList(), inputs, segments);
|
|
if (retval.IsSome()) return retval;
|
|
}
|
|
break;
|
|
case 6:
|
|
foreach (var n in new[]{0, 6, 9}) {
|
|
var retval = Analyze(n, unmapped_input.ToList(), mapped_input.ToList(), inputs, segments);
|
|
if (retval.IsSome()) return retval;
|
|
}
|
|
break;
|
|
default:
|
|
throw new Exception("Invalid input length");
|
|
}
|
|
|
|
return new Option<Dictionary<char, int>>.None();
|
|
}
|
|
|
|
private static Option<Dictionary<char, int>> Analyze(
|
|
int num,
|
|
IEnumerable<char> unmapped_input,
|
|
IEnumerable<int> mapped_input,
|
|
IEnumerable<HashSet<char>> inputs,
|
|
Dictionary<char, int> segments
|
|
) {
|
|
if (!mapped_input.Except(VALID_POSITIONS[num]).Any()) {
|
|
foreach (var perm in Permutations(unmapped_input)) {
|
|
var new_segments = new Dictionary<char, int>(segments);
|
|
|
|
foreach (var pair in perm.Zip(VALID_POSITIONS[num].Except(mapped_input), (a, b) => (a, b))) {
|
|
new_segments.Add(pair.Item1, pair.Item2);
|
|
}
|
|
|
|
var retval = Analyze(inputs.Skip(1).ToList(), new_segments);
|
|
|
|
if (retval.IsSome()) return retval;
|
|
}
|
|
}
|
|
|
|
return new Option<Dictionary<char, int>>.None();
|
|
}
|
|
}
|