Skip to content

Commit 1672165

Browse files
committed
2023 day 22, lucianoq
1 parent d7c6a0e commit 1672165

File tree

8 files changed

+1877
-0
lines changed

8 files changed

+1877
-0
lines changed

2023/22/Makefile

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
main1:
2+
go build -o main1 main1.go common.go
3+
4+
main2:
5+
go build -o main2 main2.go common.go
6+
7+
.PHONY: run1 run2 clean
8+
9+
run1: main1
10+
./main1 <input
11+
12+
run2: main2
13+
./main2 <input
14+
15+
clean:
16+
rm -f main1 main2
17+

2023/22/assignment

+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
--- Day 22: Sand Slabs ---
2+
3+
Enough sand has fallen; it can finally filter water for Snow Island.
4+
5+
Well, almost .
6+
7+
The sand has been falling as large compacted bricks of sand, piling up
8+
to form an impressive stack here near the edge of Island Island. In
9+
order to make use of the sand to filter water, some of the bricks will
10+
need to be broken apart - nay, disintegrated - back into freely flowing
11+
sand.
12+
13+
The stack is tall enough that you'll have to be careful about choosing
14+
which bricks to disintegrate; if you disintegrate the wrong brick,
15+
large portions of the stack could topple, which sounds pretty
16+
dangerous.
17+
18+
The Elves responsible for water filtering operations took a snapshot of
19+
the bricks while they were still falling (your puzzle input) which
20+
should let you work out which bricks are safe to disintegrate. For
21+
example:
22+
23+
1,0,1~1,2,1
24+
0,0,2~2,0,2
25+
0,2,3~2,2,3
26+
0,0,4~0,2,4
27+
2,0,5~2,2,5
28+
0,1,6~2,1,6
29+
1,1,8~1,1,9
30+
31+
Each line of text in the snapshot represents the position of a single
32+
brick at the time the snapshot was taken. The position is given as two
33+
x,y,z coordinates - one for each end of the brick - separated by a
34+
tilde ( ~ ). Each brick is made up of a single straight line of cubes,
35+
and the Elves were even careful to choose a time for the snapshot that
36+
had all of the free-falling bricks at integer positions above the
37+
ground , so the whole snapshot is aligned to a three-dimensional cube
38+
grid.
39+
40+
A line like 2,2,2~2,2,2 means that both ends of the brick are at the
41+
same coordinate - in other words, that the brick is a single cube.
42+
43+
Lines like 0,0,10~1,0,10 or 0,0,10~0,1,10 both represent bricks that
44+
are two cubes in volume, both oriented horizontally. The first brick
45+
extends in the x direction, while the second brick extends in the y
46+
direction.
47+
48+
A line like 0,0,1~0,0,10 represents a ten-cube brick which is oriented
49+
vertically . One end of the brick is the cube located at 0,0,1 , while
50+
the other end of the brick is located directly above it at 0,0,10 .
51+
52+
The ground is at z=0 and is perfectly flat; the lowest z value a brick
53+
can have is therefore 1 . So, 5,5,1~5,6,1 and 0,2,1~0,2,5 are both
54+
resting on the ground, but 3,3,2~3,3,3 was above the ground at the time
55+
of the snapshot.
56+
57+
Because the snapshot was taken while the bricks were still falling,
58+
some bricks will still be in the air ; you'll need to start by figuring
59+
out where they will end up. Bricks are magically stabilized, so they
60+
never rotate , even in weird situations like where a long horizontal
61+
brick is only supported on one end. Two bricks cannot occupy the same
62+
position, so a falling brick will come to rest upon the first other
63+
brick it encounters.
64+
65+
Here is the same example again, this time with each brick given a
66+
letter so it can be marked in diagrams:
67+
68+
1,0,1~1,2,1 <- A
69+
0,0,2~2,0,2 <- B
70+
0,2,3~2,2,3 <- C
71+
0,0,4~0,2,4 <- D
72+
2,0,5~2,2,5 <- E
73+
0,1,6~2,1,6 <- F
74+
1,1,8~1,1,9 <- G
75+
76+
At the time of the snapshot, from the side so the x axis goes left to
77+
right, these bricks are arranged like this:
78+
79+
x
80+
012
81+
.G. 9
82+
.G. 8
83+
... 7
84+
FFF 6
85+
..E 5 z
86+
D.. 4
87+
CCC 3
88+
BBB 2
89+
.A. 1
90+
--- 0
91+
92+
Rotating the perspective 90 degrees so the y axis now goes left to
93+
right, the same bricks are arranged like this:
94+
95+
y
96+
012
97+
.G. 9
98+
.G. 8
99+
... 7
100+
.F. 6
101+
EEE 5 z
102+
DDD 4
103+
..C 3
104+
B.. 2
105+
AAA 1
106+
--- 0
107+
108+
Once all of the bricks fall downward as far as they can go, the stack
109+
looks like this, where ? means bricks are hidden behind other bricks at
110+
that location:
111+
112+
x
113+
012
114+
.G. 6
115+
.G. 5
116+
FFF 4
117+
D.E 3 z
118+
??? 2
119+
.A. 1
120+
--- 0
121+
122+
Again from the side:
123+
124+
y
125+
012
126+
.G. 6
127+
.G. 5
128+
.F. 4
129+
??? 3 z
130+
B.C 2
131+
AAA 1
132+
--- 0
133+
134+
Now that all of the bricks have settled, it becomes easier to tell
135+
which bricks are supporting which other bricks:
136+
* Brick A is the only brick supporting bricks B and C .
137+
* Brick B is one of two bricks supporting brick D and brick E .
138+
* Brick C is the other brick supporting brick D and brick E .
139+
* Brick D supports brick F .
140+
* Brick E also supports brick F .
141+
* Brick F supports brick G .
142+
* Brick G isn't supporting any bricks.
143+
144+
Your first task is to figure out which bricks are safe to disintegrate
145+
. A brick can be safely disintegrated if, after removing it, no other
146+
bricks would fall further directly downward. Don't actually
147+
disintegrate any bricks - just determine what would happen if, for each
148+
brick, only that brick were disintegrated. Bricks can be disintegrated
149+
even if they're completely surrounded by other bricks; you can squeeze
150+
between bricks if you need to.
151+
152+
In this example, the bricks can be disintegrated as follows:
153+
* Brick A cannot be disintegrated safely; if it were disintegrated,
154+
bricks B and C would both fall.
155+
* Brick B can be disintegrated; the bricks above it ( D and E ) would
156+
still be supported by brick C .
157+
* Brick C can be disintegrated; the bricks above it ( D and E ) would
158+
still be supported by brick B .
159+
* Brick D can be disintegrated; the brick above it ( F ) would still
160+
be supported by brick E .
161+
* Brick E can be disintegrated; the brick above it ( F ) would still
162+
be supported by brick D .
163+
* Brick F cannot be disintegrated; the brick above it ( G ) would
164+
fall.
165+
* Brick G can be disintegrated; it does not support any other bricks.
166+
167+
So, in this example, 5 bricks can be safely disintegrated.
168+
169+
Figure how the blocks will settle based on the snapshot. Once they've
170+
settled, consider disintegrating a single brick; how many bricks could
171+
be safely chosen as the one to get disintegrated?
172+
173+
--- Part Two ---
174+
175+
Disintegrating bricks one at a time isn't going to be fast enough.
176+
While it might sound dangerous, what you really need is a chain
177+
reaction .
178+
179+
You'll need to figure out the best brick to disintegrate. For each
180+
brick, determine how many other bricks would fall if that brick were
181+
disintegrated.
182+
183+
Using the same example as above:
184+
* Disintegrating brick A would cause all 6 other bricks to fall.
185+
* Disintegrating brick F would cause only 1 other brick, G , to fall.
186+
187+
Disintegrating any other brick would cause no other bricks to fall. So,
188+
in this example, the sum of the number of other bricks that would fall
189+
as a result of disintegrating each brick is 7 .
190+
191+
For each brick, determine how many other bricks would fall if that
192+
brick were disintegrated. What is the sum of the number of other bricks
193+
that would fall?

