Skip to content

Commit

Permalink
day(14): Tidied up
Browse files Browse the repository at this point in the history
  • Loading branch information
adamrodger committed Dec 14, 2023
1 parent 79f308a commit 168c72f
Showing 1 changed file with 74 additions and 51 deletions.
125 changes: 74 additions & 51 deletions src/AdventOfCode/Day14.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using AdventOfCode.Utilities;
Expand All @@ -15,61 +14,77 @@ public class Day14
public int Part1(string[] input)
{
Map map = Map.Parse(input);
map.Move(Bearing.North);
map.Tilt(Bearing.North);
return map.Load;
}

public int Part2(string[] input)
{
Map map = Map.Parse(input);

List<int> loads = new();
List<int> loads = new(256);
Dictionary<string, int> seen = new(256);

for (int i = 0; i < 1000; i++)
int loopStart;

for (int i = 0; ; i++)
{
map.Cycle();
int load = map.Load;

loads.Add(load);

//Debug.WriteLine(map.Print());
}


// 102921 -- too high
// 102188 -- too high
string state = map.Print();

Dictionary<int, int> analysis = loads.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());

// 101400 -- too high
// 101288 -- incorrect (5min lockout, no too high/low info)

var keys = analysis.Where(kvp => kvp.Value > 1).OrderBy(kvp => kvp.Key);
if (seen.TryGetValue(state, out loopStart))
{
break;
}

int cycleLength = keys.Count();
loads.Add(map.Load);
seen[state] = i;
}

int index = ((1_000_000_000 - (analysis.Count - cycleLength)) % cycleLength) + analysis.Count - 1;
int loopLength = seen.Count - loopStart;
int index = (1_000_000_000 - loopStart) % loopLength + loopStart - 1;

return loads[index];
}

/// <summary>
/// Map of rocks and walls
/// </summary>
private class Map
{
private readonly ISet<Point2D> walls;
private readonly IList<Point2D> balls;
private readonly HashSet<Point2D> walls;
private readonly List<Point2D> balls;
private readonly int height;
private readonly int width;
private readonly StringBuilder printer;

/// <summary>
/// The load on the north wall of the map
/// </summary>
public int Load => this.balls.Select(b => this.height - b.Y).Sum();

private Map(ISet<Point2D> walls, IList<Point2D> balls, int height, int width)
/// <summary>
/// Initialises a new instance of the <see cref="Map"/> class.
/// </summary>
/// <param name="walls">Fixed wall positions</param>
/// <param name="balls">Mobile ball positions</param>
/// <param name="height">Map height</param>
/// <param name="width">Map width</param>
private Map(HashSet<Point2D> walls, List<Point2D> balls, int height, int width)
{
this.walls = walls;
this.balls = balls;
this.height = height;
this.width = width;
this.printer = new StringBuilder(this.width * this.height + this.height * Environment.NewLine.Length);
}

/// <summary>
/// Parse the input
/// </summary>
/// <param name="input">Input</param>
/// <returns>Parsed map</returns>
public static Map Parse(IReadOnlyList<string> input)
{
HashSet<Point2D> walls = new();
Expand All @@ -90,22 +105,22 @@ public static Map Parse(IReadOnlyList<string> input)
return new Map(walls, balls, input.Count, input[0].Length);
}

/// <summary>
/// Perform one full tilting cycle on the map
/// </summary>
public void Cycle()
{
this.Move(Bearing.North);
//Debug.WriteLine(this.Print());

this.Move(Bearing.West);
//Debug.WriteLine(this.Print());

this.Move(Bearing.South);
//Debug.WriteLine(this.Print());

this.Move(Bearing.East);
//Debug.WriteLine(this.Print());
this.Tilt(Bearing.North);
this.Tilt(Bearing.West);
this.Tilt(Bearing.South);
this.Tilt(Bearing.East);
}

public void Move(Bearing bearing)
/// <summary>
/// Tile the map in the given direction to move all of the balls
/// </summary>
/// <param name="bearing">Tilt direction</param>
public void Tilt(Bearing bearing)
{
IEnumerable<Point2D> ordered = this.Order(bearing);
HashSet<Point2D> settled = new();
Expand All @@ -121,20 +136,18 @@ public void Move(Bearing bearing)
next = current.Move(bearing);
}

bool added = settled.Add(current);
Debug.Assert(added);
settled.Add(current);
}

Debug.Assert(this.balls.Count == settled.Count, "We've lost some balls...");

this.balls.Clear();

foreach (Point2D ball in settled)
{
this.balls.Add(ball);
}
this.balls.AddRange(settled);
}

/// <summary>
/// Order the balls so they can move correctly depending on the tilt direction
/// </summary>
/// <param name="bearing">Tilt direction</param>
/// <returns>Ordered balls to move</returns>
private IEnumerable<Point2D> Order(Bearing bearing) => bearing switch
{
Bearing.North => this.balls.OrderBy(b => b.Y),
Expand All @@ -144,6 +157,12 @@ public void Move(Bearing bearing)
_ => throw new ArgumentOutOfRangeException(nameof(bearing), bearing, null)
};

/// <summary>
/// Check if the given point is still in bounds according to the tilt direction
/// </summary>
/// <param name="point">Point</param>
/// <param name="bearing">Tilt direction</param>
/// <returns>Ball is still in bounds</returns>
private bool InBounds(Point2D point, Bearing bearing) => bearing switch

Check warning on line 166 in src/AdventOfCode/Day14.cs

View workflow job for this annotation

GitHub Actions / build

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(AdventOfCode.Utilities.Bearing)4' is not covered.

Check warning on line 166 in src/AdventOfCode/Day14.cs

View workflow job for this annotation

GitHub Actions / build

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(AdventOfCode.Utilities.Bearing)4' is not covered.
{
Bearing.North => point.Y > 0,
Expand All @@ -152,9 +171,13 @@ public void Move(Bearing bearing)
Bearing.West => point.X > 0
};

/// <summary>
/// Print the current state of the map
/// </summary>
/// <returns>Map state</returns>
public string Print()
{
StringBuilder s = new(this.width * this.height + this.height * Environment.NewLine.Length);
this.printer.Clear();
HashSet<Point2D> settled = this.balls.ToHashSet();

for (int y = 0; y < this.height; y++)
Expand All @@ -163,22 +186,22 @@ public string Print()
{
if (this.walls.Contains((x, y)))
{
s.Append('#');
this.printer.Append('#');
}
else if (settled.Contains((x, y)))
{
s.Append('O');
this.printer.Append('O');
}
else
{
s.Append('.');
this.printer.Append('.');
}
}

s.AppendLine();
this.printer.AppendLine();
}

return s.ToString();
return this.printer.ToString();
}
}
}
Expand Down

0 comments on commit 168c72f

Please sign in to comment.