partial day 14 p2, added empty day 15
This commit is contained in:
parent
eb599df171
commit
a91dd1c661
@ -4,7 +4,7 @@ using AdventOfCode.Core;
|
||||
|
||||
InputReader inputReader = new()
|
||||
{
|
||||
//IsDebug = true
|
||||
IsDebug = true
|
||||
};
|
||||
|
||||
//inputReader.SetInputByChallange(3);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using AdventOfCode.Core.Shared;
|
||||
using AdventOfCode.Core.Shared.Grid;
|
||||
|
||||
namespace AdventOfCode.Core
|
||||
{
|
||||
@ -84,14 +85,14 @@ namespace AdventOfCode.Core
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Grid<T>> ReadToGrid<T>() where T : Node, new()
|
||||
public async Task<Grid<T>> ReadToGrid<T>() where T : Point, new()
|
||||
{
|
||||
Grid<T> result = new();
|
||||
int row = 0;
|
||||
await foreach(string line in ReadAsStringLine())
|
||||
{
|
||||
// create the nodes from the lines
|
||||
result.DataGrid.AddRange(line.Select((c, i) => new T { X = i, Y = row, Char = c }));
|
||||
result.DataGrid.AddRange(line.Select((c, i) => new T { X = i, Y = row, Value = c }));
|
||||
row++;
|
||||
}
|
||||
|
||||
@ -113,7 +114,7 @@ namespace AdventOfCode.Core
|
||||
continue;
|
||||
}
|
||||
// create the nodes from the lines
|
||||
result.DataGrid.AddRange(line.Select((c, i) => new T { X = i, Y = row, Char = c }));
|
||||
result.DataGrid.AddRange(line.Select((c, i) => new T { X = i, Y = row, Value = c }));
|
||||
row++;
|
||||
}
|
||||
yield return result;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
}
|
||||
|
||||
var neighbors = GetNeighbors(current, false);
|
||||
neighbors = neighbors.Where(n => current.CanMoveTo(n));
|
||||
neighbors = neighbors.Where(n => current.CanMoveTo(current));
|
||||
|
||||
// calc costs
|
||||
foreach(AStarNode neighbor in neighbors)
|
||||
|
||||
@ -1,27 +1,29 @@
|
||||
namespace AdventOfCode.Core.Shared.A_Star
|
||||
using AdventOfCode.Core.Shared.Grid;
|
||||
|
||||
namespace AdventOfCode.Core.Shared.A_Star
|
||||
{
|
||||
public class AStarNode : Node
|
||||
public class AStarNode : Point
|
||||
{
|
||||
/// <summary>
|
||||
/// Distance from start node
|
||||
/// </summary>
|
||||
public int GCost { get; set; } = 0;
|
||||
public long GCost { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Distance from end node
|
||||
/// </summary>
|
||||
public int HCost { get; set; }
|
||||
public long HCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total cost (G + F)
|
||||
/// </summary>
|
||||
public int FCost => GCost + HCost;
|
||||
public long FCost => GCost + HCost;
|
||||
|
||||
public bool? IsClosed { get; private set; } = null;
|
||||
|
||||
public AStarNode? ParentNode { get; set; }
|
||||
|
||||
public AStarNode(Node position) : base(position)
|
||||
public AStarNode(Point position) : base(position)
|
||||
{ }
|
||||
|
||||
public AStarNode(int x, int y, char value) : base(x, y, value)
|
||||
@ -33,8 +35,10 @@
|
||||
|
||||
public bool CanMoveTo(AStarNode target)
|
||||
{
|
||||
int diff = target.Integer - Integer; ;
|
||||
return diff == 0 || diff == 1;
|
||||
return false;
|
||||
// TODO FIX
|
||||
//int diff = target.Integer - Integer;
|
||||
//return diff == 0 || diff == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
namespace AdventOfCode.Core.Shared
|
||||
using AdventOfCode.Core.Shared.Grid;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AdventOfCode.Core.Shared
|
||||
{
|
||||
public class Grid<T> where T : Node
|
||||
public class Grid<T> where T : Point
|
||||
{
|
||||
public List<T> DataGrid { get; set; } = [];
|
||||
|
||||
public int Columns => DataGrid.Max(n => n.X) + 1;
|
||||
public int Rows => DataGrid.Max(n => n.Y) + 1;
|
||||
public long Columns => DataGrid.Max(n => n.X) + 1;
|
||||
public long Rows => DataGrid.Max(n => n.Y) + 1;
|
||||
|
||||
public Grid() { }
|
||||
|
||||
@ -13,12 +16,12 @@
|
||||
|
||||
public Grid(IEnumerable<T> data) : this(data.ToArray()) { }
|
||||
|
||||
public IEnumerable<T> GetRow(int rowNumber) => DataGrid.Where(n => n.X == rowNumber);
|
||||
public string GetRowAsString(int columnNumber) => string.Concat(DataGrid.Where(n => n.Y == columnNumber).OrderBy(n => n.X).Select(n => n.Char));
|
||||
public IEnumerable<T> GetColumn(int columnNumber) => DataGrid.Where(n => n.Y == columnNumber);
|
||||
public string GetColumnAsString(int rowNumber) => string.Concat(DataGrid.Where(n => n.X == rowNumber).OrderBy(n => n.Y).Select(n => n.Char));
|
||||
public T GetNode(int x, int y) => DataGrid.First(n => n.X == x && n.Y == y);
|
||||
public IEnumerable<T> FindWithValue(char toFind) => DataGrid.Where(n => n.Char == toFind);
|
||||
public IEnumerable<T> GetRow(long rowNumber) => DataGrid.Where(n => n.X == rowNumber);
|
||||
public string GetRowAsString(long columnNumber) => string.Concat(DataGrid.Where(n => n.Y == columnNumber).OrderBy(n => n.X).Select(n => n.Value));
|
||||
public IEnumerable<T> GetColumn(long columnNumber) => DataGrid.Where(n => n.Y == columnNumber);
|
||||
public string GetColumnAsString(long rowNumber) => string.Concat(DataGrid.Where(n => n.X == rowNumber).OrderBy(n => n.Y).Select(n => n.Value));
|
||||
public T GetNode(long x, long y) => DataGrid.First(n => n.X == x && n.Y == y);
|
||||
public IEnumerable<T> FindWithValue(char toFind) => DataGrid.Where(n => n.Value == toFind);
|
||||
|
||||
public void UpdateNode(T node)
|
||||
{
|
||||
@ -40,7 +43,7 @@
|
||||
|| (source.X == target.X && Math.Abs(source.Y - target.Y) <= 1));
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetSection(int fromX, int fromY, int toX, int toY)
|
||||
public IEnumerable<T> GetSection(long fromX, long fromY, long toX, long toY)
|
||||
{
|
||||
return DataGrid.Where(node => node.X >= fromX && node.X <= toX && node.Y >= fromY && node.Y <= toY);
|
||||
}
|
||||
|
||||
@ -1,15 +1,22 @@
|
||||
using static System.Collections.Specialized.BitVector32;
|
||||
|
||||
namespace AdventOfCode.Core.Shared.Grid
|
||||
namespace AdventOfCode.Core.Shared.Grid
|
||||
{
|
||||
public class Point(long X, long Y)
|
||||
public class Point(long X, long Y) : IEquatable<Point>
|
||||
{
|
||||
public long X { get; set; } = X;
|
||||
public long Y { get; set; } = Y;
|
||||
|
||||
public string Value { get; set; } = string.Empty;
|
||||
public char Value { get; set; } = ' ';
|
||||
|
||||
public Point(long X, long Y, string value) : this(X, Y) => Value = value;
|
||||
public Point() : this(-1, -1) { }
|
||||
|
||||
public Point(Point point) : this(point.X, point.Y) { }
|
||||
|
||||
public Point(long X, long Y, char value) : this(X, Y) => Value = value;
|
||||
|
||||
public long DistanceTo(Point other)
|
||||
{
|
||||
return Math.Abs(X - other.X) + Math.Abs(Y - other.Y);
|
||||
}
|
||||
|
||||
public bool Intersect(Point other)
|
||||
{
|
||||
@ -22,5 +29,23 @@ namespace AdventOfCode.Core.Shared.Grid
|
||||
{
|
||||
return $"[{Y},{X}] {Value}";
|
||||
}
|
||||
|
||||
public bool Equals(Point? other)
|
||||
{
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
if (this.X != other.X
|
||||
|| this.Y != other.Y
|
||||
|| this.Value != other.Value)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.X.GetHashCode() ^ this.Y.GetHashCode() ^ this.Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +1,15 @@
|
||||
namespace AdventOfCode.Core.Shared
|
||||
using AdventOfCode.Core.Shared.Grid;
|
||||
|
||||
namespace AdventOfCode.Core.Shared
|
||||
{
|
||||
public class Node
|
||||
public class Node(long X, long Y, char value) : Point(X, Y, value)
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public char Char { get; set; }
|
||||
public short Integer => (short)Char;
|
||||
|
||||
public Node() { }
|
||||
|
||||
public Node(int x, int y, char character)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Char = character;
|
||||
}
|
||||
|
||||
public Node(Node position) : this(position.X, position.Y, position.Char)
|
||||
{ }
|
||||
|
||||
public int DistanceTo(Node other)
|
||||
{
|
||||
return Math.Abs(X - other.X) + Math.Abs(Y - other.Y);
|
||||
}
|
||||
public Node() : this(-1, -1, '0') { }
|
||||
public Node(long X, long Y) : this(X, Y, ' ') { }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{Y},{X}] {Char}";
|
||||
return $"[{Y},{X}] {Value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ namespace AdventOfCode.Solutions._2023
|
||||
{
|
||||
var (Numbers, Symbols) = await GetNumbersAndSymbols();
|
||||
return Symbols
|
||||
.Where(s => s.Value == "*")
|
||||
.Where(s => s.Value == '*')
|
||||
.Select(g => Numbers.Where(n => n.Intersect(g)))
|
||||
.Where(n => n.Count() == 2)
|
||||
.Select(num => int.Parse(num.First().Value) * int.Parse(num.Last().Value))
|
||||
@ -57,7 +57,7 @@ namespace AdventOfCode.Solutions._2023
|
||||
}
|
||||
|
||||
List<Rectangle> numbers = parts.Where(p => p.IsDigit()).Select(number => new Rectangle(new Point(number.X - 1, number.Y - 1), new Point(number.X + number.Length, number.Y + 1), number.Section)).ToList();
|
||||
List<Point> symbols = parts.Where(p => p.IsPartSymbol()).Select(symbol => new Point(symbol.X, symbol.Y, symbol.Section)).ToList();
|
||||
List<Point> symbols = parts.Where(p => p.IsPartSymbol()).Select(symbol => new Point(symbol.X, symbol.Y, symbol.Section[0])).ToList();
|
||||
|
||||
return (numbers, symbols);
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ namespace AdventOfCode.Solutions._2023
|
||||
|
||||
if (lastId < currentSeedRange.End.X)
|
||||
{
|
||||
Line map = new(new Point(lastId, 0, ""), currentSeedRange.End);
|
||||
Line map = new(new Point(lastId, 0, ' '), currentSeedRange.End);
|
||||
resultRanges.Add(map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using AdventOfCode.Core;
|
||||
using AdventOfCode.Core.Shared.Grid;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace AdventOfCode.Solutions._2023
|
||||
@ -31,17 +32,17 @@ namespace AdventOfCode.Solutions._2023
|
||||
|
||||
if (value.Steps >= 0) // this is in the main loop
|
||||
{
|
||||
if (value.Char == '-') // never crosses, also to not update prev
|
||||
if (value.Value == '-') // never crosses, also to not update prev
|
||||
continue;
|
||||
|
||||
if ((prevSegment == 'L' && value.Char == '7') // this is L7 meaning that there is no crossing
|
||||
|| prevSegment == 'F' && value.Char == 'J') // this is FJ meaning that there is no crossing
|
||||
if ((prevSegment == 'L' && value.Value == '7') // this is L7 meaning that there is no crossing
|
||||
|| prevSegment == 'F' && value.Value == 'J') // this is FJ meaning that there is no crossing
|
||||
{
|
||||
prevSegment = value.Char;
|
||||
prevSegment = value.Value;
|
||||
continue;
|
||||
}
|
||||
|
||||
prevSegment = value.Char;
|
||||
prevSegment = value.Value;
|
||||
pipesCrossed++;
|
||||
continue;
|
||||
}
|
||||
@ -60,7 +61,7 @@ namespace AdventOfCode.Solutions._2023
|
||||
startPipe.Steps = 0;
|
||||
|
||||
Pipe[] lineToWalk = grid.GetNeighbors(startPipe, false)
|
||||
.Where(n => n.Char != '.')
|
||||
.Where(n => n.Value != '.')
|
||||
.Where(n => n.GetNeighbors().Any(np => np.X == startPipe.X && np.Y == startPipe.Y))
|
||||
.ToArray();
|
||||
|
||||
@ -99,9 +100,9 @@ namespace AdventOfCode.Solutions._2023
|
||||
}
|
||||
}
|
||||
|
||||
public class Pipe : Node
|
||||
public class Pipe : Point
|
||||
{
|
||||
public Pipe From { get; set; }
|
||||
public Pipe From { get; set; } = null;
|
||||
|
||||
public int Steps { get; set; } = -1;
|
||||
|
||||
@ -115,7 +116,7 @@ namespace AdventOfCode.Solutions._2023
|
||||
|
||||
public IEnumerable<Pipe> GetNeighbors()
|
||||
{
|
||||
switch (Char)
|
||||
switch (Value)
|
||||
{
|
||||
case '|':
|
||||
yield return GetNorth();
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
using AdventOfCode.Core;
|
||||
using AdventOfCode.Core.Shared.Grid;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks.Dataflow;
|
||||
|
||||
namespace AdventOfCode.Solutions._2023
|
||||
{
|
||||
@ -8,38 +13,154 @@ namespace AdventOfCode.Solutions._2023
|
||||
|
||||
public async Task<string> GetSolutionPart1()
|
||||
{
|
||||
string[] lines = await _inputReader.ReadAsVerticalArrayString();
|
||||
int totalWeight = 0;
|
||||
for(int lineIndex = 0; lineIndex < lines.Length; lineIndex++)
|
||||
{
|
||||
int weight = lines[lineIndex].Length, lineWeight = 0;
|
||||
for (int charIndex = 0; charIndex < lines[lineIndex].Length; charIndex++)
|
||||
{
|
||||
if (lines[lineIndex][charIndex] is '.')
|
||||
continue;
|
||||
Grid<Point> grid = await _inputReader.ReadToGrid<Point>();
|
||||
HashSet<Point> bolders = grid.FindWithValue('O').Select(p => new Point(p.X, p.Y)).ToHashSet();
|
||||
HashSet<Point> cubes = grid.FindWithValue('#').Select(p => new Point(p.X, p.Y)).ToHashSet();
|
||||
|
||||
if (lines[lineIndex][charIndex] is '#')
|
||||
{
|
||||
weight = lines[lineIndex].Length - charIndex - 1;
|
||||
continue;
|
||||
}
|
||||
bolders = MoveUp(bolders, cubes);
|
||||
|
||||
if (lines[lineIndex][charIndex] is 'O')
|
||||
{
|
||||
lineWeight += weight;
|
||||
weight--;
|
||||
}
|
||||
}
|
||||
|
||||
totalWeight += lineWeight;
|
||||
}
|
||||
|
||||
return totalWeight.ToString();
|
||||
return bolders.Sum(bolder => grid.Rows - bolder.Y).ToString();
|
||||
}
|
||||
|
||||
public async Task<string> GetSolutionPart2()
|
||||
{
|
||||
return string.Empty;
|
||||
long maxCycles = 1_000_000_000;
|
||||
Dictionary<string, int> mapStates = [];
|
||||
bool foundLoop = false;
|
||||
|
||||
Grid<Point> grid = await _inputReader.ReadToGrid<Point>();
|
||||
HashSet<Point> bolders = grid.FindWithValue('O').Select(p => new Point(p.X, p.Y)).ToHashSet();
|
||||
HashSet<Point> cubes = grid.FindWithValue('#').Select(p => new Point(p.X, p.Y)).ToHashSet();
|
||||
|
||||
for (int currentCycle = 0; currentCycle < maxCycles; currentCycle++)
|
||||
{
|
||||
mapStates.TryAdd(CreateStringMap(bolders, cubes, grid.Rows, grid.Columns), currentCycle);
|
||||
|
||||
bolders = MoveUp(bolders, cubes);
|
||||
bolders = MoveLeft(bolders, cubes);
|
||||
bolders = MoveDown(bolders, cubes, grid.Rows);
|
||||
bolders = MoveRight(bolders, cubes, grid.Columns);
|
||||
|
||||
if (foundLoop) continue;
|
||||
|
||||
int hash = bolders.GetHashCode();
|
||||
if (mapStates.TryGetValue(CreateStringMap(bolders, cubes, grid.Rows, grid.Columns), out int prevCycle))
|
||||
{
|
||||
// calculate remaining cycles to the first exit point
|
||||
long remainingCycles = (maxCycles - prevCycle) % (currentCycle + 1 - prevCycle) + 1;
|
||||
// set the total the first exit point
|
||||
maxCycles = remainingCycles + currentCycle;
|
||||
foundLoop = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return bolders.Sum(bolder => grid.Rows - bolder.Y).ToString();
|
||||
}
|
||||
|
||||
private HashSet<Point> MoveUp(HashSet<Point> bolders, HashSet<Point> cubes)
|
||||
{
|
||||
HashSet<Point> boldersMoved = [];
|
||||
foreach (Point bolder in bolders.OrderBy(bolder => bolder.Y) )
|
||||
{
|
||||
// current location
|
||||
long ySearch = bolder.Y;
|
||||
while (ySearch - 1 >= 0 // ensure in map
|
||||
&& !boldersMoved.Contains(new(bolder.X, ySearch - 1)) // check that the next tile does not have a bolder
|
||||
&& !cubes.Contains(new(bolder.X, ySearch - 1))) // check that the next tile has not cube
|
||||
{
|
||||
ySearch--; // move to next
|
||||
}
|
||||
|
||||
// something found on next location so place bolder here
|
||||
boldersMoved.Add(new(bolder.X, ySearch));
|
||||
}
|
||||
|
||||
return boldersMoved;
|
||||
}
|
||||
|
||||
private HashSet<Point> MoveDown(HashSet<Point> bolders, HashSet<Point> cubes, long ySize)
|
||||
{
|
||||
HashSet<Point> boldersMoved = [];
|
||||
foreach (Point bolder in bolders.OrderBy(bolder => bolder.Y))
|
||||
{
|
||||
// current location
|
||||
long ySearch = bolder.Y;
|
||||
while (ySearch + 1 < ySize // ensure in map
|
||||
&& !boldersMoved.Contains(new(bolder.X, ySearch + 1)) // check that the next tile does not have a bolder
|
||||
&& !cubes.Contains(new(bolder.X, ySearch + 1))) // check that the next tile has not cube
|
||||
{
|
||||
ySearch++; // move to next
|
||||
}
|
||||
|
||||
// something found on next location so place bolder here
|
||||
boldersMoved.Add(new(bolder.X, ySearch));
|
||||
}
|
||||
|
||||
return boldersMoved;
|
||||
}
|
||||
|
||||
private HashSet<Point> MoveLeft(HashSet<Point> bolders, HashSet<Point> cubes)
|
||||
{
|
||||
HashSet<Point> boldersMoved = [];
|
||||
foreach (Point bolder in bolders.OrderBy(bolder => bolder.X))
|
||||
{
|
||||
// current location
|
||||
long xSearch = bolder.X;
|
||||
while (xSearch - 1 >= 0 // ensure in map
|
||||
&& !boldersMoved.Contains(new(xSearch, bolder.Y)) // check that the next tile does not have a bolder
|
||||
&& !cubes.Contains(new(xSearch, bolder.Y))) // check that the next tile has not cube
|
||||
{
|
||||
xSearch--; // move to next
|
||||
}
|
||||
|
||||
// something found on next location so place bolder here
|
||||
boldersMoved.Add(new(xSearch, bolder.Y));
|
||||
}
|
||||
|
||||
return boldersMoved;
|
||||
}
|
||||
|
||||
private HashSet<Point> MoveRight(HashSet<Point> bolders, HashSet<Point> cubes, long xSize)
|
||||
{
|
||||
HashSet<Point> boldersMoved = [];
|
||||
foreach (Point bolder in bolders.OrderBy(bolder => bolder.Y))
|
||||
{
|
||||
// current location
|
||||
long xSearch = bolder.Y;
|
||||
while (xSearch + 1 < xSize // ensure in map
|
||||
&& !boldersMoved.Contains(new(xSearch, bolder.Y)) // check that the next tile does not have a bolder
|
||||
&& !cubes.Contains(new(xSearch, bolder.Y))) // check that the next tile has not cube
|
||||
{
|
||||
xSearch++; // move to next
|
||||
}
|
||||
|
||||
// something found on next location so place bolder here
|
||||
boldersMoved.Add(new(xSearch, bolder.Y));
|
||||
}
|
||||
|
||||
return boldersMoved;
|
||||
}
|
||||
|
||||
private static string CreateStringMap(HashSet<Point> bolders, HashSet<Point> cubess, long maxX, long maxY)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
for (var y = 0; y < maxY; y++)
|
||||
{
|
||||
for (var x = 0; x < maxX; x++)
|
||||
{
|
||||
if (bolders.Contains(new Point(x, y)))
|
||||
stringBuilder.Append('O');
|
||||
else if (cubess.Contains(new Point(x, y)))
|
||||
stringBuilder.Append('#');
|
||||
else
|
||||
stringBuilder.Append('.');
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine();
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
19
AdventOfCode.Solutions/2023/Day 15/Day15.cs
Normal file
19
AdventOfCode.Solutions/2023/Day 15/Day15.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using AdventOfCode.Core;
|
||||
|
||||
namespace AdventOfCode.Solutions._2023
|
||||
{
|
||||
public class Day15(InputReader reader) : IChallange
|
||||
{
|
||||
private InputReader _inputReader = reader;
|
||||
|
||||
public async Task<string> GetSolutionPart1()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public async Task<string> GetSolutionPart2()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
0
AdventOfCode.Solutions/2023/Day 15/day-15-input.txt
Normal file
0
AdventOfCode.Solutions/2023/Day 15/day-15-input.txt
Normal file
Loading…
Reference in New Issue
Block a user