feat: solve puzzle 3
This commit is contained in:
@@ -9,16 +9,16 @@ public class Program
|
|||||||
if (args.Length is 0)
|
if (args.Length is 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Please provide a path to the input file.");
|
Console.WriteLine("Please provide a path to the input file.");
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (File.Exists(args[0]) is false)
|
if (File.Exists(args[0]) is false)
|
||||||
{
|
{
|
||||||
Console.WriteLine("The provided file does not exist.");
|
Console.WriteLine("The provided file does not exist.");
|
||||||
return 2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPuzzleSolver puzzleSolver = args.Length > 1 && args[1] == "2"
|
IPuzzleSolver puzzleSolver = args.Length > 1 && args[1] == "part2"
|
||||||
? new PartTwoPuzzleSolver()
|
? new PartTwoPuzzleSolver()
|
||||||
: new PartOnePuzzleSolver();
|
: new PartOnePuzzleSolver();
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ public class Program
|
|||||||
|
|
||||||
Console.WriteLine($"The sum of all calibration values is {result}.");
|
Console.WriteLine($"The sum of all calibration values is {result}.");
|
||||||
|
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,14 @@ public class Program
|
|||||||
? puzzleSolver.SumGameMinimumPowers(games)
|
? puzzleSolver.SumGameMinimumPowers(games)
|
||||||
: puzzleSolver.SumPossibleGameIds(games);
|
: puzzleSolver.SumPossibleGameIds(games);
|
||||||
|
|
||||||
Console.WriteLine($"The sum of all possible game ids is {result}.");
|
if (args.Length > 1 && args[1] == "part2")
|
||||||
|
{
|
||||||
|
Console.WriteLine($"The sum of the minimum powers of all games is {result}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"The sum of all possible game ids is {result}.");
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
global using Xunit;
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace GearRatios.Test;
|
|
||||||
|
|
||||||
public class UnitTest1
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void Test1()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -10,6 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.2" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
global using Xunit;
|
||||||
|
global using FluentAssertions;
|
||||||
@@ -0,0 +1,353 @@
|
|||||||
|
namespace GearRatios.Test;
|
||||||
|
|
||||||
|
public class LineTests
|
||||||
|
{
|
||||||
|
[Theory, MemberData(nameof(TestData.LineData), MemberType = typeof(TestData))]
|
||||||
|
public void Parse_GivenLine_ItShouldParseExpectedValues(string line, Line expected)
|
||||||
|
{
|
||||||
|
var actual = Line.Parse(line);
|
||||||
|
actual.Should().BeEquivalentTo(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, MemberData(nameof(TestData.PartNumberData), MemberType = typeof(TestData))]
|
||||||
|
public void GetPartNumbers_GivenLine_ItShouldReturnExpectedValues(Line currentLine, Line? prevLine, Line? nextLine, List<int> expected)
|
||||||
|
{
|
||||||
|
var actual = currentLine.GetPartNumbers(prevLine, nextLine);
|
||||||
|
actual.Should().BeEquivalentTo(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, MemberData(nameof(TestData.GearData), MemberType = typeof(TestData))]
|
||||||
|
public void GetGearRatios_GivenLine_ItShouldReturnExpectedValues(Line currentLine, Line? prevLine, Line? nextLine, List<int> expected)
|
||||||
|
{
|
||||||
|
var actual = currentLine.GetGearRatios(prevLine, nextLine);
|
||||||
|
actual.Should().BeEquivalentTo(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class TestData
|
||||||
|
{
|
||||||
|
public static IEnumerable<object?[]> GearData =>
|
||||||
|
new List<object?[]>
|
||||||
|
{
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[],
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int>(),
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 467, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 114, new Indexes(5, 7) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int>(),
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int>(),
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 617, new Indexes(0, 2) },
|
||||||
|
{ 114, new Indexes(4, 6) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int> { 617 * 114 },
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 467, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 114, new Indexes(5, 7) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 35, new Indexes(2, 3) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 633, new Indexes(6, 8) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
new List<int> { 467 * 35 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static IEnumerable<object?[]> PartNumberData =>
|
||||||
|
new List<object?[]>
|
||||||
|
{
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 467, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 114, new Indexes(5, 7) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int>(),
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int>(),
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 617, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int> { 617 },
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 617, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 114, new Indexes(6, 8) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(9, 9) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new List<int> { 617, 114 },
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 467, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 114, new Indexes(5, 7) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
]
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
new Line(
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
new List<int>() { 467 },
|
||||||
|
},
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 58, new Indexes(7, 8) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "+", new Indexes(5, 5) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 617, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 592, new Indexes(2, 4) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
new List<int>(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> LineData =>
|
||||||
|
new List<object[]>
|
||||||
|
{
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
"467..114..",
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 467, new Indexes(0, 2) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 114, new Indexes(5, 7) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
},
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
"...*......",
|
||||||
|
new Line(
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "*", new Indexes(3, 3) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
},
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
"...41+...564",
|
||||||
|
new Line(
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 41, new Indexes(3, 4) },
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ 564, new Indexes(9, 11) },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "+", new Indexes(5, 5) },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
namespace GearRatios.Test;
|
||||||
|
|
||||||
|
public class PuzzleSolverTests
|
||||||
|
{
|
||||||
|
private readonly PuzzleSolver _sut = new();
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(TestData.SumPartNumbersData), MemberType = typeof(TestData))]
|
||||||
|
public void SumPartNumbers_GivenSchematic_ItShouldReturnExpectedValue(string[] schematic, int expected)
|
||||||
|
{
|
||||||
|
var actual = _sut.SumPartNumbers(schematic);
|
||||||
|
actual.Should().Be(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(TestData.SumGearRatios), MemberType = typeof(TestData))]
|
||||||
|
public void SumGearRatios_GivenSchematic_ItShouldReturnExpectedValue(string[] schematic, int expected)
|
||||||
|
{
|
||||||
|
var actual = _sut.SumGearRatios(schematic);
|
||||||
|
actual.Should().Be(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestData
|
||||||
|
{
|
||||||
|
private static readonly string[] TestSchematic =
|
||||||
|
[
|
||||||
|
"467..114..",
|
||||||
|
"...*......",
|
||||||
|
"..35..633.",
|
||||||
|
"......#...",
|
||||||
|
"617*......",
|
||||||
|
".....+.58.",
|
||||||
|
"..592.....",
|
||||||
|
"......755.",
|
||||||
|
"...$.*....",
|
||||||
|
".664.598..",
|
||||||
|
];
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> SumGearRatios =>
|
||||||
|
new List<object[]>
|
||||||
|
{
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
TestSchematic,
|
||||||
|
467835,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
public static IEnumerable<object?[]> SumPartNumbersData =>
|
||||||
|
new List<object?[]>
|
||||||
|
{
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
TestSchematic,
|
||||||
|
4361,
|
||||||
|
},
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
"...................305.124................................432..............................................576..313.....514.................",
|
||||||
|
".............113...-......&....................&...819...........654..../..........................&901................*....869.257.........",
|
||||||
|
"...377..&783../.................................9...........855*......940..463................-.........................844.*....@......679.",
|
||||||
|
"......*...........197.261.....817..336.759............&742......548.......&........748......844.............#.......&........254...169..*...",
|
||||||
|
},
|
||||||
|
10421,
|
||||||
|
},
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
".............................457....834.....................94..564..........&.........498....*...304....../...*.....*..........845.....&...",
|
||||||
|
".......12*48.753...244..196....=......$..721....90*29.........*.................+.522.......487...............317.....531..311........20....",
|
||||||
|
".177...............*.....*.................*.............*969.611.......*565..338...*.............712..922$.......770......*....522.........",
|
||||||
|
},
|
||||||
|
8318
|
||||||
|
},
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
"663..462...........*..........109..706*.................=.............553........712......*971......674.396...635*..........................",
|
||||||
|
"........../...728.952...413......*......744.......%..........................300..*....782................*.......742..&424........41+...564",
|
||||||
|
"........375...%.........*......450.456.$.........714........851.327..#...+......*...+.......179.630....854.................................*",
|
||||||
|
},
|
||||||
|
11612
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+228
-2
@@ -1,2 +1,228 @@
|
|||||||
// See https://aka.ms/new-console-template for more information
|
namespace GearRatios;
|
||||||
Console.WriteLine("Hello, World!");
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public async static 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 puzzleSolver = new PuzzleSolver();
|
||||||
|
|
||||||
|
var input = await File.ReadAllLinesAsync(args[0]);
|
||||||
|
var result = args.Length > 1 && args[1] == "part2"
|
||||||
|
? puzzleSolver.SumGearRatios(input)
|
||||||
|
: puzzleSolver.SumPartNumbers(input);
|
||||||
|
|
||||||
|
if (args.Length > 1 && args[1] == "part2")
|
||||||
|
{
|
||||||
|
Console.WriteLine($"The sum of all gear ratios is {result}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"The sum of all part numbers is {result}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PuzzleSolver
|
||||||
|
{
|
||||||
|
public int SumPartNumbers(string[] schematic)
|
||||||
|
{
|
||||||
|
var allPartNumbers = new List<int>();
|
||||||
|
|
||||||
|
for (var i = 0; i < schematic.Length; i++)
|
||||||
|
{
|
||||||
|
var currentLine = Line.Parse(schematic[i]);
|
||||||
|
var prevLine = i > 0 ? Line.Parse(schematic[i - 1]) : null;
|
||||||
|
var nextLine = i < schematic.Length - 1 ? Line.Parse(schematic[i + 1]) : null;
|
||||||
|
var linePartNumbers = currentLine.GetPartNumbers(prevLine, nextLine);
|
||||||
|
allPartNumbers.AddRange(linePartNumbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allPartNumbers.Sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int SumGearRatios(string[] schematic)
|
||||||
|
{
|
||||||
|
var allGearRatios = new List<int>();
|
||||||
|
|
||||||
|
for (var i = 0; i < schematic.Length; i++)
|
||||||
|
{
|
||||||
|
var currentLine = Line.Parse(schematic[i]);
|
||||||
|
var prevLine = i > 0 ? Line.Parse(schematic[i - 1]) : null;
|
||||||
|
var nextLine = i < schematic.Length - 1 ? Line.Parse(schematic[i + 1]) : null;
|
||||||
|
var lineGearRatios = currentLine.GetGearRatios(prevLine, nextLine);
|
||||||
|
allGearRatios.AddRange(lineGearRatios);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allGearRatios.Sum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Line(
|
||||||
|
List<Dictionary<int, Indexes>> numbers,
|
||||||
|
List<Dictionary<string, Indexes>> specialCharacters
|
||||||
|
)
|
||||||
|
{
|
||||||
|
public List<Dictionary<int, Indexes>> Numbers { get; init; } = numbers;
|
||||||
|
public List<Dictionary<string, Indexes>> SpecialCharacters { get; init; } = specialCharacters;
|
||||||
|
public List<int> SpecialCharacterIndexes => SpecialCharacters.SelectMany(dict => dict.Values).Select(v => v.Start).ToList();
|
||||||
|
|
||||||
|
private bool IsGearCharacter(string character) => character == "*";
|
||||||
|
|
||||||
|
public List<int> GetGearRatios(Line? previousLine = null, Line? nextLine = null)
|
||||||
|
{
|
||||||
|
var gearRatios = new List<int>();
|
||||||
|
var gearCharacters = SpecialCharacters.Where(dict => dict.Keys.Any(IsGearCharacter)).ToList();
|
||||||
|
|
||||||
|
if (previousLine is not null)
|
||||||
|
{
|
||||||
|
Numbers.AddRange(previousLine.Numbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextLine is not null)
|
||||||
|
{
|
||||||
|
Numbers.AddRange(nextLine.Numbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var gear in gearCharacters)
|
||||||
|
{
|
||||||
|
foreach (var (key, value) in gear)
|
||||||
|
{
|
||||||
|
var beforeGear = value.Start - 1;
|
||||||
|
var afterGear = value.End + 1;
|
||||||
|
|
||||||
|
var gearNumbers = Numbers
|
||||||
|
.Where(
|
||||||
|
n => n.Values.Any(
|
||||||
|
v =>
|
||||||
|
v.Start >= beforeGear && v.Start <= afterGear ||
|
||||||
|
v.End >= beforeGear && v.End <= afterGear
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.SelectMany(n => n.Keys)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (gearNumbers.Count == 2)
|
||||||
|
{
|
||||||
|
gearRatios.Add(gearNumbers.First() * gearNumbers.Last());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gearRatios;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<int> GetPartNumbers(Line? previousLine = null, Line? nextLine = null)
|
||||||
|
{
|
||||||
|
var partNumbers = new List<int>();
|
||||||
|
|
||||||
|
if (previousLine is not null)
|
||||||
|
{
|
||||||
|
SpecialCharacters.AddRange(previousLine.SpecialCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextLine is not null)
|
||||||
|
{
|
||||||
|
SpecialCharacters.AddRange(nextLine.SpecialCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var number in Numbers)
|
||||||
|
{
|
||||||
|
foreach (var (key, value) in number)
|
||||||
|
{
|
||||||
|
var beforeNumber = value.Start - 1;
|
||||||
|
var afterNumber = value.End + 1;
|
||||||
|
|
||||||
|
if (SpecialCharacterIndexes.Any(idx => idx >= beforeNumber && idx <= afterNumber))
|
||||||
|
{
|
||||||
|
partNumbers.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return partNumbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Line Parse(string line)
|
||||||
|
{
|
||||||
|
var numbers = new List<Dictionary<int, Indexes>>();
|
||||||
|
var specialCharacters = new List<Dictionary<string, Indexes>>();
|
||||||
|
|
||||||
|
var number = string.Empty;
|
||||||
|
int? numberStart = null;
|
||||||
|
int? numberEnd;
|
||||||
|
|
||||||
|
for (var i = 0; i < line.Length; i++)
|
||||||
|
{
|
||||||
|
var currentCharacter = line[i];
|
||||||
|
|
||||||
|
if (char.IsDigit(currentCharacter))
|
||||||
|
{
|
||||||
|
number += line[i];
|
||||||
|
numberStart ??= i;
|
||||||
|
|
||||||
|
if (i == line.Length - 1)
|
||||||
|
{
|
||||||
|
numberEnd = i;
|
||||||
|
numbers.Add(new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
int.Parse(number),
|
||||||
|
new Indexes(numberStart.Value, numberEnd.Value)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (numberStart.HasValue)
|
||||||
|
{
|
||||||
|
numberEnd = i - 1;
|
||||||
|
numbers.Add(new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
int.Parse(number),
|
||||||
|
new Indexes(numberStart.Value, numberEnd.Value)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
number = string.Empty;
|
||||||
|
numberStart = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCharacter == '.')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
specialCharacters.Add(new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
currentCharacter.ToString(),
|
||||||
|
new Indexes(i, i)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Line(numbers, specialCharacters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Indexes(int start, int end)
|
||||||
|
{
|
||||||
|
public int Start { get; init; } = start;
|
||||||
|
public int End { get; init; } = end;
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# Notes
|
||||||
|
|
||||||
|
## Contraints
|
||||||
|
|
||||||
|
- Periods don't count as special characters
|
||||||
|
- All lines have same length
|
||||||
|
- If not a number or period then it is a special character
|
||||||
|
|
||||||
|
Each line parsed need to collect all numbers.
|
||||||
|
|
||||||
|
Can't know whether a collected number is a part number until we
|
||||||
|
have also parsed the proceeding or following line.
|
||||||
|
|
||||||
|
```text
|
||||||
|
467..114..
|
||||||
|
...*......
|
||||||
|
..35..633.
|
||||||
|
......#...
|
||||||
|
617*......
|
||||||
|
```
|
||||||
|
|
||||||
|
After parsing first line we would have `467` with start index 0 and end index 2 and `114` with start index 5 and end index 7.
|
||||||
|
|
||||||
|
For 467 to be a part number it needs to have a special character at index 3 or it needs to have a special character at index 1, 2, 3, 4 on the next line.
|
||||||
|
|
||||||
|
For 114 to be a part number it needs to have a special character at index 4 or index 8 or it needs to have a special character at index 4, 5, 6, 7 on the next line.
|
||||||
|
|
||||||
|
Need to keep track of:
|
||||||
|
|
||||||
|
- Previous line - will start as empty
|
||||||
|
- Current line
|
||||||
|
- Next line
|
||||||
|
|
||||||
|
So you look at the current line and you parse all the numbers with their start and end index. You also parse all special characters with their index.
|
||||||
|
|
||||||
|
Then you end up with something like this: currentLine
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"numbers": [
|
||||||
|
"467": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 2
|
||||||
|
},
|
||||||
|
"114": {
|
||||||
|
"start": 5,
|
||||||
|
"end": 7
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"specialCharacters": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var currentLineString = "467..114..";
|
||||||
|
var currentLine = new Line(currentLineString);
|
||||||
|
|
||||||
|
class Line
|
||||||
|
{
|
||||||
|
public List<Dictionary<int, Indexes>> Numbers { get; set; }
|
||||||
|
public List<Dictionary<int, Indexes>> SpecialCharacters { get; set; }
|
||||||
|
|
||||||
|
public Line(string line)
|
||||||
|
{
|
||||||
|
// parse line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Indexes
|
||||||
|
{
|
||||||
|
public int Start { get; set; }
|
||||||
|
public int End { get; set; }
|
||||||
|
|
||||||
|
public Indexes(int start, int length)
|
||||||
|
{
|
||||||
|
Start = start;
|
||||||
|
End = start + length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you see if those numbers are part numbers just by checking if a special character proceeds or follows their start and end indexes.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
```
|
||||||
|
|
||||||
|
If not then you need to see if there is a previous line and whether there is a special character at on the previous line that has an index that is between 1 less than the start index and 1 more than the end index.
|
||||||
|
|
||||||
|
If not then you need to see if there is a next line and whether there is a special character at on the next line that has an index that is between 1 less than the start index and 1 more than the end index.
|
||||||
|
```
|
||||||
@@ -19,7 +19,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03", "03", "{EA04152D-316A-
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GearRatios", "03\GearRatios\GearRatios.csproj", "{F697AC19-C92D-4E2A-975A-1A16A1961133}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GearRatios", "03\GearRatios\GearRatios.csproj", "{F697AC19-C92D-4E2A-975A-1A16A1961133}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GearRatios.Test", "03\GearRatios.Test\GearRatios.Test.csproj", "{FEE9253C-A56B-4735-BDB3-C62220C5B1B1}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GearRatios.Tests", "03\GearRatios.Tests\GearRatios.Tests.csproj", "{FEE9253C-A56B-4735-BDB3-C62220C5B1B1}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|||||||
Reference in New Issue
Block a user