-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSolution.cs
143 lines (122 loc) · 4.35 KB
/
Solution.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Collections.Generic;
using System.Linq;
namespace AdventOfCode2020.Day24
{
internal class Solution
{
private const int NumberOfIterations = 100;
private readonly IReadOnlyCollection<Tile> _tiles;
private readonly ConwaySimulator _simulator;
public Solution(IEnumerable<string> input)
{
_simulator = new ConwaySimulator(NumberOfIterations, NextTileState);
_tiles = input
.Select(ParseDirections)
.Select(NavigateToTile)
.ToList();
}
public int PartOne() => _tiles.GroupBy(x => x).Count(g => g.Count() % 2 == 1);
public int PartTwo()
{
var initialState = _tiles
.GroupBy(x => x)
.ToDictionary(x => (IConwayCell) x.Key, x => x.Count() % 2 == 1);
var state = _simulator.Simulate(initialState);
return state.Count(x => x.Value);
}
private static bool NextTileState(bool isBlack, int blackNeighbours) => isBlack switch
{
true when blackNeighbours == 0 || blackNeighbours > 2 => false,
false when blackNeighbours == 2 => true,
_ => isBlack
};
private static IEnumerable<HexDirection> ParseDirections(string line)
{
while (line.Length > 0)
{
if (line.StartsWith("e"))
{
yield return HexDirection.East;
line = line.Substring(1);
continue;
}
if (line.StartsWith("w"))
{
yield return HexDirection.West;
line = line.Substring(1);
continue;
}
if (line.StartsWith("ne"))
{
yield return HexDirection.NorthEast;
line = line.Substring(2);
continue;
}
if (line.StartsWith("se"))
{
yield return HexDirection.SouthEast;
line = line.Substring(2);
continue;
}
if (line.StartsWith("nw"))
{
yield return HexDirection.NorthWest;
line = line.Substring(2);
continue;
}
yield return HexDirection.SouthWest;
line = line.Substring(2);
}
}
private static Tile NavigateToTile(IEnumerable<HexDirection> directions) =>
directions.Aggregate(new Tile(0, 0), (tile, direction) => direction.Move(tile));
}
internal enum HexDirection
{
East,
West,
SouthEast,
SouthWest,
NorthWest,
NorthEast,
}
internal class Tile : IConwayCell
{
public Tile(int x, int y)
{
X = x;
Y = y;
}
public int X { get; }
public int Y { get; }
public IEnumerable<IConwayCell> Neighbours
{
get
{
yield return HexDirection.East.Move(this);
yield return HexDirection.West.Move(this);
yield return HexDirection.SouthEast.Move(this);
yield return HexDirection.SouthWest.Move(this);
yield return HexDirection.NorthWest.Move(this);
yield return HexDirection.NorthEast.Move(this);
}
}
public override bool Equals(object? obj) =>
obj is Tile tile && tile.X == X && tile.Y == Y;
public override int GetHashCode() => HashCode.Combine(X, Y);
}
internal static class DirectionExtensions
{
public static Tile Move(this HexDirection direction, Tile from) => direction switch
{
HexDirection.East => new Tile(from.X + 1, from.Y + 1),
HexDirection.West => new Tile(from.X - 1, from.Y - 1),
HexDirection.SouthEast => new Tile(from.X + 1, from.Y),
HexDirection.NorthEast => new Tile(from.X, from.Y + 1),
HexDirection.NorthWest => new Tile(from.X - 1, from.Y),
HexDirection.SouthWest => new Tile(from.X, from.Y - 1),
_ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
};
}
}