Merge pull request #9 from StevanFreeborn/stevanfreeborn/feat/solve-puzzle-9

feat: solve puzzle 9
This commit is contained in:
Stevan Freeborn
2023-12-09 21:25:58 -06:00
committed by GitHub
10 changed files with 587 additions and 29 deletions
+2 -1
View File
@@ -1,2 +1,3 @@
global using Xunit;
global using FluentAssertions;
global using Xunit;
@@ -0,0 +1,3 @@
global using FluentAssertions;
global using Xunit;
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MirageMaintenance\MirageMaintenance.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="..\INPUT.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
@@ -0,0 +1,77 @@
namespace MirageMaintenance.Tests;
public class UnitTest1
{
[Theory]
[MemberData(nameof(TestData.OasisReportParseTestData), MemberType = typeof(TestData))]
public void Parse_GivenAReportInput_ItShouldReturnExpectedOasisReportInstance(string[] input, OasisReport expected)
{
OasisReport
.Parse(input)
.Should()
.BeEquivalentTo(expected);
}
[Fact]
public void CalculateSumOfNextValues_GivenAReportInput_ItShouldReturnTheSumOfAllNextValues()
{
var input = new string[]
{
"0 3 6 9 12 15",
"1 3 6 10 15 21",
"10 13 16 21 30 45",
};
OasisReport
.Parse(input)
.CalculateSumOfNextValues()
.Should()
.Be(114);
}
[Fact]
public void CalculateSumOfNextValues_WhenGivenInput_ItShouldReturnTheSumOfAllNextValues()
{
OasisReport
.Parse(TestData.Input)
.CalculateSumOfNextValues()
.Should()
.Be(2175229206);
}
[Fact]
public void CalculateSumOfNextValues_WhenGivenInputAndBackwardsIsTrue_ItShouldReturnTheSumOfAllNextValues()
{
OasisReport
.Parse(TestData.Input)
.CalculateSumOfNextValues(true)
.Should()
.Be(942);
}
public static class TestData
{
public static readonly string[] Input = File.ReadAllLines("INPUT.txt");
public static IEnumerable<object[]> OasisReportParseTestData =>
new List<object[]>
{
new object[]
{
new string[]
{
"0 3 6 9 12 15",
"1 3 6 10 15 21",
"10 13 16 21 30 45",
},
new OasisReport(
[
new([0, 3, 6, 9, 12, 15]),
new([1, 3, 6, 10, 15, 21]),
new([10, 13, 16, 21, 30, 45]),
]
)
}
};
}
}
@@ -0,0 +1,249 @@
namespace MirageMaintenance.Tests;
public class ValueHistoryTests
{
[Theory]
[MemberData(nameof(TestData.CalculateDifferencesTestData), MemberType = typeof(TestData))]
public void CalculateDifferences_GivenAListOfValues_ItShouldReturnAListOfDifferences(List<long> values, List<long> expected)
{
new ValueHistory([])
.CalculateDifferences(values)
.Should()
.BeEquivalentTo(expected);
}
[Theory]
[MemberData(nameof(TestData.CalculateHistoryTestData), MemberType = typeof(TestData))]
public void CalculateHistory_GivenAListOfValues_ItShouldReturnAListOfHistoricalValues(List<long> values, List<List<long>> expected)
{
new ValueHistory(values)
.CalculateHistory()
.Should()
.BeEquivalentTo(expected);
}
[Theory]
[MemberData(nameof(TestData.CalculateNextValueTestData), MemberType = typeof(TestData))]
public void CalculateNextValue_GivenAListOfValues_ItShouldReturnTheNextValue(List<long> values, long expected)
{
new ValueHistory(values)
.CalculateNextValue()
.Should()
.Be(expected);
}
[Theory]
[MemberData(nameof(TestData.CalculateNextValueTestDataBackwards), MemberType = typeof(TestData))]
public void CalculateNextValue_GivenAListOfValuesAndBackwardsIsTrue_ItShouldReturnTheNextValue(List<long> values, long expected)
{
new ValueHistory(values)
.CalculateNextValue(true)
.Should()
.Be(expected);
}
public static class TestData
{
public static IEnumerable<object[]> CalculateNextValueTestDataBackwards =>
new List<object[]>
{
new object[]
{
new List<long> { 10, 13, 16, 21, 30, 45 },
5,
}
};
public static IEnumerable<object[]> CalculateNextValueTestData =>
new List<object[]>
{
new object[]
{
new List<long> { 0, 3, 6, 9, 12, 15 },
18,
},
new object[]
{
new List<long> { 1, 3, 6, 10, 15, 21 },
28,
},
new object[]
{
new List<long> { 10, 13, 16, 21, 30, 45 },
68,
},
new object[]
{
new List<long> { -7, 6, 44, 130, 309, 672, 1404, 2864, 5712, 11113, 21082, 39112, 71386, 129156, 233312, 422773, 769075, 1400300, 2538072, 4551386, 8029995 },
13877188,
},
new object[]
{
new List<long> { 5, 13, 45, 115, 234, 420, 731, 1329, 2591, 5314, 11131, 23388, 48974, 102035, 211293, 434077, 882526, 1771333, 3502944, 6817585, 13056927 },
24632652
},
new object[]
{
new List<long> { 12, 34, 63, 97, 134, 172, 209, 243, 272, 294, 307, 309, 298, 272, 229, 167, 84, -22, -153, -311, -498 },
-716,
},
new object[]
{
new List<long> { 0, 8, 26, 57, 105, 173, 258, 346, 429, 605, 1397, 4561, 14876, 43758, 116059, 282152, 638422, 1360646, 2756524, 5345897, 9980043 },
18014971,
},
new object[]
{
new List<long> { 8, 29, 72, 144, 248, 390, 605, 1026, 2039, 4596, 10807, 25025, 55832, 119755, 248445, 502919, 1002134, 1980015, 3897262, 7655070, 14992036 },
29199652,
},
new object[]
{
new List<long> { 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7 },
-8,
},
new object[]
{
new List<long> { -6, -13, -22, -33, -46, -61, -78, -97, -118, -141, -166, -193, -222, -253, -286, -321, -358, -397, -438, -481, -526 },
-573
},
new object[]
{
new List<long> { 9, 27, 56, 112, 226, 457, 930, 1921, 4030, 8514, 17905, 37139, 75621, 151030, 296349, 572758, 1092879, 2061701, 3846702, 7094666, 12920996 },
23208575,
},
new object[]
{
new List<long> { -3, -1, 14, 61, 171, 389, 774, 1400, 2372, 3888, 6401, 10974, 20014, 38812, 78893, 165423, 353359, 761461, 1640856, 3507131, 7384045 },
15235639,
},
new object[]
{
new List<long> { 11, 29, 63, 133, 274, 553, 1096, 2121, 3987, 7294, 13115, 23530, 42796, 79765, 152604, 297574, 584852, 1146848, 2229936, 4292852, 8201987 },
15629938,
},
new object[]
{
new List<long> { 4, 16, 45, 98, 187, 334, 576, 970, 1598, 2572, 4039, 6186, 9245, 13498, 19282, 26994, 37096, 50120, 66673, 87442, 113199 },
144806,
},
new object[]
{
new List<long> { 8, 20, 57, 137, 294, 600, 1198, 2360, 4606, 8946, 17345, 33579, 64776, 124157, 235847, 443145, 822344, 1505117, 2713796, 4816071, 8409952 },
14458829,
},
new object[]
{
new List<long> { 13, 16, 31, 72, 171, 391, 853, 1788, 3635, 7233, 14219, 27894, 55158, 110850, 227371, 475612, 1009429, 2157809, 4610859, 9784975, 20520225 },
42376168
}
};
public static IEnumerable<object[]> CalculateHistoryTestData =>
new List<object[]>
{
new object[]
{
new List<long> { 0, 3, 6, 9, 12, 15 },
new List<List<long>>
{
new() { 3, 3, 3, 3, 3 },
new() { 0, 0, 0, 0 },
},
},
new object[]
{
new List<long> { 1, 3, 6, 10, 15, 21 },
new List<List<long>>
{
new() { 2, 3, 4, 5, 6 },
new() { 1, 1, 1, 1 },
new() { 0, 0, 0 },
},
},
new object[]
{
new List<long> { 10, 13, 16, 21, 30, 45 },
new List<List<long>>
{
new() { 3, 3, 5, 9, 15 },
new() { 0, 2, 4, 6 },
new() { 2, 2, 2 },
new() { 0, 0 },
},
},
new object[]
{
new List<long> { -7, 6, 44, 130, 309, 672, 1404, 2864, 5712, 11113, 21082, 39112, 71386, 129156, 233312, 422773, 769075, 1400300, 2538072, 4551386, 8029995 },
new List<List<long>>
{
new() { 13, 38, 86, 179, 363, 732, 1460, 2848, 5401, 9969, 18030, 32274, 57770, 104156, 189461, 346302, 631225, 1137772, 2013314, 3478609 },
new() { 25, 48, 93, 184, 369, 728, 1388, 2553, 4568, 8061, 14244, 25496, 46386, 85305, 156841, 284923, 506547, 875542, 1465295 },
new() { 23, 45, 91, 185, 359, 660, 1165, 2015, 3493, 6183, 11252, 20890, 38919, 71536, 128082, 221624, 368995, 589753 },
new() { 22, 46, 94, 174, 301, 505, 850, 1478, 2690, 5069, 9638, 18029, 32617, 56546, 93542, 147371, 220758 },
new() { 24, 48, 80, 127, 204, 345, 628, 1212, 2379, 4569, 8391, 14588, 23929, 36996, 53829, 73387 },
new() { 24, 32, 47, 77, 141, 283, 584, 1167, 2190, 3822, 6197, 9341, 13067, 16833, 19558 },
new() { 8, 15, 30, 64, 142, 301, 583, 1023, 1632, 2375, 3144, 3726, 3766, 2725 },
new() { 7, 15, 34, 78, 159, 282, 440, 609, 743, 769, 582, 40, -1041 },
new() { 8, 19, 44, 81, 123, 158, 169, 134, 26, -187, -542, -1081 },
new() { 11, 25, 37, 42, 35, 11, -35, -108, -213, -355, -539 },
new() { 14, 12, 5, -7, -24, -46, -73, -105, -142, -184 },
new() { -2, -7, -12, -17, -22, -27, -32, -37, -42 },
new() { -5, -5, -5, -5, -5, -5, -5, -5 },
new() { 0, 0, 0, 0, 0, 0, 0 },
}
},
new object[]
{
new List<long> { 8, 20, 57, 137, 294, 600, 1198, 2360, 4606, 8946, 17345, 33579, 64776, 124157, 235847, 443145, 822344, 1505117, 2713796, 4816071, 8409952 },
new List<List<long>>
{
new() { 12, 37, 80, 157, 306, 598, 1162, 2246, 4340, 8399, 16234, 31197, 59381, 111690, 207298, 379199, 682773, 1208679, 2102275, 3593881 },
new() { 25, 43, 77, 149, 292, 564, 1084, 2094, 4059, 7835, 14963, 28184, 52309, 95608, 171901, 303574, 525906, 893596, 1491606 },
new() { 18, 34, 72, 143, 272, 520, 1010, 1965, 3776, 7128, 13221, 24125, 43299, 76293, 131673, 222332, 367690, 598010 },
new() { 16, 38, 71, 129, 248, 490, 955, 1811, 3352, 6093, 10904, 19174, 32994, 55380, 90659, 145358, 230320 },
new() { 22, 33, 58, 119, 242, 465, 856, 1541, 2741, 4811, 8270, 13820, 22386, 35279, 54699, 84962 },
new() { 11, 25, 61, 123, 223, 391, 685, 1200, 2070, 3459, 5550, 8566, 12893, 19420, 30263 },
new() { 14, 36, 62, 100, 168, 294, 515, 870, 1389, 2091, 3016, 4327, 6527, 10843 },
new() { 22, 26, 38, 68, 126, 221, 355, 519, 702, 925, 1311, 2200, 4316 },
new() { 4, 12, 30, 58, 95, 134, 164, 183, 223, 386, 889, 2116 },
new() { 8, 18, 28, 37, 39, 30, 19, 40, 163, 503, 1227 },
new() { 10, 10, 9, 2, -9, -11, 21, 123, 340, 724 },
new() { 0, -1, -7, -11, -2, 32, 102, 217, 384 },
new() { -1, -6, -4, 9, 34, 70, 115, 167 },
new() { -5, 2, 13, 25, 36, 45, 52 },
new() { 7, 11, 12, 11, 9, 7 },
new() { 4, 1, -1, -2, -2 },
new() { -3, -2, -1, 0 },
new() { 1, 1, 1 },
new() { 0, 0 },
}
}
};
public static IEnumerable<object[]> CalculateDifferencesTestData =>
new List<object[]>
{
new object[]
{
new List<long> { 0, 3, 6, 9, 12, 15 },
new List<long> { 3, 3, 3, 3, 3 },
},
new object[]
{
new List<long> { 1, 3, 6, 10, 15, 21 },
new List<long> { 2, 3, 4, 5, 6 },
},
new object[]
{
new List<long> { 10, 13, 16, 21, 30, 45 },
new List<long> { 3, 3, 5, 9, 15 },
},
new object[]
{
new List<long> { 10, 13, 16 },
new List<long> { 3, 3 },
}
};
}
}
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+166
View File
@@ -0,0 +1,166 @@
using System.Diagnostics;
namespace MirageMaintenance;
public class Program
{
public static async Task<int> 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.ReadAllLinesAsync(args[0]);
var stopwatch = new Stopwatch();
stopwatch.Start();
var result = OasisReport.Parse(input).CalculateSumOfNextValues(isPart2);
stopwatch.Stop();
Console.WriteLine($"The sum of all next values is {result}. ({stopwatch.ElapsedMilliseconds}ms)");
return (int)result;
}
}
/// <summary>
/// Represents a report from the Oasis.
/// </summary>
/// <param name="ValueHistories">The value histories.</param>
/// <returns>An instance of <see cref="OasisReport"/>.</returns>
public class OasisReport(
List<ValueHistory> valueHistories
)
{
/// <summary>
/// Gets the value histories.
/// </summary>
public List<ValueHistory> ValueHistories { get; init; } = valueHistories;
/// <summary>
/// Calculates the sum of all next values.
/// </summary>
/// <param name="backwards">if set to true will extrapolate next values backwards</param>
/// <returns>The sum of all next values.</returns>
public long CalculateSumOfNextValues(bool backwards = false) => ValueHistories
.Select(valueHistory => valueHistory.CalculateNextValue(backwards))
.Sum();
/// <summary>
/// Parses the specified oasis report input.
/// </summary>
/// <param name="oasisReportInput">The oasis report input.</param>
/// <returns>An instance of <see cref="OasisReport"/>.</returns>
public static OasisReport Parse(string[] oasisReportInput)
{
var valueHistories = new List<ValueHistory>();
foreach (var line in oasisReportInput)
{
var values = line
.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.Select(long.Parse)
.ToList();
var valueHistory = new ValueHistory(values);
valueHistories.Add(valueHistory);
}
return new OasisReport(valueHistories);
}
}
/// <summary>
/// Represents a value history.
/// </summary>
/// <param name="Values">The values.</param>
/// <returns>An instance of <see cref="ValueHistory"/>.</returns>
public class ValueHistory(
List<long> values
)
{
/// <summary>
/// Gets the values.
/// </summary>
List<long> Values { get; init; } = values;
/// <summary>
/// Calculates the differences between each value.
/// </summary>
/// <param name="values">The values.</param>
/// <returns>The differences between each value.</returns>
public List<long> CalculateDifferences(List<long> values) => Enumerable
.Range(0, values.Count - 1)
.Select(i => values[i + 1] - values[i])
.ToList();
/// <summary>
/// Calculates the history.
/// </summary>
/// <returns>The history.</returns>
public List<List<long>> CalculateHistory()
{
var allHistoricalValues = new List<List<long>>();
var currentValues = Values;
while (
allHistoricalValues.Count is 0 ||
allHistoricalValues.Last().Any(value => value is not 0)
)
{
var historicalValues = CalculateDifferences(currentValues);
allHistoricalValues.Add(historicalValues);
currentValues = historicalValues;
}
return allHistoricalValues;
}
/// <summary>
/// Calculates the next value.
/// </summary>
/// <param name="backwards">if set to true will extrapolate next value backwards</param>
/// <returns>The next value.</returns>
public long CalculateNextValue(bool backwards = false)
{
var historicalValues = CalculateHistory();
var values = historicalValues.Prepend(Values).Reverse().ToList();
if (backwards)
{
values.ForEach(value => value.Reverse());
}
for (var i = 0; i < values.Count; i++)
{
var currentValues = values[i];
if (i is 0)
{
currentValues.Add(0);
continue;
}
var previousValues = values[i - 1];
var extrapolatedValue = backwards
? currentValues.Last() - previousValues.Last()
: currentValues.Last() + previousValues.Last();
currentValues.Add(extrapolatedValue);
}
return values.Last().Last();
}
}
+16
View File
@@ -51,6 +51,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HauntedWasteland", "08\Haun
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HauntedWasteland.Tests", "08\HauntedWasteland.Tests\HauntedWasteland.Tests.csproj", "{FA8DDDD1-4DD9-4927-A9FB-C4FACDEAF901}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "09", "09", "{79203C8D-F382-4C95-90EA-FECEE65602DA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MirageMaintenance", "09\MirageMaintenance\MirageMaintenance.csproj", "{6C233DE5-D1D0-46C0-A250-AF0272B495CE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MirageMaintenance.Tests", "09\MirageMaintenance.Tests\MirageMaintenance.Tests.csproj", "{5C39C115-ACBF-458A-9409-FBD23637A789}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -124,6 +130,14 @@ Global
{FA8DDDD1-4DD9-4927-A9FB-C4FACDEAF901}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA8DDDD1-4DD9-4927-A9FB-C4FACDEAF901}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA8DDDD1-4DD9-4927-A9FB-C4FACDEAF901}.Release|Any CPU.Build.0 = Release|Any CPU
{6C233DE5-D1D0-46C0-A250-AF0272B495CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C233DE5-D1D0-46C0-A250-AF0272B495CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C233DE5-D1D0-46C0-A250-AF0272B495CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C233DE5-D1D0-46C0-A250-AF0272B495CE}.Release|Any CPU.Build.0 = Release|Any CPU
{5C39C115-ACBF-458A-9409-FBD23637A789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5C39C115-ACBF-458A-9409-FBD23637A789}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5C39C115-ACBF-458A-9409-FBD23637A789}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5C39C115-ACBF-458A-9409-FBD23637A789}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{3F8EAC09-4BC7-43AA-B72B-48DDD2710F6D} = {8C29858C-623A-461A-BF0B-254E151CD9C2}
@@ -142,5 +156,7 @@ Global
{8F04A78E-D2E1-41AC-B43C-74608B7B4FCB} = {7F8AD027-D8D7-407B-9E08-B363B7B34621}
{332B56C1-8ECB-4E34-9E69-54BF6A192CFB} = {F21CCF39-1F8A-40DA-A0E5-F1426B09BAA2}
{FA8DDDD1-4DD9-4927-A9FB-C4FACDEAF901} = {F21CCF39-1F8A-40DA-A0E5-F1426B09BAA2}
{6C233DE5-D1D0-46C0-A250-AF0272B495CE} = {79203C8D-F382-4C95-90EA-FECEE65602DA}
{5C39C115-ACBF-458A-9409-FBD23637A789} = {79203C8D-F382-4C95-90EA-FECEE65602DA}
EndGlobalSection
EndGlobal
+2 -2
View File
@@ -43,7 +43,7 @@ dotnet build
## Challenges
| Day | Problem | Solution | Status | Notes |
| --- | -------------------------- | :--------------------------------: | :----: | ------------------------------------------------------------------------------------------------------- |
| --- | -------------------------- | :---------------------------------: | :----: | ------------------------------------------------------------------------------------------------------------------------------------ |
| 01 | [Problem](./01/PROBLEM.md) | [Solution](./01/Trebuchet/) | ✅ | The trickiest part here was accounting for overlapping digit words. |
| 02 | [Problem](./02/PROBLEM.md) | [Solution](./02/CubeConundrum/) | ✅ | The key to me here was to parse the input into a useful model. |
| 03 | [Problem](./03/PROBLEM.md) | [Solution](./03/GearRatios/) | ✅ | The edge case that got me here was lines ending with a part number. |
@@ -52,7 +52,7 @@ dotnet build
| 06 | [Problem](./06/PROBLEM.md) | [Solution](./06/WaitForIt/) | ✅ | Thank goodness part 2 was not like 5's part 2. 😅 |
| 07 | [Problem](./07/PROBLEM.md) | [Solution](./07/CamelCards/) | ✅ | What took me longest here was I missed a case when jokers are wild and there are three groups of cards. |
| 08 | [Problem](./08/PROBLEM.md) | [Solution](./08/HauntedWasteland/) | ✅ | Got to implement a least common multiple algorithm for part 2. |
| 09 | [Problem](./09/PROBLEM.md) | [Solution](./09/) | ⌛ |
| 09 | [Problem](./09/PROBLEM.md) | [Solution](./09/MirageMaintenance/) | | Part 1 took me unnecessarily long. The bug was summing a line to check for all zeros is bad idea when negative numbers are involved. |
| 10 | [Problem](./10/PROBLEM.md) | [Solution](./10/) | ⌛ |
| 11 | [Problem](./11/PROBLEM.md) | [Solution](./11/) | ⌛ |
| 12 | [Problem](./12/PROBLEM.md) | [Solution](./12/) | ⌛ |