Skip to content

Commit

Permalink
Day 18
Browse files Browse the repository at this point in the history
  • Loading branch information
jongeorge1 committed Feb 25, 2019
1 parent c4f152e commit 01935ae
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 1 deletion.
2 changes: 1 addition & 1 deletion AoC2018.Runner/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"AoC2018.Runner": {
"commandName": "Project",
"commandLineArgs": "17 1"
"commandLineArgs": "18 1"
}
}
}
13 changes: 13 additions & 0 deletions AoC2018.Solutions/Day18/MapAcre.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace AoC2018.Solutions.Day18
{
using System.Collections.Generic;

public static class MapAcre
{
public const char Open = '.';

public const char Trees = '|';

public const char Lumberyard = '#';
}
}
128 changes: 128 additions & 0 deletions AoC2018.Solutions/Day18/MapExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
namespace AoC2018.Solutions.Day18
{
using System;
using System.Collections.Generic;
using System.Linq;

public static class MapExtensions
{
public static void WriteToConsole(this (char[] Map, int yOffset) state)
{
int rows = state.Map.Length / state.yOffset;

for (int i = 0; i < rows; i++)
{
string row = new string(state.Map.Skip(i * state.yOffset).Take(state.yOffset).ToArray());
Console.WriteLine(row);
}
}

public static (char[] Map, int yOffset) GetNextState(this (char[] Map, int yOffset) state)
{
char[] result = new char[state.Map.Length];

for (int i = 0; i < result.Length; i++)
{
result[i] = state.GetNextStateForAcre(i);
}

return (result, state.yOffset);
}

public static string Memoize(this (char[] Map, int yOffset) state)
{
// Lazy, as I'm not bothering to include the yOffset...
return new string(state.Map);
}

public static char GetNextStateForAcre(this (char[] Map, int yOffset) state, int acre)
{
char[] adjacentAcres = state.GetAdjacentAcres(acre).ToArray();

switch (state.Map[acre])
{
case MapAcre.Open:
if (adjacentAcres.Count(x => x == MapAcre.Trees) >= 3)
{
return MapAcre.Trees;
}

return MapAcre.Open;

case MapAcre.Trees:
if (adjacentAcres.Count(x => x == MapAcre.Lumberyard) >= 3)
{
return MapAcre.Lumberyard;
}

return MapAcre.Trees;

case MapAcre.Lumberyard:
if (adjacentAcres.Count(x => x == MapAcre.Lumberyard) >= 1 && adjacentAcres.Count(x => x == MapAcre.Trees) >= 1)
{
return MapAcre.Lumberyard;
}

return MapAcre.Open;
}

throw new InvalidOperationException();
}

public static IEnumerable<char> GetAdjacentAcres(this (char[] Map, int yOffset) state, int acre)
{
int up = acre - state.yOffset;
int left = acre - 1;
int right = acre + 1;
int down = acre + state.yOffset;

int minX = (acre / state.yOffset) * state.yOffset;
int maxX = minX + state.yOffset;

bool canLookUp = up >= 0;
bool canLookDown = down < state.Map.Length;
bool canLookLeft = left >= minX;
bool canLookRight = right < maxX;

if (canLookUp)
{
yield return state.Map[up];

if (canLookLeft)
{
yield return state.Map[up - 1];
}

if (canLookRight)
{
yield return state.Map[up + 1];
}
}

if (canLookDown)
{
yield return state.Map[down];

if (canLookLeft)
{
yield return state.Map[down - 1];
}

if (canLookRight)
{
yield return state.Map[down + 1];
}
}

if (canLookLeft)
{
yield return state.Map[left];
}

if (canLookRight)
{
yield return state.Map[right];
}
}
}
}
17 changes: 17 additions & 0 deletions AoC2018.Solutions/Day18/MapParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace AoC2018.Solutions.Day18
{
using System;
using System.Linq;

public static class MapParser
{
public static (char[] Map, int yOffset) Parse(string input)
{
string[] rows = input.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
int yOffset = rows[0].Length;
char[] map = rows.SelectMany(x => x.ToCharArray()).ToArray();

return (map, yOffset);
}
}
}
29 changes: 29 additions & 0 deletions AoC2018.Solutions/Day18/Part01.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace AoC2018.Solutions.Day18
{
using System;
using System.Linq;

public class Part01 : ISolution
{
public string Solve(string input)
{
(char[] Map, int yOffset) map = MapParser.Parse(input);

////Console.WriteLine("Initial state:");
////map.WriteToConsole();

for (int i = 0; i < 10; i++)
{
map = map.GetNextState();

////Console.WriteLine($"After {i + 1} minute:");
////map.WriteToConsole();
}

int woodCount = map.Map.Count(x => x == MapAcre.Trees);
int lumberYardCount = map.Map.Count(x => x == MapAcre.Lumberyard);

return (woodCount * lumberYardCount).ToString();
}
}
}
53 changes: 53 additions & 0 deletions AoC2018.Solutions/Day18/Part02.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace AoC2018.Solutions.Day18
{
using System;
using System.Collections.Generic;
using System.Linq;

public class Part02 : ISolution
{
public string Solve(string input)
{
(char[] Map, int yOffset) map = MapParser.Parse(input);

// Predictably, part 2 is just part 1 amped up. Equally predictably, this means
// that after a certain amount of time, the pattern will settle into a loop. This
// means we need to:
// 1. Work out the point at which we start iterating.
// 2. Find the iteration length.
// 3. Do some maths
// 4. Iterate a few more times
var states = new List<string>(10000);
string mapMemo = map.Memoize();

do
{
states.Add(mapMemo);

map = map.GetNextState();
mapMemo = map.Memoize();
}
while (!states.Contains(mapMemo));

Console.WriteLine($"Iteration point hit after {states.Count} iterations");

// We've hit a point where we've seen this state before.
int originalIterationForThisState = states.IndexOf(mapMemo);
int iterationLength = states.Count - originalIterationForThisState;

const int target = 1000000000;
int numberOfWholeIterations = (target - originalIterationForThisState) / iterationLength;
int remainingTicksRequired = target - originalIterationForThisState - (numberOfWholeIterations * iterationLength);

for (int i = 0; i < remainingTicksRequired; i++)
{
map = map.GetNextState();
}

int woodCount = map.Map.Count(x => x == MapAcre.Trees);
int lumberYardCount = map.Map.Count(x => x == MapAcre.Lumberyard);

return (woodCount * lumberYardCount).ToString();
}
}
}
1 change: 1 addition & 0 deletions AoC2018.Tests/AoCTestCases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class AoCTestCases
[TestCase(16, 1, "Before: [3, 2, 1, 1]\r\n9 2 1 2\r\nAfter: [3, 2, 2, 1]", "1")]
[TestCase(17, 1, "x=495, y=2..7\r\ny=7, x=495..501\r\nx=501, y=3..7\r\nx=498, y=2..4\r\nx=506, y=1..2\r\nx=498, y=10..13\r\nx=504, y=10..13\r\ny=13, x=498..504", "57")]
[TestCase(17, 2, "x=495, y=2..7\r\ny=7, x=495..501\r\nx=501, y=3..7\r\nx=498, y=2..4\r\nx=506, y=1..2\r\nx=498, y=10..13\r\nx=504, y=10..13\r\ny=13, x=498..504", "29")]
[TestCase(18, 1, ".#.#...|#.\r\n.....#|##|\r\n.|..|...#.\r\n..|#.....#\r\n#.#|||#|#|\r\n...#.||...\r\n.|....|...\r\n||...#|.#|\r\n|.||||..|.\r\n...#.|..|.", "1147")]
public void Tests(int day, int part, string input, string expectedResult)
{
ISolution solution = SolutionFactory.GetSolution(day, part);
Expand Down

0 comments on commit 01935ae

Please sign in to comment.