Skip to content
This repository was archived by the owner on Dec 28, 2024. It is now read-only.

Commit 6a8ce93

Browse files
committed
Add solution day 15 part 1
1 parent db623c3 commit 6a8ce93

File tree

4 files changed

+190
-2
lines changed

4 files changed

+190
-2
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ automatically rebuilt and redeployed ever time the `common` module or their own
4646
| Day | Solution | Day | Solution |
4747
|-----|----------|-----|----------|
4848
| 01 | ⭐ ⭐ | 14 | ⭐ ⭐ |
49-
| 02 | ⭐ ⭐ | 15 | |
49+
| 02 | ⭐ ⭐ | 15 | |
5050
| 03 | ⭐ ⭐ | 16 | |
5151
| 04 | ⭐ ⭐ | 17 | |
5252
| 05 | ⭐ ⭐ | 18 | |

common/util/coordinate.go

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ func (c Coordinate) Modulo(x int, y int) Coordinate {
3131
return Coordinate{X: c.X % x, Y: c.Y % y}
3232
}
3333

34+
func (c Coordinate) Equals(c2 Coordinate) bool {
35+
return c.X == c2.X && c.Y == c2.Y
36+
}
37+
3438
func (c Coordinate) PositiveModulo(x int, y int) Coordinate {
3539
// This is similar to how modulo works in Python
3640
// See: https://stackoverflow.com/questions/13794171/how-to-make-the-mod-of-a-negative-number-to-be-positive/13794192

solutions/day15/main.go

+63-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,71 @@
11
package main
22

33
import (
4+
"fmt"
45
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
57
)
68

79
func main() {
8-
common.Setup(15, nil, nil)
10+
common.Setup(15, part1, nil)
11+
}
12+
13+
func part1(
14+
input string,
15+
) string {
16+
p, err := parse(input)
17+
if err != nil {
18+
return fmt.Sprintf("Failed to parse input: %v", err)
19+
}
20+
21+
for _, move := range p.moves {
22+
endPosition, err := findEndPosition(p.warehouse, p.robot, move)
23+
if err != nil {
24+
continue
25+
}
26+
27+
newRobot := move(p.robot)
28+
if !newRobot.Equals(endPosition) {
29+
// End position is more than one step, meaning we need to move boxes
30+
p.warehouse[newRobot.Y][newRobot.X] = GROUND
31+
p.warehouse[endPosition.Y][endPosition.X] = BOX
32+
}
33+
p.robot = newRobot
34+
}
35+
36+
return fmt.Sprintf("Sum of all GPS coordinates: %d", score(p.warehouse))
37+
}
38+
39+
func findEndPosition(
40+
w warehouseMatrix,
41+
s util.Coordinate,
42+
d util.Direction,
43+
) (util.Coordinate, error) {
44+
np := d(s)
45+
ch := w[np.Y][np.X]
46+
switch ch {
47+
case GROUND:
48+
return np, nil
49+
case BOX:
50+
return findEndPosition(w, np, d)
51+
case WALL:
52+
return np, fmt.Errorf("wall hit")
53+
}
54+
55+
panic(fmt.Sprintf("Invalid character: %c", ch))
56+
}
57+
58+
func score(
59+
wh warehouseMatrix,
60+
) int {
61+
sum := 0
62+
for y, row := range wh {
63+
for x, ch := range row {
64+
if ch != BOX {
65+
continue
66+
}
67+
sum += x + 100*y
68+
}
69+
}
70+
return sum
971
}

solutions/day15/parse.go

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"github.com/terminalnode/adventofcode2024/common/util"
6+
"strings"
7+
)
8+
9+
type warehouseMatrix = [][]int32
10+
type moveList = []util.Direction
11+
type robotPosition = util.Coordinate
12+
13+
type problem struct {
14+
robot robotPosition
15+
warehouse warehouseMatrix
16+
moves moveList
17+
}
18+
19+
const (
20+
WALL = '#'
21+
BOX = 'O'
22+
ROBOT = '@'
23+
GROUND = '.'
24+
)
25+
26+
func parse(
27+
input string,
28+
) (problem, error) {
29+
whRaw, mRaw, err := splitInput(input)
30+
if err != nil {
31+
return problem{}, err
32+
}
33+
34+
wh, r, err := parseWarehouse(whRaw)
35+
36+
m, err := parseMoves(mRaw)
37+
if err != nil {
38+
return problem{}, err
39+
}
40+
41+
return problem{
42+
robot: r,
43+
warehouse: wh,
44+
moves: m,
45+
}, nil
46+
}
47+
48+
func splitInput(
49+
input string,
50+
) (string, string, error) {
51+
split := strings.Split(input, "\n\n")
52+
if len(split) != 2 {
53+
return "", "", fmt.Errorf("expected input to have two parts, but was %d", len(split))
54+
}
55+
return split[0], split[1], nil
56+
}
57+
58+
func parseWarehouse(
59+
wh string,
60+
) (warehouseMatrix, util.Coordinate, error) {
61+
lines := strings.Split(wh, "\n")
62+
out := make(warehouseMatrix, len(lines))
63+
robot := util.Coordinate{}
64+
foundRobot := false
65+
66+
for y, line := range lines {
67+
out[y] = []int32(line)
68+
for x, ch := range line {
69+
if ch != WALL && ch != ROBOT && ch != BOX && ch != GROUND {
70+
return out, robot, fmt.Errorf("invalid character in warehouse matrix: %c", ch)
71+
}
72+
73+
if ch != ROBOT {
74+
continue
75+
}
76+
foundRobot = true
77+
robot = util.Coordinate{X: x, Y: y}
78+
out[y][x] = GROUND
79+
}
80+
}
81+
82+
if !foundRobot {
83+
return out, robot, fmt.Errorf("no robot in input")
84+
}
85+
86+
return out, robot, nil
87+
}
88+
89+
func parseMoves(
90+
m string,
91+
) (moveList, error) {
92+
ms := make(moveList, 0, len(m))
93+
for _, ch := range m {
94+
if ch == '\n' {
95+
// As per instructions, ignore new lines
96+
continue
97+
}
98+
99+
newMove, err := charToDirection(ch)
100+
if err != nil {
101+
return ms, err
102+
}
103+
ms = append(ms, newMove)
104+
}
105+
return ms, nil
106+
}
107+
108+
func charToDirection(
109+
ch int32,
110+
) (util.Direction, error) {
111+
switch ch {
112+
case '^':
113+
return util.Coordinate.North, nil
114+
case 'v':
115+
return util.Coordinate.South, nil
116+
case '>':
117+
return util.Coordinate.East, nil
118+
case '<':
119+
return util.Coordinate.West, nil
120+
}
121+
return nil, fmt.Errorf("invalid direction '%c'", ch)
122+
}

0 commit comments

Comments
 (0)