Merge pull request #13 from StevanFreeborn/stevanfreeborn/feat/solve-puzzle-13
feat: solve puzzle 13
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
global using Xunit;
|
|
||||||
global using FluentAssertions;
|
global using FluentAssertions;
|
||||||
|
|
||||||
|
global using Xunit;
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
global using Xunit;
|
|
||||||
global using FluentAssertions;
|
global using FluentAssertions;
|
||||||
|
|
||||||
|
global using Xunit;
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
global using FluentAssertions;
|
||||||
|
|
||||||
|
global using Xunit;
|
||||||
@@ -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<object[]> ParseTestData =>
|
||||||
|
new List<object[]>
|
||||||
|
{
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
new string[]
|
||||||
|
{
|
||||||
|
"#.##..##.",
|
||||||
|
"..#.##.#.",
|
||||||
|
},
|
||||||
|
new Pattern(
|
||||||
|
[
|
||||||
|
['#', '.', '#', '#', '.', '.', '#', '#', '.'],
|
||||||
|
['.', '.', '#', '.', '#', '#', '.', '#', '.'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
['#', '.'],
|
||||||
|
['.', '.'],
|
||||||
|
['#', '#'],
|
||||||
|
['#', '.'],
|
||||||
|
['.', '#'],
|
||||||
|
['.', '#'],
|
||||||
|
['#', '.'],
|
||||||
|
['#', '#'],
|
||||||
|
['.', '.'],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> FindPointOfReflectionWithoutSmudgeTestData =>
|
||||||
|
new List<object[]>
|
||||||
|
{
|
||||||
|
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<object[]> FindPointOfReflectionTestData =>
|
||||||
|
new List<object[]>
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<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="..\PointOfIncidence\PointOfIncidence.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="..\INPUT.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include=".\EXAMPLE.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,518 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace PointOfIncidence;
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rows">The rows of the pattern.</param>
|
||||||
|
/// <param name="columns">The columns of the pattern.</param>
|
||||||
|
/// <returns>A <see cref="Pattern"/> instance.</returns>
|
||||||
|
public class Pattern(
|
||||||
|
List<List<char>> rows,
|
||||||
|
List<List<char>> columns
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the rows of the pattern.
|
||||||
|
/// </summary>
|
||||||
|
public List<List<char>> Rows { get; init; } = rows;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the columns of the pattern.
|
||||||
|
/// </summary>
|
||||||
|
public List<List<char>> Columns { get; init; } = columns;
|
||||||
|
|
||||||
|
private bool HasSmudge(List<char> row, List<char> 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<char> start;
|
||||||
|
List<char> end;
|
||||||
|
List<List<char>> 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<char> start;
|
||||||
|
List<char> end;
|
||||||
|
List<List<char>> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the point of reflection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cleanSmudge">Indicates whether to clean smudges.</param>
|
||||||
|
/// <returns>A <see cref="PointOfReflection"/> instance at which the reflection occurs.</returns>
|
||||||
|
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<PointOfReflection>();
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Summarizes the pattern notes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cleanSmudge">Indicates whether to clean smudges.</param>
|
||||||
|
/// <returns>A number that represents the summary of the pattern notes.</returns>
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the input into a <see cref="Pattern"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The input to parse.</param>
|
||||||
|
/// <returns>A <see cref="Pattern"/> instance.</returns>
|
||||||
|
public static Pattern Parse(string[] input)
|
||||||
|
{
|
||||||
|
var columns = new List<List<char>>();
|
||||||
|
|
||||||
|
var height = input.Length;
|
||||||
|
var width = input[0].Length;
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
var column = new List<char>();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a point of reflection
|
||||||
|
/// </summary>
|
||||||
|
public class PointOfReflection : IEquatable<PointOfReflection>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type of the reflection.
|
||||||
|
/// </summary>
|
||||||
|
public ReflectionType Type { get; set; } = ReflectionType.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the start index of the reflection.
|
||||||
|
/// </summary>
|
||||||
|
public int StartIndex { get; set; } = -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the end index of the reflection.
|
||||||
|
/// </summary>
|
||||||
|
public int EndIndex { get; set; } = -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the current instance is equal to another instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">An instance of <see cref="PointOfReflection"/> to compare with this instance.</param>
|
||||||
|
/// <returns>true if the current instance is equal to the other parameter; otherwise, false.</returns>
|
||||||
|
public bool Equals(PointOfReflection? other) =>
|
||||||
|
other is not null &&
|
||||||
|
Type == other.Type &&
|
||||||
|
StartIndex == other.StartIndex &&
|
||||||
|
EndIndex == other.EndIndex;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified object is equal to the current object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to compare with the current object.</param>
|
||||||
|
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return Equals(obj as PointOfReflection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the hash code for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An integer that is the hash code for this instance.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Type, StartIndex, EndIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the type of reflection
|
||||||
|
/// </summary>
|
||||||
|
public enum ReflectionType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reflection that occurs on the horizontal axis
|
||||||
|
/// </summary>
|
||||||
|
Horizontal,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reflection that occurs on the vertical axis
|
||||||
|
/// </summary>
|
||||||
|
Vertical,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No reflection
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
}
|
||||||
@@ -75,6 +75,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotSprings", "12\HotSprings
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotSprings.Tests", "12\HotSprings.Tests\HotSprings.Tests.csproj", "{2731DE56-AF4B-4009-8259-2EA5A9A102FE}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotSprings.Tests", "12\HotSprings.Tests\HotSprings.Tests.csproj", "{2731DE56-AF4B-4009-8259-2EA5A9A102FE}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{2731DE56-AF4B-4009-8259-2EA5A9A102FE}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{3F8EAC09-4BC7-43AA-B72B-48DDD2710F6D} = {8C29858C-623A-461A-BF0B-254E151CD9C2}
|
{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}
|
{0D6CD658-65BB-47DC-A865-E3428EBE3075} = {01A6D73F-996E-48B3-B111-2725016A49C2}
|
||||||
{DB4A8A1F-54A8-4534-AE0A-027B365AA73B} = {ABF03698-B81C-45DE-B76A-C7FBC0C72DB6}
|
{DB4A8A1F-54A8-4534-AE0A-027B365AA73B} = {ABF03698-B81C-45DE-B76A-C7FBC0C72DB6}
|
||||||
{2731DE56-AF4B-4009-8259-2EA5A9A102FE} = {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
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -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. |
|
| 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. |
|
| 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. |
|
| 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/) | ⌛ |
|
| 14 | [Problem](./14/PROBLEM.md) | [Solution](./14/) | ⌛ |
|
||||||
| 15 | [Problem](./15/PROBLEM.md) | [Solution](./15/) | ⌛ |
|
| 15 | [Problem](./15/PROBLEM.md) | [Solution](./15/) | ⌛ |
|
||||||
| 16 | [Problem](./16/PROBLEM.md) | [Solution](./16/) | ⌛ |
|
| 16 | [Problem](./16/PROBLEM.md) | [Solution](./16/) | ⌛ |
|
||||||
|
|||||||
Reference in New Issue
Block a user