Skip to content

Commit b7c4835

Browse files
committed
bug: Fixing day 12 solution
1 parent 764db7e commit b7c4835

File tree

2 files changed

+243
-65
lines changed

2 files changed

+243
-65
lines changed

src/day12/day12.go

Lines changed: 93 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,15 @@ import (
44
"strings"
55
)
66

7-
type point struct {
8-
x, y int
7+
type plot struct {
8+
crop rune
9+
top, bottom, left, right bool
10+
regionId uint
911
}
1012

11-
type fence struct {
12-
x, y int
13-
direction rune
14-
}
15-
16-
func (p point) surroundingFences() []fence {
17-
top := fence{x: p.x, y: p.y, direction: '-'}
18-
bottom := fence{x: p.x, y: p.y + 1, direction: '-'}
19-
left := fence{x: p.x, y: p.y, direction: '|'}
20-
right := fence{x: p.x + 1, y: p.y, direction: '|'}
21-
return []fence{top, bottom, left, right}
13+
type region struct {
14+
crop rune
15+
id uint
2216
}
2317

2418
type patch struct {
@@ -27,79 +21,116 @@ type patch struct {
2721
}
2822

2923
func Solve(input string) uint {
30-
crops := parseInput(input)
24+
garden := parseInput(input)
25+
updateFences(&garden)
26+
assignCropId(&garden)
27+
mergeNeighbors(&garden)
28+
3129
var cost uint = 0
32-
for _, crop := range crops {
33-
uniquePatches, fencesUsed := findUniquePatches(crop)
34-
details := patchDetails(uniquePatches, fencesUsed)
35-
for _, d := range details {
36-
cost += d.area * d.perimeter
37-
}
30+
for _, p := range getPatches(&garden) {
31+
cost += p.area * p.perimeter
3832
}
3933
return cost
4034
}
4135

42-
func parseInput(input string) map[rune][]point {
43-
crops := make(map[rune][]point)
36+
func parseInput(input string) [][]plot {
37+
garden := make([][]plot, 0)
4438
for j, line := range strings.Split(input, "\n") {
45-
for i, plant := range line {
46-
crops[plant] = append(crops[plant], point{x: i, y: j})
39+
garden = append(garden, make([]plot, 0))
40+
for _, r := range line {
41+
garden[j] = append(garden[j], plot{crop: r})
4742
}
4843
}
49-
return crops
44+
return garden
5045
}
5146

52-
func findUniquePatches(crop []point) (map[uint][]point, map[fence]uint) {
53-
var nextPatchId uint = 1
54-
patches := make(map[uint][]point)
55-
fencesByPatchId := make(map[fence]uint)
56-
for _, p := range crop {
57-
usedNewPatchId := true
58-
currentPatchId := nextPatchId
59-
newlyUsedFences := make([]fence, 0)
47+
func updateFences(garden *[][]plot) {
48+
max := len((*garden)) - 1
49+
for j, line := range *garden {
50+
for i, plot := range line {
51+
(*garden)[j][i].top = j == 0 || (*garden)[j-1][i].crop != plot.crop
52+
(*garden)[j][i].bottom = j == max || (*garden)[j+1][i].crop != plot.crop
53+
(*garden)[j][i].left = i == 0 || (*garden)[j][i-1].crop != plot.crop
54+
(*garden)[j][i].right = i == max || (*garden)[j][i+1].crop != plot.crop
55+
}
56+
}
57+
}
6058

61-
for _, f := range p.surroundingFences() {
62-
if fencesByPatchId[f] == 0 {
63-
newlyUsedFences = append(newlyUsedFences, f)
64-
continue
59+
func assignCropId(garden *[][]plot) {
60+
nextRegionId := make(map[rune]uint)
61+
for j, line := range *garden {
62+
for i, plot := range line {
63+
var plotId uint
64+
if !plot.top {
65+
plotId = (*garden)[j-1][i].regionId
66+
} else if !plot.left {
67+
plotId = (*garden)[j][i-1].regionId
68+
} else {
69+
plotId = nextRegionId[plot.crop] + 1
6570
}
71+
(*garden)[j][i].regionId = plotId
6672

67-
if fencesByPatchId[f] != currentPatchId {
68-
patches[fencesByPatchId[f]] = append(patches[fencesByPatchId[f]], patches[currentPatchId]...)
69-
delete(patches, currentPatchId)
70-
currentPatchId = fencesByPatchId[f]
71-
usedNewPatchId = false
73+
if plot.right {
74+
nextRegionId[plot.crop]++
7275
}
73-
delete(fencesByPatchId, f)
7476
}
77+
}
78+
}
7579

76-
for _, f := range newlyUsedFences {
77-
fencesByPatchId[f] = currentPatchId
78-
}
80+
func mergeNeighbors(garden *[][]plot) {
81+
for {
82+
mergesMade := false
83+
mergedRegions := make(map[region]region)
84+
for j, line := range *garden {
85+
for i := 0; i < len(line)-1; i++ {
86+
plot := line[i]
87+
if plot.right || (*garden)[j][i+1].regionId == plot.regionId {
88+
continue
89+
}
7990

80-
patches[currentPatchId] = append(patches[currentPatchId], p)
91+
var t, f uint
92+
if plot.regionId > (*garden)[j][i+1].regionId {
93+
t = plot.regionId
94+
f = (*garden)[j][i+1].regionId
95+
} else {
96+
t = (*garden)[j][i+1].regionId
97+
f = plot.regionId
98+
}
99+
to := region{crop: plot.crop, id: t}
100+
from := region{crop: plot.crop, id: f}
101+
mergedRegions[from] = to
102+
mergesMade = true
103+
}
104+
}
105+
if !mergesMade {
106+
break
107+
}
81108

82-
if usedNewPatchId {
83-
nextPatchId++
109+
for j, line := range *garden {
110+
for i, plot := range line {
111+
r := region{id: plot.regionId, crop: plot.crop}
112+
if update, ok := mergedRegions[r]; ok {
113+
(*garden)[j][i].regionId = update.id
114+
}
115+
}
84116
}
85117
}
86-
87-
return patches, fencesByPatchId
88118
}
89119

90-
func patchDetails(patches map[uint][]point, fencesUsed map[fence]uint) []patch {
91-
details := make([]patch, len(patches))
92-
i := 0
93-
for _, points := range patches {
94-
details[i].area = uint(len(points))
95-
for _, p := range points {
96-
for _, f := range p.surroundingFences() {
97-
if fencesUsed[f] > 0 {
98-
details[i].perimeter++
120+
func getPatches(garden *[][]plot) map[region]patch {
121+
result := make(map[region]patch)
122+
for _, line := range *garden {
123+
for _, plot := range line {
124+
r := region{id: plot.regionId, crop: plot.crop}
125+
p := result[r]
126+
p.area++
127+
for _, f := range []bool{plot.top, plot.bottom, plot.left, plot.right} {
128+
if f {
129+
p.perimeter++
99130
}
100131
}
132+
result[r] = p
101133
}
102-
i++
103134
}
104-
return details
135+
return result
105136
}

0 commit comments

Comments
 (0)