-
Notifications
You must be signed in to change notification settings - Fork 0
/
day8.go
183 lines (155 loc) · 3.82 KB
/
day8.go
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"time"
"github.com/japorito/merry/libxmas/toybag"
"github.com/japorito/merry/libxmas/xmas"
"github.com/spf13/cobra"
)
type tree struct {
height rune
visible bool
scenicScore int
}
func createForest(input [][]rune) [][]*tree {
rowCount := len(input)
rowLength := len(input[0])
trees := make([][]*tree, rowCount)
for rowNum, row := range input {
trees[rowNum] = make([]*tree, rowLength)
for colNum, height := range row {
trees[rowNum][colNum] = &tree{
height: height,
// outside edge always visible
visible: rowNum == 0 || colNum == 0 || colNum == (rowLength-1) || rowNum == (rowCount-1),
scenicScore: 1,
}
}
}
return trees
}
func determineVisibility(forest [][]*tree) [][]*tree {
rowCount := len(forest)
rowLength := len(forest[0])
// right-left
for _, row := range forest {
maxLeft, maxRight := '0', '0'
for colNum, tree := range row {
if tree.height > maxLeft {
maxLeft = tree.height
tree.visible = true
}
reverseTree := row[(rowLength-1)-colNum]
if reverseTree.height > maxRight {
maxRight = reverseTree.height
reverseTree.visible = true
}
}
}
// top-bottom
for i := 0; i < rowLength; i++ {
maxTop, maxBottom := '0', '0'
for rowNum := range forest {
tree := forest[rowNum][i]
reverseTree := forest[-1+rowCount-rowNum][i]
if tree.height > maxTop {
maxTop = tree.height
tree.visible = true
}
if reverseTree.height > maxBottom {
maxBottom = reverseTree.height
reverseTree.visible = true
}
}
}
return forest
}
func checkHeightBlocksView(forest [][]*tree, col, row int, height rune) bool {
treeHeight := forest[row][col].height
return treeHeight >= height
}
func calculateScenicScore(forest [][]*tree, col, row, cols, rows int) int {
if col == 0 || row == 0 || row == (rows-1) || col == (cols-1) {
return 0
}
height := forest[row][col].height
upCount, downCount, leftCount, rightCount := 0, 0, 0, 0
i := 0
for i = row - 1; i > 0; i-- {
if checkHeightBlocksView(forest, col, i, height) {
break
}
}
upCount = row - i
for i = row + 1; i < (rows - 1); i++ {
if checkHeightBlocksView(forest, col, i, height) {
break
}
}
downCount = i - row
for i = col - 1; i > 0; i-- {
if checkHeightBlocksView(forest, i, row, height) {
break
}
}
leftCount = col - i
for i = col + 1; i < (cols - 1); i++ {
if checkHeightBlocksView(forest, i, row, height) {
break
}
}
rightCount = i - col
return upCount * downCount * leftCount * rightCount
}
func findHighestScenicScore(forest [][]*tree) int {
rows, cols := len(forest), len(forest[0])
maxScore := -1
for row := range forest {
for col := range forest[row] {
score := calculateScenicScore(forest, col, row, cols, rows)
if score > maxScore {
maxScore = score
}
}
}
return maxScore
}
func countVisible(forest [][]*tree) int {
sum := 0
for _, row := range forest {
for _, tree := range row {
if tree.visible {
sum++
}
}
}
return sum
}
// day8Cmd represents the day8 command
var day8Cmd = &cobra.Command{
Use: "day8 path/to/input/file",
Short: "AoC Day 8",
Long: `Advent of Code Day 8: Treetop Tree House`,
Run: func(cmd *cobra.Command, args []string) {
if input := toybag.ReadToRuneSliceLines(args...); input != nil {
fmt.Printf("%d rows of trees read.\n", len(input))
defer xmas.PrintHolidayMessage(time.Now())
forest := createForest(input)
determineVisibility(forest)
if Parts.Has(1) {
fmt.Println("Part 1 running...")
fmt.Printf("Count of outwardly-visible trees in forest is **%d**.\n", countVisible(forest))
}
if Parts.Has(2) {
fmt.Println("Part 2 running...")
fmt.Printf("Top tree has Scenic Score: **%d**\n", findHighestScenicScore(forest))
}
}
},
}
func init() {
rootCmd.AddCommand(day8Cmd)
}