Skip to content

Commit

Permalink
2023 Day23 Rewritten
Browse files Browse the repository at this point in the history
  • Loading branch information
smabuk committed Dec 23, 2023
1 parent 20f8c96 commit 9919cb8
Showing 1 changed file with 101 additions and 80 deletions.
181 changes: 101 additions & 80 deletions Solutions/2023/Day23.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using static AdventOfCode.Solutions._2023.Day23;

using Map = char[,];

namespace AdventOfCode.Solutions._2023;

/// <summary>
Expand All @@ -12,26 +10,26 @@ namespace AdventOfCode.Solutions._2023;
public sealed partial class Day23 {

[Init]
public static void Init(string[] input, params object[]? args) => LoadHikingTrails(input);
public static void Init(string[] input, params object[]? args) => LoadMap(input);
public static string Part1(string[] input, params object[]? args) => Solution1().ToString();
public static string Part2(string[] input, params object[]? args) => Solution2().ToString();

public const char PATH = '.';
public const char FOREST = '#';
public const char SLOPE_RIGHT = '>';
public const char SLOPE_LEFT = '<';
public const char SLOPE_UP = '^';
public const char SLOPE_DOWN = 'v';
public static readonly char[] SLOPES = [SLOPE_RIGHT, SLOPE_LEFT, SLOPE_UP, SLOPE_DOWN];
public const char PATH = '.';
public const char FOREST = '#';
public const char SLOPE_RIGHT = '>';
public const char SLOPE_LEFT = '<';
public const char SLOPE_UP = '^';
public const char SLOPE_DOWN = 'v';
public static readonly char[] SLOPES = [SLOPE_RIGHT, SLOPE_LEFT, SLOPE_UP, SLOPE_DOWN];

private static Map _map = default!;
private static Point _start;
private static Point _end;
public static char[,] _map = default!;
public static Point _start;
public static Point _end;

private static void LoadHikingTrails(string[] input) {
_map = input.To2dArray();
private static void LoadMap(string[] input) {
_map = input.To2dArray();
_start = new(_map.RowAsString(0).IndexOf(PATH), 0);
_end = new(_map.RowAsString(_map.YMax()).IndexOf(PATH), _map.YMax());
_end = new(_map.RowAsString(_map.YMax()).IndexOf(PATH), _map.YMax());
}

private static int Solution1() {
Expand All @@ -40,101 +38,124 @@ private static int Solution1() {
.Max();
}

private static string Solution2() {
if (_map.RowAsString(0) == "#.###########################################################################################################################################") {
// my input
return "6302 (too slow)";
}

return _map
.FindAllPathLengths2(_start, _end)
.Max()
.ToString();
private static int Solution2()
{
return
_map
.CondenseMap([_start, _end])
.BuildGraph()
.FindMaxSteps_DepthFirstSearch(_start, []);
}

}

file static class Day23Helpers
{
public static List<int> FindAllPathLengths(this Map map, Point current, Point end, List<Point> isVisited)
public static List<Point> CondenseMap(this char[,] map, List<Point> initialPoints)
{
if (current == end) {
return [isVisited.Count];
}
List<Point> points = [.. initialPoints];

List<int> pathLengths = [];
for (int y = 0; y < map.RowsCount(); y++) {
for (int x = 0; x < map.ColsCount(); x++) {
Point current = new(x, y);
if (map[current.X, current.Y] == FOREST) {
continue;
}

foreach (Point next in map.GetNeighbours(current)) {
if (isVisited.Contains(next) is false) {
pathLengths.AddRange(FindAllPathLengths(map, next, end, [.. isVisited, next]));
if (map.GetAdjacentCells(current).Where(adj => adj.Value != FOREST).Count() >= 3) {
points.Add(current);
}
}
}

return pathLengths;
return points;
}

public static List<int> FindAllPathLengths2(this Map map, Point start, Point end)
public static Dictionary<Point, Dictionary<Point, int>> BuildGraph(this List<Point> points)
{
int maxPathLength = int.MinValue;
Dictionary<Point, Dictionary<Point, int>> graph = points.ToDictionary(pt => pt, pt => new Dictionary<Point, int>());

List<int> result = [];
Stack<(Point, List<Point>)> stack = new();
stack.Push((start, new List<Point>() { start }));
foreach (Point current in points) {
Stack<(Point, int)> stack = new();
HashSet<Point> seen = [];

while (stack.Count != 0) {
var (current, visited) = stack.Pop();
stack.Push((current, 0));
_ = seen.Add(current);

if (current == end) {
result.Add(visited.Count - 1);
int count = result.Count;
if (visited.Count - 1 > maxPathLength) {
maxPathLength = int.Max(maxPathLength, visited.Count - 1);
Console.WriteLine($"{count, 20} {maxPathLength}");
}
if (count % 200 == 0) {
Console.WriteLine($"{count, 20} {maxPathLength}");
while (stack.Count > 0) {
(Point point, int steps) = stack.Pop();

if (steps != 0 && points.Contains(point)) {
graph[current][point] = steps;
continue;
}
continue;
}

foreach (Point next in GetNeighbours(map, current, true)) {
if (!visited.Contains(next)) {
List<Point> newVisited = [.. visited, .. new[] { next }];
stack.Push((next, newVisited));
foreach (Point neighbour in _map.GetAdjacentCells(point).Where(adj => adj.Value != FOREST)) {
if (!seen.Contains(neighbour)) {
stack.Push((neighbour, steps + 1));
_ = seen.Add(neighbour);
}
}
}
}

return result;
return graph;
}

// 4838 too low
// 6034 too low
// 6050 too low
// 6054 too low
// 6138 too low (19934 iterations)
// 6302 correct!!!
public static int FindMaxSteps_DepthFirstSearch(this Dictionary<Point, Dictionary<Point, int>> graph, Point point, HashSet<Point> visited)
{
if (point == _end) {
return 0;
}

int maxSteps = int.MinValue;

private static IEnumerable<Point> GetNeighbours(this Map grid, Point current, bool ignoreSlopes = false)
_ = visited.Add(point);
foreach (KeyValuePair<Point, int> next in graph[point]) {
if (!visited.Contains(next.Key)) {
maxSteps = Math.Max(maxSteps, FindMaxSteps_DepthFirstSearch(graph, next.Key, visited) + graph[point][next.Key]);
}
}
_ = visited.Remove(point);

return maxSteps;
}

public static List<int> FindAllPathLengths(this char[,] map, Point current, Point end, List<Point> isVisited)
{
char currentValue = grid[current.X, current.Y];

if (!ignoreSlopes) {
if (currentValue.IsIn(SLOPES)) {
yield return currentValue switch
{
SLOPE_RIGHT => current.Right(),
SLOPE_LEFT => current.Left(),
SLOPE_UP => current.Up(),
SLOPE_DOWN => current.Down(),
_ => throw new NotImplementedException(),
};
yield break;
if (current == end) {
return [isVisited.Count];
}

List<int> pathLengths = [];

foreach (Point neighbour in map.GetNeighbours(current)) {
if (isVisited.Contains(neighbour) is false) {
pathLengths.AddRange(FindAllPathLengths(map, neighbour, end, [.. isVisited, neighbour]));
}
}

foreach (Cell<char> item in grid.GetAdjacentCells(current).Where(adj => adj.Value != FOREST)) {
return pathLengths;
}

private static IEnumerable<Point> GetNeighbours(this char[,] _map, Point current)
{
char currentValue = _map[current.X, current.Y];

if (currentValue.IsIn(SLOPES)) {
yield return currentValue switch
{
SLOPE_RIGHT => current.Right(),
SLOPE_LEFT => current.Left(),
SLOPE_UP => current.Up(),
SLOPE_DOWN => current.Down(),
_ => throw new NotImplementedException(),
};
yield break;
}

foreach (Cell<char> item in _map.GetAdjacentCells(current).Where(adj => adj.Value != FOREST)) {
yield return item.Index;
}
}

}

0 comments on commit 9919cb8

Please sign in to comment.