diff --git a/11/CosmicExpansion.Tests/GlobalUsings.cs b/11/CosmicExpansion.Tests/GlobalUsings.cs index 7fef4b0..2d5b473 100644 --- a/11/CosmicExpansion.Tests/GlobalUsings.cs +++ b/11/CosmicExpansion.Tests/GlobalUsings.cs @@ -1,2 +1,3 @@ +global using FluentAssertions; + global using Xunit; -global using FluentAssertions; \ No newline at end of file diff --git a/12/HotSprings.Tests/GlobalUsings.cs b/12/HotSprings.Tests/GlobalUsings.cs index 7fef4b0..2d5b473 100644 --- a/12/HotSprings.Tests/GlobalUsings.cs +++ b/12/HotSprings.Tests/GlobalUsings.cs @@ -1,2 +1,3 @@ +global using FluentAssertions; + global using Xunit; -global using FluentAssertions; \ No newline at end of file diff --git a/12/HotSprings/Program.cs b/12/HotSprings/Program.cs index c41a588..83bf898 100644 --- a/12/HotSprings/Program.cs +++ b/12/HotSprings/Program.cs @@ -177,23 +177,23 @@ public class Condition( if (unfold) { springs = [ - ..springs, + .. springs, SpringCondition.Unknown, - ..springs, + .. springs, SpringCondition.Unknown, - ..springs, + .. springs, SpringCondition.Unknown, - ..springs, + .. springs, SpringCondition.Unknown, - ..springs, + .. springs, ]; contiguousGroupSizes = [ - ..contiguousGroupSizes, - ..contiguousGroupSizes, - ..contiguousGroupSizes, - ..contiguousGroupSizes, - ..contiguousGroupSizes, + .. contiguousGroupSizes, + .. contiguousGroupSizes, + .. contiguousGroupSizes, + .. contiguousGroupSizes, + .. contiguousGroupSizes, ]; } diff --git a/13/PointOfIncidence.Tests/GlobalUsings.cs b/13/PointOfIncidence.Tests/GlobalUsings.cs new file mode 100644 index 0000000..2d5b473 --- /dev/null +++ b/13/PointOfIncidence.Tests/GlobalUsings.cs @@ -0,0 +1,3 @@ +global using FluentAssertions; + +global using Xunit; diff --git a/13/PointOfIncidence.Tests/PatternTests.cs b/13/PointOfIncidence.Tests/PatternTests.cs new file mode 100644 index 0000000..2000d85 --- /dev/null +++ b/13/PointOfIncidence.Tests/PatternTests.cs @@ -0,0 +1,281 @@ +namespace PointOfIncidence.Tests; + +public class PatternTests +{ + [Theory] + [MemberData(nameof(TestData.ParseTestData), MemberType = typeof(TestData))] + public void Parse_GivenAPattern_ItShouldReturnPatternInstance(string[] input, Pattern expected) + { + var result = Pattern.Parse(input); + result.Should().BeEquivalentTo(expected); + } + + [Theory] + [MemberData(nameof(TestData.FindPointOfReflectionTestData), MemberType = typeof(TestData))] + public void FindPointOfReflection_GivenAPattern_ItShouldReturnPointOfReflection(string[] input, PointOfReflection expected) + { + var pattern = Pattern.Parse(input); + var result = pattern.FindPointOfReflection(); + result.Should().BeEquivalentTo(expected); + } + + [Theory] + [MemberData(nameof(TestData.FindPointOfReflectionWithoutSmudgeTestData), MemberType = typeof(TestData))] + public void FindPointOfReflection_GivenAPatternAndCleanSmudgeIsTrue_ItShouldReturnPointOfReflection(string[] input, PointOfReflection expected) + { + var pattern = Pattern.Parse(input); + var result = pattern.FindPointOfReflection(true); + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public void SummarizePatternNotes_GivenExampleInput_ItShouldReturnExpectedValue() + { + var input = File + .ReadAllText("EXAMPLE.txt") + .ReplaceLineEndings(); + + var patterns = input + .Split(Environment.NewLine + Environment.NewLine) + .Select(p => p.Split(Environment.NewLine)); + + var result = patterns + .Select(Pattern.Parse) + .Sum(p => p.SummarizePatternNotes()); + + result.Should().Be(405); + } + + + [Fact] + public void SummarizePatternNotes_GivenInput_ItShouldReturnExpectedValue() + { + var input = File + .ReadAllText("INPUT.txt") + .ReplaceLineEndings(); + + var patterns = input + .Split(Environment.NewLine + Environment.NewLine) + .Select(p => p.Split(Environment.NewLine)); + + var summaries = patterns + .Select(Pattern.Parse) + .Select(p => p.SummarizePatternNotes()); + + var result = summaries.Sum(); + + result.Should().Be(33728); + } + + [Fact] + public void SummarizePatternNotes_GivenInputAndIsPartTwo_ItShouldReturnExpectedValue() + { + var input = File + .ReadAllText("INPUT.txt") + .ReplaceLineEndings(); + + var patterns = input + .Split(Environment.NewLine + Environment.NewLine) + .Select(p => p.Split(Environment.NewLine)); + + var summaries = patterns + .Select(Pattern.Parse) + .Select(p => p.SummarizePatternNotes(true)); + + var result = summaries.Sum(); + + result.Should().Be(28235); + } + + public static class TestData + { + public static IEnumerable ParseTestData => + new List + { + new object[] + { + new string[] + { + "#.##..##.", + "..#.##.#.", + }, + new Pattern( + [ + ['#', '.', '#', '#', '.', '.', '#', '#', '.'], + ['.', '.', '#', '.', '#', '#', '.', '#', '.'], + ], + [ + ['#', '.'], + ['.', '.'], + ['#', '#'], + ['#', '.'], + ['.', '#'], + ['.', '#'], + ['#', '.'], + ['#', '#'], + ['.', '.'], + ] + ), + } + }; + + public static IEnumerable FindPointOfReflectionWithoutSmudgeTestData => + new List + { + new object[] + { + new string[] + { + "#...##..#", + "#....#..#", + "..##..###", + "#####.##.", + "#####.##.", + "..##..###", + "#....#..#", + }, + new PointOfReflection + { + Type = ReflectionType.Horizontal, + StartIndex = 0, + EndIndex = 1, + }, + }, + new object[] + { + new string[] + { + "#.##..##.", + "..#.##.#.", + "##......#", + "##......#", + "..#.##.#.", + "..##..##.", + "#.#.##.#.", + }, + new PointOfReflection + { + Type = ReflectionType.Horizontal, + StartIndex = 2, + EndIndex = 3, + } + }, + new object[] + { + new string[] + { + "#..#.#........#", + "#..######..####", + ".##..#.#.##.#.#", + "#..##..........", + "######........#", + "#..####......##", + ".##.##.#...##.#", + }, + new PointOfReflection + { + Type = ReflectionType.Vertical, + StartIndex = 9, + EndIndex = 10, + } + }, + new object[] + { + new string[] + { + "####.##.....###.#", + "#####.......#..#.", + "#####.......#..#.", + "####..#.....###.#", + "#..####..#.#.##.#", + ".##..#..........#", + "######..#.##....#", + "#..####...###...#", + "####..#..###.....", + ".......#.##.##...", + "....##.###.##..#.", + "#..##..###...#.#.", + "....#...#.##...##", + ".##........##....", + ".....#.####..##.#", + "#..#..#..#.#.#..#", + "#######.#.#.#....", + }, + new PointOfReflection + { + Type = ReflectionType.Horizontal, + StartIndex = 1, + EndIndex = 2, + }, + } + }; + + public static IEnumerable FindPointOfReflectionTestData => + new List + { + new object[] + { + new string[] + { + "#...##..#", + "#....#..#", + "..##..###", + "#####.##.", + "#####.##.", + "..##..###", + "#....#..#", + }, + new PointOfReflection + { + Type = ReflectionType.Horizontal, + StartIndex = 3, + EndIndex = 4, + }, + }, + new object[] + { + new string[] + { + "#.##..##.", + "..#.##.#.", + "##......#", + "##......#", + "..#.##.#.", + "..##..##.", + "#.#.##.#.", + }, + new PointOfReflection + { + Type = ReflectionType.Vertical, + StartIndex = 4, + EndIndex = 5, + } + }, + new object[] + { + new string[] + { + "...##..##.#.#", + ".##.#####.###", + "##.#....####.", + "#.#....#.#..#", + ".#..#.#...#.#", + ".#..#.#...#.#", + "#.#....#.#..#", + "##.#....####.", + ".########.###", + "...##..##.#.#", + "#.#.###.....#", + "#.#.###.....#", + "...##..##.#.#", + }, + new PointOfReflection + { + Type = ReflectionType.Horizontal, + StartIndex = 10, + EndIndex = 11, + }, + }, + }; + } +} \ No newline at end of file diff --git a/13/PointOfIncidence.Tests/PointOfIncidence.Tests.csproj b/13/PointOfIncidence.Tests/PointOfIncidence.Tests.csproj new file mode 100644 index 0000000..21b4499 --- /dev/null +++ b/13/PointOfIncidence.Tests/PointOfIncidence.Tests.csproj @@ -0,0 +1,42 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + PreserveNewest + + + + + + PreserveNewest + + + + diff --git a/13/PointOfIncidence/PointOfIncidence.csproj b/13/PointOfIncidence/PointOfIncidence.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/13/PointOfIncidence/PointOfIncidence.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/13/PointOfIncidence/Program.cs b/13/PointOfIncidence/Program.cs new file mode 100644 index 0000000..9b26656 --- /dev/null +++ b/13/PointOfIncidence/Program.cs @@ -0,0 +1,518 @@ +using System.Diagnostics; + +namespace PointOfIncidence; + +public class Program +{ + public static async Task Main(string[] args) + { + if (args.Length is 0) + { + Console.WriteLine("Please provide a path to the input file."); + return -1; + } + + if (File.Exists(args[0]) is false) + { + Console.WriteLine("The provided file does not exist."); + return -2; + } + + var isPart2 = args.Length > 1 && args[1] == "part2"; + var input = await File.ReadAllTextAsync(args[0]); + + var patterns = input + .ReplaceLineEndings() + .Split(Environment.NewLine + Environment.NewLine) + .Select(p => p.Split(Environment.NewLine)); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + var result = patterns + .Select(Pattern.Parse) + .Sum(p => p.SummarizePatternNotes(isPart2)); + + stopwatch.Stop(); + + Console.WriteLine($"The total of all pattern note summaries is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); + + return (int)result; + } +} + +/// +/// Represents a pattern. +/// +/// The rows of the pattern. +/// The columns of the pattern. +/// A instance. +public class Pattern( + List> rows, + List> columns +) +{ + /// + /// Gets the rows of the pattern. + /// + public List> Rows { get; init; } = rows; + + /// + /// Gets the columns of the pattern. + /// + public List> Columns { get; init; } = columns; + + private bool HasSmudge(List row, List otherRow) + { + var numOfDiffs = 0; + + for (var i = 0; i < row.Count; i++) + { + if (row[i] != otherRow[i]) + { + numOfDiffs++; + } + } + + return numOfDiffs is 1; + } + + private bool CheckForReflection( + int startIndex, + int endIndex, + ReflectionType reflectionType, + out PointOfReflection pointOfReflection + ) + { + List start; + List end; + List> collection; + var isReflection = false; + pointOfReflection = new PointOfReflection(); + + // maintain the original indices for the point of reflection + var originalStartIndex = startIndex; + var originalEndIndex = endIndex; + + // set the start and end points and the collection to check + // based on the reflection type + if (reflectionType == ReflectionType.Horizontal) + { + start = Rows[startIndex]; + end = Rows[endIndex]; + collection = Rows; + } + else + { + start = Columns[startIndex]; + end = Columns[endIndex]; + collection = Columns; + } + + // check if the start and end collections are equal + if (start.SequenceEqual(end)) + { + isReflection = true; + + // move the start and end indices outwards + // until the start index reaches start of the collection + // or the end index reaches the end of the collection + while (startIndex > 0 && endIndex < collection.Count - 1) + { + var previous = collection[startIndex - 1]; + var next = collection[endIndex + 1]; + + // if the previous and next collections + // are not equal then the reflection is + // not complete + if (previous.SequenceEqual(next) is false) + { + isReflection = false; + break; + } + + startIndex--; + endIndex++; + } + } + + // if the reflection is complete + // set the point of reflection + if (isReflection) + { + pointOfReflection = new PointOfReflection + { + StartIndex = originalStartIndex, + EndIndex = originalEndIndex, + Type = reflectionType, + }; + } + + return isReflection; + } + + private bool CheckForReflectionWithoutSmudges( + PointOfReflection originalPointOfReflection, + int startIndex, + int endIndex, + ReflectionType reflectionType, + out PointOfReflection pointOfReflection + ) + { + List start; + List end; + List> collection; + var isReflection = false; + var smudgeCleaned = false; + pointOfReflection = new PointOfReflection(); + + // maintain the original indices for the point of reflection + var originalStartIndex = startIndex; + var originalEndIndex = endIndex; + + // set the start and end points and the collection to check + // based on the reflection type + if (reflectionType == ReflectionType.Horizontal) + { + start = Rows[startIndex]; + end = Rows[endIndex]; + collection = Rows; + } + else + { + start = Columns[startIndex]; + end = Columns[endIndex]; + collection = Columns; + } + + var isNotOriginalPointOfReflection = + ( + startIndex != originalPointOfReflection.StartIndex && + endIndex != originalPointOfReflection.EndIndex + ) || originalPointOfReflection.Type != reflectionType; + + do + { + // check if the start and end collections are equal + // and that they are not the original point of reflection + // or that the smudge has been cleaned + if ((start.SequenceEqual(end) && isNotOriginalPointOfReflection) || smudgeCleaned) + { + isReflection = true; + + // move the start and end indices outwards + // until the start index reaches start of the collection + // or the end index reaches the end of the collection + while (startIndex > 0 && endIndex < collection.Count - 1) + { + var previous = collection[startIndex - 1]; + var next = collection[endIndex + 1]; + + // if the previous and next collections + // are not equal then the reflection is + // not complete + if (previous.SequenceEqual(next) is false) + { + // if we can clean the smudge and + // keep reflection intact continue + // checking for reflection at this point + if (HasSmudge(previous, next) && smudgeCleaned is false) + { + smudgeCleaned = true; + startIndex--; + endIndex++; + continue; + } + + isReflection = false; + break; + } + + startIndex--; + endIndex++; + } + + smudgeCleaned = false; + } + else + { + // if we can clean the smudge and + // then we need to check for reflection + // at this point + if (HasSmudge(start, end)) + { + smudgeCleaned = true; + continue; + } + } + } while (smudgeCleaned); + + // if the reflection is complete + // set the point of reflection + if (isReflection) + { + pointOfReflection = new PointOfReflection + { + StartIndex = originalStartIndex, + EndIndex = originalEndIndex, + Type = reflectionType, + }; + } + + return isReflection; + } + + /// + /// Finds the point of reflection. + /// + /// Indicates whether to clean smudges. + /// A instance at which the reflection occurs. + public PointOfReflection FindPointOfReflection(bool cleanSmudge = false) + { + var orgPointOfReflection = new PointOfReflection(); + + var startRowIndex = 0; + var endRowIndex = 1; + + // check for horizontal reflection + while (endRowIndex < Rows.Count) + { + var isReflection = CheckForReflection( + startRowIndex, + endRowIndex, + ReflectionType.Horizontal, + out var reflectionPoint + ); + + if (isReflection) + { + orgPointOfReflection = reflectionPoint; + break; + } + + startRowIndex++; + endRowIndex++; + } + + // if no horizontal reflection was found + if (orgPointOfReflection.Type == ReflectionType.None) + { + var startColumnIndex = 0; + var endColumnIndex = 1; + + // check for vertical reflection + while (endColumnIndex < Columns.Count) + { + var isReflection = CheckForReflection( + startColumnIndex, + endColumnIndex, + ReflectionType.Vertical, + out var reflectionPoint + ); + + if (isReflection) + { + orgPointOfReflection = reflectionPoint; + break; + } + + startColumnIndex++; + endColumnIndex++; + } + } + + // if we are not factoring in smudges + // return the original point of reflection + if (cleanSmudge is false) + { + return orgPointOfReflection; + } + + var newPointsOfReflection = new List(); + startRowIndex = 0; + endRowIndex = 1; + + // check for horizontal reflection + // without smudges + while (endRowIndex < Rows.Count) + { + var isReflection = CheckForReflectionWithoutSmudges( + orgPointOfReflection, + startRowIndex, + endRowIndex, + ReflectionType.Horizontal, + out var reflectionPoint + ); + + if (isReflection) + { + newPointsOfReflection.Add(reflectionPoint); + break; + } + + startRowIndex++; + endRowIndex++; + } + + // if no horizontal reflection was found + // without smudges or the original point of reflection + // was found again + if (newPointsOfReflection.Count is 0 || newPointsOfReflection[0].Equals(orgPointOfReflection)) + { + var startColumnIndex = 0; + var endColumnIndex = 1; + + // check for vertical reflection + // without smudges + while (endColumnIndex < Columns.Count) + { + var isReflection = CheckForReflectionWithoutSmudges( + orgPointOfReflection, + startColumnIndex, + endColumnIndex, + ReflectionType.Vertical, + out var reflectionPoint + ); + + if (isReflection) + { + newPointsOfReflection.Add(reflectionPoint); + break; + } + + startColumnIndex++; + endColumnIndex++; + } + } + + // return the first point of reflection + // that is not the original point of reflection + return newPointsOfReflection.First( + p => p.Equals(orgPointOfReflection) is false + ); + } + + /// + /// Summarizes the pattern notes. + /// + /// Indicates whether to clean smudges. + /// A number that represents the summary of the pattern notes. + public long SummarizePatternNotes(bool cleanSmudge = false) + { + var pointOfReflection = FindPointOfReflection(cleanSmudge); + + return pointOfReflection.Type switch + { + ReflectionType.Horizontal => (pointOfReflection.StartIndex + 1) * 100, + ReflectionType.Vertical => pointOfReflection.StartIndex + 1, + _ => 0, + }; + } + + /// + /// Parses the input into a instance. + /// + /// The input to parse. + /// A instance. + public static Pattern Parse(string[] input) + { + var columns = new List>(); + + var height = input.Length; + var width = input[0].Length; + + for (var i = 0; i < width; i++) + { + var column = new List(); + + for (var j = 0; j < height; j++) + { + column.Add(input[j][i]); + } + + columns.Add(column); + } + + var rows = input + .Select( + row => row + .ToCharArray() + .ToList() + ) + .ToList(); + + return new Pattern(rows, columns); + } +} + +/// +/// Represents a point of reflection +/// +public class PointOfReflection : IEquatable +{ + /// + /// Gets or sets the type of the reflection. + /// + public ReflectionType Type { get; set; } = ReflectionType.None; + + /// + /// Gets or sets the start index of the reflection. + /// + public int StartIndex { get; set; } = -1; + + /// + /// Gets or sets the end index of the reflection. + /// + public int EndIndex { get; set; } = -1; + + /// + /// Indicates whether the current instance is equal to another instance. + /// + /// An instance of to compare with this instance. + /// true if the current instance is equal to the other parameter; otherwise, false. + public bool Equals(PointOfReflection? other) => + other is not null && + Type == other.Type && + StartIndex == other.StartIndex && + EndIndex == other.EndIndex; + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals(object? obj) + { + return Equals(obj as PointOfReflection); + } + + /// + /// Returns the hash code for this instance. + /// + /// An integer that is the hash code for this instance. + public override int GetHashCode() + { + return HashCode.Combine(Type, StartIndex, EndIndex); + } +} + +/// +/// Represents the type of reflection +/// +public enum ReflectionType +{ + /// + /// Reflection that occurs on the horizontal axis + /// + Horizontal, + + /// + /// Reflection that occurs on the vertical axis + /// + Vertical, + + /// + /// No reflection + /// + None, +} \ No newline at end of file diff --git a/AdventOfCode2023.sln b/AdventOfCode2023.sln index 741151e..90f8bdb 100644 --- a/AdventOfCode2023.sln +++ b/AdventOfCode2023.sln @@ -75,6 +75,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotSprings", "12\HotSprings EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotSprings.Tests", "12\HotSprings.Tests\HotSprings.Tests.csproj", "{2731DE56-AF4B-4009-8259-2EA5A9A102FE}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "13", "13", "{DC4E691A-0061-4937-8732-E8D8073C868D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PointOfIncidence", "13\PointOfIncidence\PointOfIncidence.csproj", "{334D6DFF-6131-49C1-B54C-B9E8E00F1E3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PointOfIncidence.Tests", "13\PointOfIncidence.Tests\PointOfIncidence.Tests.csproj", "{0E74E842-A876-4E8C-9D10-BA09F40039EC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -180,6 +186,14 @@ Global {2731DE56-AF4B-4009-8259-2EA5A9A102FE}.Debug|Any CPU.Build.0 = Debug|Any CPU {2731DE56-AF4B-4009-8259-2EA5A9A102FE}.Release|Any CPU.ActiveCfg = Release|Any CPU {2731DE56-AF4B-4009-8259-2EA5A9A102FE}.Release|Any CPU.Build.0 = Release|Any CPU + {334D6DFF-6131-49C1-B54C-B9E8E00F1E3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {334D6DFF-6131-49C1-B54C-B9E8E00F1E3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {334D6DFF-6131-49C1-B54C-B9E8E00F1E3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {334D6DFF-6131-49C1-B54C-B9E8E00F1E3E}.Release|Any CPU.Build.0 = Release|Any CPU + {0E74E842-A876-4E8C-9D10-BA09F40039EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E74E842-A876-4E8C-9D10-BA09F40039EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E74E842-A876-4E8C-9D10-BA09F40039EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E74E842-A876-4E8C-9D10-BA09F40039EC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {3F8EAC09-4BC7-43AA-B72B-48DDD2710F6D} = {8C29858C-623A-461A-BF0B-254E151CD9C2} @@ -206,5 +220,7 @@ Global {0D6CD658-65BB-47DC-A865-E3428EBE3075} = {01A6D73F-996E-48B3-B111-2725016A49C2} {DB4A8A1F-54A8-4534-AE0A-027B365AA73B} = {ABF03698-B81C-45DE-B76A-C7FBC0C72DB6} {2731DE56-AF4B-4009-8259-2EA5A9A102FE} = {ABF03698-B81C-45DE-B76A-C7FBC0C72DB6} + {334D6DFF-6131-49C1-B54C-B9E8E00F1E3E} = {DC4E691A-0061-4937-8732-E8D8073C868D} + {0E74E842-A876-4E8C-9D10-BA09F40039EC} = {DC4E691A-0061-4937-8732-E8D8073C868D} EndGlobalSection EndGlobal diff --git a/README.md b/README.md index 35d0522..eb8f2d6 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ dotnet build | 10 | [Problem](./10/PROBLEM.md) | [Solution](./10/PipeMaze/) | ✅ | So...my solutions are rather slow, but they work. Part 2 appears to have a mathematical solution, but scanning is what I came up with on my own. | | 11 | [Problem](./11/PROBLEM.md) | [Solution](./11/CosmicExpansion/) | ✅ | Expanding the universe was fine in part 1, but part 2 showed I actually needed to calculate the expansion instead of expanding the input. | | 12 | [Problem](./12/PROBLEM.md) | [Solution](./12/HotSprings/) | ✅ | This one stretched my skills. I needed lots of help from the interwebz. | -| 13 | [Problem](./13/PROBLEM.md) | [Solution](./13/) | ⌛ | +| 13 | [Problem](./13/PROBLEM.md) | [Solution](./13/PointOfIncidence/) | ✅ | This solution is the one I think I'm most proud of so far. | | 14 | [Problem](./14/PROBLEM.md) | [Solution](./14/) | ⌛ | | 15 | [Problem](./15/PROBLEM.md) | [Solution](./15/) | ⌛ | | 16 | [Problem](./16/PROBLEM.md) | [Solution](./16/) | ⌛ |