2023/22/common.go

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"strings"
8+
)
9+
10+
type P struct{ X, Y, Z int }
11+
12+
type Brick struct {
13+
ID int
14+
Start, End P
15+
}
16+
17+
type Space struct {
18+
Map map[P]int
19+
Bricks map[int]*Brick
20+
}
21+
22+
func parse() *Space {
23+
s := NewSpace()
24+
scanner := bufio.NewScanner(os.Stdin)
25+
for i := 0; scanner.Scan(); i++ {
26+
ff := strings.Split(scanner.Text(), "~")
27+
var start, end P
28+
_, _ = fmt.Sscanf(ff[0], "%d,%d,%d", &start.X, &start.Y, &start.Z)
29+
_, _ = fmt.Sscanf(ff[1], "%d,%d,%d", &end.X, &end.Y, &end.Z)
30+
s.Add(&Brick{i, start, end})
31+
}
32+
return s
33+
}
34+
35+
func NewSpace() *Space {
36+
return &Space{
37+
Map: make(map[P]int),
38+
Bricks: make(map[int]*Brick),
39+
}
40+
}
41+
42+
func (s *Space) Add(b *Brick) {
43+
s.Bricks[b.ID] = b
44+
for x := b.Start.X; x <= b.End.X; x++ {
45+
for y := b.Start.Y; y <= b.End.Y; y++ {
46+
for z := b.Start.Z; z <= b.End.Z; z++ {
47+
s.Map[P{x, y, z}] = b.ID
48+
}
49+
}
50+
}
51+
}
52+
53+
func (s *Space) Fall() int {
54+
fallen := map[int]struct{}{}
55+
for changed := true; changed; {
56+
changed = false
57+
for _, b := range s.Bricks {
58+
for s.EmptyBelow(b) {
59+
s.Move(b, P{0, 0, -1})
60+
changed = true
61+
fallen[b.ID] = struct{}{}
62+
}
63+
}
64+
}
65+
return len(fallen)
66+
}
67+
68+
func (s *Space) EmptyBelow(b *Brick) bool {
69+
if b.Start.Z == 1 {
70+
return false
71+
}
72+
for x := b.Start.X; x <= b.End.X; x++ {
73+
for y := b.Start.Y; y <= b.End.Y; y++ {
74+
if _, full := s.Map[P{x, y, b.Start.Z - 1}]; full {
75+
return false
76+
}
77+
}
78+
}
79+
return true
80+
}
81+
82+
func (s *Space) Move(b *Brick, p P) {
83+
for x := b.Start.X; x <= b.End.X; x++ {
84+
for y := b.Start.Y; y <= b.End.Y; y++ {
85+
for z := b.Start.Z; z <= b.End.Z; z++ {
86+
delete(s.Map, P{x, y, z})
87+
}
88+
}
89+
}
90+
for x := b.Start.X + p.X; x <= b.End.X+p.X; x++ {
91+
for y := b.Start.Y + p.Y; y <= b.End.Y+p.Y; y++ {
92+
for z := b.Start.Z + p.Z; z <= b.End.Z+p.Z; z++ {
93+
s.Map[P{x, y, z}] = b.ID
94+
}
95+
}
96+
}
97+
98+
s.Bricks[b.ID].Start.X += p.X
99+
s.Bricks[b.ID].Start.Y += p.Y
100+
s.Bricks[b.ID].Start.Z += p.Z
101+
s.Bricks[b.ID].End.X += p.X
102+
s.Bricks[b.ID].End.Y += p.Y
103+
s.Bricks[b.ID].End.Z += p.Z
104+
}
105+
106+
func (s *Space) TopOf(b *Brick) []*Brick {
107+
var onTop []*Brick
108+
for x := b.Start.X; x <= b.End.X; x++ {
109+
for y := b.Start.Y; y <= b.End.Y; y++ {
110+
if id, ok := s.Map[P{x, y, b.End.Z + 1}]; ok {
111+
onTop = append(onTop, s.Bricks[id])
112+
}
113+
}
114+
}
115+
return onTop
116+
}
117+
118+
func (s *Space) SafeToDisintegrate(b *Brick) bool {
119+
for _, topB := range s.TopOf(b) {
120+
if s.DependsOn(topB, b) {
121+
return false
122+
}
123+
}
124+
return true
125+
}
126+
127+
func (s *Space) DependsOn(topB, botB *Brick) bool {
128+
for x := topB.Start.X; x <= topB.End.X; x++ {
129+
for y := topB.Start.Y; y <= topB.End.Y; y++ {
130+
if id, full := s.Map[P{x, y, topB.Start.Z - 1}]; full && id != botB.ID {
131+
return false
132+
}
133+
}
134+
}
135+
return true
136+
}

0 commit comments

Comments
 (0)