Skip to content

Commit 9445814

Browse files
committed
2022/23 with iterators
1 parent 28c4e2e commit 9445814

File tree

1 file changed

+52
-72
lines changed

1 file changed

+52
-72
lines changed

2022/Day23/Solution.cs

Lines changed: 52 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,100 +10,80 @@ class Solution : Solver {
1010

1111
// I used complex numbers for a change. The map is represented with a hashset of positions.
1212

13-
public object PartOne(string input) {
14-
var state = Parse(input);
15-
for (var i = 0; i < 10; i++) {
16-
state = Step(state);
17-
}
18-
19-
// smallest enclosing rectangle
20-
var width = state.elves.Select(p => p.Real).Max() -
21-
state.elves.Select(p => p.Real).Min() + 1;
13+
public object PartOne(string input)
14+
=> Simulate(Parse(input)).Select(Area).ElementAt(9);
2215

23-
var height = state.elves.Select(p => p.Imaginary).Max() -
24-
state.elves.Select(p => p.Imaginary).Min() + 1;
16+
public object PartTwo(string input)
17+
=> Simulate(Parse(input)).Count();
2518

26-
return width * height - state.elves.Count;
27-
}
19+
IEnumerable<HashSet<Complex>> Simulate(HashSet<Complex> elves) {
20+
var lookAround = new Queue<Complex>(new []{ N, S, W, E });
2821

29-
public object PartTwo(string input) {
30-
// interate until fixpoint is reached
31-
var steps = 0;
22+
for (var fixpoint = false; !fixpoint; lookAround.Enqueue(lookAround.Dequeue())) {
23+
24+
// 1) collect proposals; for each position (key) compute the list of the elves
25+
// who want to step there
26+
var proposals = new Dictionary<Complex, List<Complex>>();
3227

33-
var state = Parse(input);
34-
while (!state.fixpoint) {
35-
state = Step(state);
36-
steps++;
37-
}
38-
39-
return steps;
40-
}
41-
42-
State Step(State state) {
43-
44-
bool occupied(Complex pos) => state.elves.Contains(pos);
45-
bool lonely(Complex pos) => directions.All(dir => !occupied(pos + dir));
46-
47-
// elf proposes a postion if nobody is nearby in that direction
48-
bool proposes(Complex elf, Complex dir) => ExtendDir(dir).All(d => !occupied(elf + d));
49-
50-
// for each position (key) it has a list of the elves who wants to step there
51-
var proposals = new Dictionary<Complex, List<Complex>>();
52-
53-
foreach (var elf in state.elves) {
54-
if (lonely(elf)) {
55-
continue;
56-
}
28+
foreach (var elf in elves) {
29+
var lonely = Directions.All(dir => !elves.Contains(elf + dir));
30+
if (lonely) {
31+
continue;
32+
}
5733

58-
foreach (var dir in state.directions) {
59-
if (proposes(elf, dir)) {
60-
var pos = elf + dir;
61-
if (!proposals.ContainsKey(pos)) {
62-
proposals[pos] = new List<Complex>();
34+
foreach (var dir in lookAround) {
35+
36+
// elf proposes a postion if nobody stands in that direction
37+
var proposes = ExtendDir(dir).All(d => !elves.Contains(elf + d));
38+
if (proposes) {
39+
var pos = elf + dir;
40+
if (!proposals.ContainsKey(pos)) {
41+
proposals[pos] = new List<Complex>();
42+
}
43+
proposals[pos].Add(elf);
44+
break;
6345
}
64-
proposals[pos].Add(elf);
65-
break;
6646
}
6747
}
68-
}
6948

70-
// move elves, compute fixpoint flag
71-
var fixpoint = true;
72-
foreach (var p in proposals) {
73-
var (to, from) = p;
74-
if (from.Count == 1) {
75-
state.elves.Remove(from.Single());
76-
state.elves.Add(to);
77-
fixpoint = false;
49+
// 2) move elves, compute fixpoint flag
50+
fixpoint = true;
51+
foreach (var p in proposals) {
52+
var (to, from) = p;
53+
if (from.Count == 1) {
54+
elves.Remove(from.Single());
55+
elves.Add(to);
56+
fixpoint = false;
57+
}
7858
}
79-
}
8059

81-
return new State(
82-
state.elves,
83-
state.directions.Skip(1).Concat(state.directions.Take(1)).ToList(),
84-
fixpoint
85-
);
60+
yield return elves;
61+
}
8662
}
8763

88-
State Parse(string input) {
89-
var lines = input.Split("\n");
64+
double Area(HashSet<Complex> elves) {
65+
// smallest enclosing rectangle
66+
var width = elves.Select(p => p.Real).Max() -
67+
elves.Select(p => p.Real).Min() + 1;
9068

91-
var elves = (
69+
var height = elves.Select(p => p.Imaginary).Max() -
70+
elves.Select(p => p.Imaginary).Min() + 1;
71+
72+
return width * height - elves.Count;
73+
}
74+
75+
HashSet<Complex> Parse(string input) {
76+
var lines = input.Split("\n");
77+
return (
9278
from irow in Enumerable.Range(0, lines.Length)
9379
from icol in Enumerable.Range(0, lines[0].Length)
9480
where lines[irow][icol] == '#'
9581
select new Complex(icol, irow)
9682
).ToHashSet();
97-
98-
var directions = new List<Complex>() { N, S, W, E };
99-
100-
return new State(elves, directions, fixpoint: false);
10183
}
10284

10385
/// -------
10486

105-
record State(HashSet<Complex> elves, List<Complex> directions, bool fixpoint);
106-
10787
static Complex N = new Complex(0, -1);
10888
static Complex E = new Complex(1, 0);
10989
static Complex S = new Complex(0, 1);
@@ -113,7 +93,7 @@ record State(HashSet<Complex> elves, List<Complex> directions, bool fixpoint);
11393
static Complex SE = S + E;
11494
static Complex SW = S + W;
11595

116-
static Complex[] directions = new[] { NW, N, NE, E, SE, S, SW, W };
96+
static Complex[] Directions = new[] { NW, N, NE, E, SE, S, SW, W };
11797

11898
// Extends an ordinal position with its intercardinal neighbours
11999
Complex[] ExtendDir(Complex dir) =>

0 commit comments

Comments
 (0)