diff --git a/AOC2021.Test/AOCTester.cs b/AOC2021.Test/AOCTester.cs index 0d8daee..c3d99e3 100644 --- a/AOC2021.Test/AOCTester.cs +++ b/AOC2021.Test/AOCTester.cs @@ -18,20 +18,20 @@ namespace AOC2021.Test Console.WriteLine($"Testing {request.Day} Part A, Test data"); if (!string.IsNullOrEmpty(request.Answer.Day_A_Test)) - response.Answer.Day_A_Test = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = test, Version = AOCVersion.A }).Answer; + response.Answer.Day_A_Test = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = test, Version = AOCVersion.A }).Answer.ToString(); Console.WriteLine(response.Answer.Day_A_Test); Console.WriteLine($"Testing {request.Day} Part A, Input data"); if (!string.IsNullOrEmpty(request.Answer.Day_A_Input)) - response.Answer.Day_A_Input = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = input, Version = AOCVersion.A }).Answer; + response.Answer.Day_A_Input = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = input, Version = AOCVersion.A }).Answer.ToString(); Console.WriteLine(response.Answer.Day_A_Input); Console.WriteLine($"Testing {request.Day} Part B, Test data"); if (!string.IsNullOrEmpty(request.Answer.Day_B_Test)) - response.Answer.Day_B_Test = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = test, Version = AOCVersion.B }).Answer; + response.Answer.Day_B_Test = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = test, Version = AOCVersion.B }).Answer.ToString(); Console.WriteLine(response.Answer.Day_B_Test); Console.WriteLine($"Testing {request.Day} Part B, Input data"); if (!string.IsNullOrEmpty(request.Answer.Day_B_Input)) - response.Answer.Day_B_Input = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = input, Version = AOCVersion.B }).Answer; + response.Answer.Day_B_Input = GetAOCDay(request.Day).ExecuteDay(new AOCRequest() { Input = input, Version = AOCVersion.B }).Answer.ToString(); Console.WriteLine(response.Answer.Day_B_Input); return response; } diff --git a/AOC2021.Test/DayTest.cs b/AOC2021.Test/DayTest.cs index cfbf472..45ee74f 100644 --- a/AOC2021.Test/DayTest.cs +++ b/AOC2021.Test/DayTest.cs @@ -73,6 +73,13 @@ namespace AOC2021.Tests var result = _tester.Test(request); Assert.IsTrue(request.Answer.Equals(result.Answer)); } + [TestMethod] + public void Day8() + { + var request = new TestRequest() { Day = "day8", Answer = new Answer() { Day_A_Test = "26", Day_A_Input = "543", Day_B_Test = "", Day_B_Input = "" } }; + var result = _tester.Test(request); + Assert.IsTrue(request.Answer.Equals(result.Answer)); + } //[TestMethod] public void MapVsEnumberable() diff --git a/AOC2021.Test/Input/Day8_test.txt b/AOC2021.Test/Input/Day8_test.txt new file mode 100644 index 0000000..236a3de --- /dev/null +++ b/AOC2021.Test/Input/Day8_test.txt @@ -0,0 +1,10 @@ +be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe +edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc +fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg +fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb +aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea +fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb +dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe +bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef +egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb +gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce \ No newline at end of file diff --git a/AOC2021/Controllers/AdventOfCodeController.cs b/AOC2021/Controllers/AdventOfCodeController.cs index 5a7e44e..238ec6b 100644 --- a/AOC2021/Controllers/AdventOfCodeController.cs +++ b/AOC2021/Controllers/AdventOfCodeController.cs @@ -26,6 +26,7 @@ namespace AOC2021.Controllers [Route("day5")] [Route("day6")] [Route("day7")] + [Route("day8")] public AOCResponse Day(AOCVersion version, [FromBody] string input, bool IgnoreLogMessages = false) { AOCRequest request = new AOCRequest() { Input = input, Version = version, IgnoreLogMessages = IgnoreLogMessages }; diff --git a/AOC2021/Days/Day8.cs b/AOC2021/Days/Day8.cs new file mode 100644 index 0000000..0ad64b0 --- /dev/null +++ b/AOC2021/Days/Day8.cs @@ -0,0 +1,42 @@ +using AOC2021.Models; +using AOC2021.Models.Day8; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace AOC2021.Days +{ + public class Day8 : AOCDay + { + protected override AOCResponse ExecutePartA() + { + var count = 0; + var uniqueNumberOfLineSegments = new int[] { 2, 4, 3, 7 }; + var lines = GetSplitInput(); + foreach (var line in lines) + { + var displayedDigits = line.Split("|")[1].Trim(); + foreach (var digit in displayedDigits.Split(" ")) + { + if (uniqueNumberOfLineSegments.Contains(digit.Trim().Length)) + { + Log($"{digit} has a length of {digit.Length} which is unique."); + count++; + } + } + } + this._response.Answer = count; + return this._response; + } + + protected override AOCResponse ExecutePartB() + { + //be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb + new SSDGenerator("be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb").Generate(); + + + return this._response; + } + } +} diff --git a/AOC2021/Models/AOCDay.cs b/AOC2021/Models/AOCDay.cs index 343e6f4..6e00c2e 100644 --- a/AOC2021/Models/AOCDay.cs +++ b/AOC2021/Models/AOCDay.cs @@ -23,7 +23,6 @@ namespace AOC2021.Models } public AOCResponse ExecuteDay(AOCRequest request) { - Console.WriteLine("Executing request " + Newtonsoft.Json.JsonConvert.SerializeObject(request)); _request = request; var timer = new Stopwatch(); try diff --git a/AOC2021/Models/AOCResponse.cs b/AOC2021/Models/AOCResponse.cs index a894cc2..e346d82 100644 --- a/AOC2021/Models/AOCResponse.cs +++ b/AOC2021/Models/AOCResponse.cs @@ -12,7 +12,7 @@ namespace AOC2021.Models [DataMember] public DateTime Date { get { return DateTime.Now; } } [DataMember] - public string Answer { get; set; } + public object Answer { get; set; } [DataMember] public bool Status { get; set; } [DataMember] diff --git a/AOC2021/Models/Day8/SSD.cs b/AOC2021/Models/Day8/SSD.cs new file mode 100644 index 0000000..8037bec --- /dev/null +++ b/AOC2021/Models/Day8/SSD.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace AOC2021.Models.Day8 +{ + public enum SSD : int + { + _,A,B,C,D,E,F,G + } +} diff --git a/AOC2021/Models/Day8/SSDGenerator.cs b/AOC2021/Models/Day8/SSDGenerator.cs new file mode 100644 index 0000000..cf853de --- /dev/null +++ b/AOC2021/Models/Day8/SSDGenerator.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace AOC2021.Models.Day8 +{ + public class SSDGenerator + { + public static string ZERO = "abcefg"; + public static string ONE = "cf"; + public static string TWO = "acdeg"; + public static string THREE = "acdfg"; + public static string FOUR = "bcdf"; + public static string FIVE = "abdfg"; + public static string SIX = "abdefg"; + public static string SEVEN = "acf"; + public static string EIGHT = "abcdefg"; + public static string NINE = "abcdfg"; + private string _numbers; + private Dictionary _lookup; + private Dictionary> _possibleLookup; + public SSDGenerator(string numbers) + { + _numbers = numbers; + _lookup = new Dictionary(); + _possibleLookup = new Dictionary>(); + foreach (SSD ssd in Enum.GetValues(typeof(SSD))) + { + if (ssd != SSD._) + _lookup[ssd] = null; + _possibleLookup[ssd] = new List(); + } + } + public void Generate() + { + var one = GetPossibleNumbers(ONE).First(); + var seven = GetPossibleNumbers(SEVEN).First(); + var AcharDiff = CharDiff(one, seven); + _lookup[SSD.A] = GetProperCode(AcharDiff); //We found the A value + _possibleLookup[SSD.C] = GetPossibleSSD(one); //Can also be #1 or #7 with AcharDiff as removed valued + _possibleLookup[SSD.F] = GetPossibleSSD(one); //Can also be #1 or #7 with AcharDiff as removed valued + + //We know that #4 shares two of the same segments(C & F) as #1/#7. So we can remove possible values for that + var four = GetPossibleNumbers(FOUR).First(); + //Remove all possible segments for C/F and assign what is left to B/D + _possibleLookup[SSD.B] = GetPossibleSSD(four, _possibleLookup[SSD.C].Select(x => GetProperCode(x)).ToArray()); + _possibleLookup[SSD.D] = GetPossibleSSD(four, _possibleLookup[SSD.C].Select(x => GetProperCode(x)).ToArray()); + + //We have finished the unique digits. Now we move onto digits that have multiple possible values. + + //Now we address the ones with 5 segments, #2, #3, #5. They all have the same possible numbers, so just use #2 as lookup + var twoThreeFivePossible = GetPossibleNumbers(TWO); + var simplifiedTwoThreeFive = twoThreeFivePossible.Select(x => RemoveKnownSSD(x)).ToArray(); + var possibleValuesForSegmentDG = FindInCommon(simplifiedTwoThreeFive); + _possibleLookup[SSD.D].AddRange(GetPossibleSSD(possibleValuesForSegmentDG)); //Since D already has possible lookups, we add more + _possibleLookup[SSD.G] = GetPossibleSSD(possibleValuesForSegmentDG); + DeducePossibleLookups(); //Since we have overlapping possible values, we deduce the correct ones and simplify + + PrintOutLookup(); + //Now we address the ones with 6 segments, #0, #6, #9. They all have the same possible numbers, so just use #0 as lookup + var zeroSixNinePossible = GetPossibleNumbers(ZERO); + var simplifiedZeroSixNine = zeroSixNinePossible.Select(x => RemoveKnownSSD(x)).ToArray(); + var possibleValuesForSegmentF = FindInCommon(simplifiedZeroSixNine); //F segment is in common with 0, 6, 9. + _lookup[SSD.F] = GetProperCode(possibleValuesForSegmentF[0]); //Its a single char since its the only one in common with all 3 digits + PrintOutLookup(); + DeducePossibleLookups(); + PrintOutLookup(); + foreach (var l in simplifiedZeroSixNine) + Console.WriteLine(l); + } + + private void DeducePossibleLookups() + { + var reRunDeduce = false; + //Remove any possible lookup that have matched to lookup + foreach (var lookup in _lookup) + { + if (lookup.Value != null) + { + _possibleLookup[lookup.Key].Clear(); + } + } + + //Remove from Possible lookup any values that are already looked up. + foreach (var pL in _possibleLookup) + { + foreach (var lookup in _lookup.Where(x => x.Value != null)) + { + pL.Value.Remove(lookup.Value.GetValueOrDefault()); + } + } + + //Duplicate possible value check (implies the duplicate value is correct one) + foreach (var pL in _possibleLookup) + { + var duplicateCount = pL.Value.GroupBy(x => x).Where(y => y.Count() > 1).Select(y => y.Key); + if (duplicateCount.Any()) //Means we have a duplicate entry for one of the possible and it means THAT is the correct value + { + _lookup[pL.Key] = duplicateCount.First(); + pL.Value.Clear(); + reRunDeduce = true; + } + } + + //If there is only one possible value implies that it is the answer + foreach (var pL in _possibleLookup) + { + if (pL.Value.Count == 1) + { + _lookup[pL.Key] = pL.Value.First(); + pL.Value.Clear(); + reRunDeduce = true; + } + } + + //Indicates 6 / 7 values are found, meaning the next unused value is it. + var lastOne = _lookup.Where(x => x.Value == null).Select(x => x.Key); + if (lastOne.Count() == 1) + { + var selectedValues = _lookup.Select(x => x.Value); + foreach (SSD ssd in Enum.GetValues(typeof(SSD))) + { + if (ssd == SSD._) + continue; + if (!selectedValues.Contains(ssd)) + { + _lookup[lastOne.First()] = ssd; + break; + } + } + } + + if (reRunDeduce) + DeducePossibleLookups(); + } + + private string[] GetPossibleNumbers(string searchingNumber) + { + var possibleNumbers = new List(); + foreach (var number in _numbers.Split(" ")) + { + if (searchingNumber.Length == number.Trim().Length) + possibleNumbers.Add(String.Concat(number.OrderBy(c => c))); + } + return possibleNumbers.ToArray(); + } + + private string RemoveKnownSSD(string s) + { + var knownSSDs = _lookup.Select(x => x.Value); + var retVal = ""; + foreach (var c in s) + { + if (!knownSSDs.Contains(GetProperCode(c))) + retVal += c; + } + return retVal; + } + + private string FindInCommon(string[] values) + { + var retVal = ""; + var charArrays = values.Select(x => x.ToCharArray()).ToArray(); + var initial = charArrays[0]; + foreach (var c in initial) + { + bool contains = true; + for (int i = 1; i < charArrays.Count(); i++) + { + if (!charArrays[i].Contains(c)) + contains = false; + } + if (contains) + retVal += c; + } + return retVal; + } + + private char CharDiff(string s1, string s2) + { + string diff = ""; + var high = s1.Length > s2.Length ? s1 : s2; + var low = s1.Length <= s2.Length ? s1 : s2; + foreach (char c in high) + { + if (low.IndexOf(c) == -1) + diff += c; + } + if (diff.Length != 1) + throw new Exception($"Char Diff has value {diff} for {s1} and {s2}"); + return diff[0]; + } + + private List GetPossibleSSD(string value, params char[] removedChars) + { + var retVal = new List(); + foreach (var c in value) + { + if (!removedChars.Contains(c)) + retVal.Add(GetProperCode(c)); + } + return retVal; + } + + public void PrintOutLookup() + { + foreach (var e in _lookup) + { + if (e.Key == SSD._) + continue; + Console.WriteLine($"{e.Key}: {e.Value}"); + } + foreach (var e in _possibleLookup) + { + if (e.Key == SSD._) + continue; + Console.WriteLine($"P_{e.Key}: {string.Join(", ", e.Value)}"); + } + } + + public string GetProperCode(int x) + { + if (x == 0) + return ZERO; + if (x == 1) + return ONE; + if (x == 2) + return TWO; + if (x == 3) + return THREE; + if (x == 4) + return FOUR; + if (x == 5) + return FIVE; + if (x == 6) + return SIX; + if (x == 7) + return SEVEN; + if (x == 8) + return EIGHT; + if (x == 9) + return NINE; + return ""; + } + + public SSD GetProperCode(char c) + { + c = c.ToString().ToLower()[0]; + if (c == 'a') + return SSD.A; + if (c == 'b') + return SSD.B; + if (c == 'c') + return SSD.C; + if (c == 'd') + return SSD.D; + if (c == 'e') + return SSD.E; + if (c == 'f') + return SSD.F; + if (c == 'g') + return SSD.G; + return SSD._; + } + + public char GetProperCode(SSD ssd) + { + if (ssd == SSD.A) + return 'a'; + if (ssd == SSD.B) + return 'b'; + if (ssd == SSD.C) + return 'c'; + if (ssd == SSD.D) + return 'd'; + if (ssd == SSD.E) + return 'e'; + if (ssd == SSD.F) + return 'f'; + if (ssd == SSD.G) + return 'g'; + return ' '; + } + + } +} diff --git a/AOC2021/Models/Day8/SSDNumber.cs b/AOC2021/Models/Day8/SSDNumber.cs new file mode 100644 index 0000000..f9b76b0 --- /dev/null +++ b/AOC2021/Models/Day8/SSDNumber.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace AOC2021.Models.Day8 +{ + public class SSDNumber + { + + + public SSDNumber() + { + + } + public bool[] Layout { get; set; } + public bool Finalized { get; set; } + } +}