196 lines
6.3 KiB
C#
196 lines
6.3 KiB
C#
|
|
var lines = File.ReadAllLines("input.txt");
|
|||
|
|
var charArray = new char[lines.Length, lines[0].Length];
|
|||
|
|
|
|||
|
|
for (var i = 0; i < charArray.GetLength(0); i++)
|
|||
|
|
for (var j = 0; j < charArray.GetLength(1); j++)
|
|||
|
|
{
|
|||
|
|
charArray[i, j] = lines[i][j];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var uniqueCharacterPositions = GroupUniqueCharacterPositions(charArray);
|
|||
|
|
|
|||
|
|
var antinodeLocations = new List<(int, int)>();
|
|||
|
|
var antinodeHarmonicsLocations = new List<(int, int)>();
|
|||
|
|
|
|||
|
|
foreach (var uniqueCharacter in uniqueCharacterPositions)
|
|||
|
|
{
|
|||
|
|
for (var i = 0; i < uniqueCharacter.Value.Count - 1; i++)
|
|||
|
|
{
|
|||
|
|
var currentPosition = uniqueCharacter.Value[i];
|
|||
|
|
|
|||
|
|
for (var j = i + 1; j < uniqueCharacter.Value.Count; j++)
|
|||
|
|
{
|
|||
|
|
var nextPosition = uniqueCharacter.Value[j];
|
|||
|
|
|
|||
|
|
if (Distance(currentPosition.Item1, currentPosition.Item2, nextPosition.Item1, nextPosition.Item2) >= 1)
|
|||
|
|
{
|
|||
|
|
antinodeLocations.AddRange(CalculateAntinodes(currentPosition, nextPosition, charArray));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
antinodeHarmonicsLocations.AddRange(CalculateAntinodesWithHarmonics(currentPosition, nextPosition, charArray));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Console.WriteLine(
|
|||
|
|
$"Part 1: {antinodeLocations.Distinct().Count()}\nPart 2: {antinodeHarmonicsLocations.Distinct().Count()}");
|
|||
|
|
|
|||
|
|
List<(int, int)> CalculateAntinodesWithHarmonics((int, int) currentPosition, (int, int) nextPosition, char[,] input)
|
|||
|
|
{
|
|||
|
|
var locations = new List<(int, int)>
|
|||
|
|
{
|
|||
|
|
currentPosition,
|
|||
|
|
nextPosition
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
var verticalDistance = Math.Abs(currentPosition.Item1 - nextPosition.Item1);
|
|||
|
|
var horizontalDistance = Math.Abs(currentPosition.Item2 - nextPosition.Item2);
|
|||
|
|
|
|||
|
|
var currentPositionClone = currentPosition;
|
|||
|
|
var nextPositionClone = nextPosition;
|
|||
|
|
int antinodePositionRow, antinodePositionColumn;
|
|||
|
|
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
if (currentPositionClone.Item1 < nextPositionClone.Item1)
|
|||
|
|
{
|
|||
|
|
antinodePositionRow = currentPositionClone.Item1 - verticalDistance;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
antinodePositionRow = currentPositionClone.Item1 + verticalDistance;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (currentPositionClone.Item2 < nextPositionClone.Item2)
|
|||
|
|
{
|
|||
|
|
antinodePositionColumn = currentPositionClone.Item2 - horizontalDistance;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
antinodePositionColumn = currentPositionClone.Item2 + horizontalDistance;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (IsValid(antinodePositionRow, antinodePositionColumn, input))
|
|||
|
|
{
|
|||
|
|
locations.Add((antinodePositionRow, antinodePositionColumn));
|
|||
|
|
nextPositionClone = currentPositionClone;
|
|||
|
|
currentPositionClone = (antinodePositionRow, antinodePositionColumn);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
currentPositionClone = currentPosition;
|
|||
|
|
nextPositionClone = nextPosition;
|
|||
|
|
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
if (currentPositionClone.Item1 < nextPositionClone.Item1)
|
|||
|
|
{
|
|||
|
|
antinodePositionRow = nextPositionClone.Item1 + verticalDistance;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
antinodePositionRow = nextPositionClone.Item1 - verticalDistance;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (currentPositionClone.Item2 < nextPositionClone.Item2)
|
|||
|
|
{
|
|||
|
|
antinodePositionColumn = nextPositionClone.Item2 + horizontalDistance;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
antinodePositionColumn = nextPositionClone.Item2 - horizontalDistance;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (IsValid(antinodePositionRow, antinodePositionColumn, input))
|
|||
|
|
{
|
|||
|
|
locations.Add((antinodePositionRow, antinodePositionColumn));
|
|||
|
|
currentPositionClone = nextPositionClone;
|
|||
|
|
nextPositionClone = (antinodePositionRow, antinodePositionColumn);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return locations;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
List<(int, int)> CalculateAntinodes((int, int) currentPosition, (int, int) nextPosition, char[,] input)
|
|||
|
|
{
|
|||
|
|
var locations = new List<(int, int)>();
|
|||
|
|
|
|||
|
|
int firstAntinodePositionRow,
|
|||
|
|
firstAntinodePositionColumn,
|
|||
|
|
secondAntinodePositionRow,
|
|||
|
|
secondAntinodePositionColumn;
|
|||
|
|
|
|||
|
|
var verticalDistance = Math.Abs(currentPosition.Item1 - nextPosition.Item1);
|
|||
|
|
var horizontalDistance = Math.Abs(currentPosition.Item2 - nextPosition.Item2);
|
|||
|
|
|
|||
|
|
if (currentPosition.Item1 < nextPosition.Item1)
|
|||
|
|
{
|
|||
|
|
firstAntinodePositionRow = currentPosition.Item1 - verticalDistance;
|
|||
|
|
secondAntinodePositionRow = nextPosition.Item1 + verticalDistance;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
firstAntinodePositionRow = currentPosition.Item1 + verticalDistance;
|
|||
|
|
secondAntinodePositionRow = nextPosition.Item1 - verticalDistance;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (currentPosition.Item2 < nextPosition.Item2)
|
|||
|
|
{
|
|||
|
|
firstAntinodePositionColumn = currentPosition.Item2 - horizontalDistance;
|
|||
|
|
secondAntinodePositionColumn = nextPosition.Item2 + horizontalDistance;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
firstAntinodePositionColumn = currentPosition.Item2 + horizontalDistance;
|
|||
|
|
secondAntinodePositionColumn = nextPosition.Item2 - horizontalDistance;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (IsValid(firstAntinodePositionRow, firstAntinodePositionColumn, input))
|
|||
|
|
{
|
|||
|
|
locations.Add((firstAntinodePositionRow, firstAntinodePositionColumn));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (IsValid(secondAntinodePositionRow, secondAntinodePositionColumn, input))
|
|||
|
|
{
|
|||
|
|
locations.Add((secondAntinodePositionRow, secondAntinodePositionColumn));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return locations;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Dictionary<char, List<(int, int)>> GroupUniqueCharacterPositions(char[,] array)
|
|||
|
|
{
|
|||
|
|
var charLocations = new Dictionary<char, List<(int, int)>>();
|
|||
|
|
|
|||
|
|
for (var i = 0; i < array.GetLength(0); i++)
|
|||
|
|
{
|
|||
|
|
for (var j = 0; j < array.GetLength(1); j++)
|
|||
|
|
{
|
|||
|
|
var currentChar = array[i, j];
|
|||
|
|
|
|||
|
|
if (currentChar == '.') continue;
|
|||
|
|
|
|||
|
|
if (!charLocations.ContainsKey(currentChar))
|
|||
|
|
{
|
|||
|
|
charLocations[currentChar] = new List<(int, int)>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
charLocations[currentChar].Add((i, j));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return charLocations;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool IsValid(int row, int column, char[,] grid) => row >= 0 && row < grid.GetLength(0) && column >= 0 && column < grid.GetLength(1);
|
|||
|
|
|
|||
|
|
double Distance(int position1Row, int position1Column, int position2Row, int position2Column) => Math.Sqrt(Math.Pow(position1Column - position2Column, 2) + Math.Pow(position2Row - position1Row, 2));
|