diff options
Diffstat (limited to 'day8.go')
| -rw-r--r-- | day8.go | 169 |
1 files changed, 169 insertions, 0 deletions
@@ -0,0 +1,169 @@ +// I'll come back later to this day +// +// The second part is bad with time O(n*(W+H)) -> could be better for sure like O(4n) +package main + +import ( + "bufio" + "fmt" + "log" + "os" +) + +type quadcopter struct { + scans []*scan +} + +// Scans all rows and columns, probably could be a bit better +func (q *quadcopter) scanMap(hmap [][]byte, xlen, ylen int) { + for i, row := range hmap { + q.scans[i] = NewScan(row) + } + for y := 0; y < ylen; y++ { + col := make([]byte, xlen) + for x := 0; x < xlen; x++ { + col[x] = hmap[x][y] + } + q.scans[xlen+y] = NewScan(col) + } +} + +func (q *quadcopter) countVisibleTrees(hmap [][]byte, xlen, ylen int) int { + // circumference + visible := 2 * (xlen - 1 + ylen - 1) + // inner rectangle + for x := 1; x < xlen-1; x++ { + for y := 1; y < ylen-1; y++ { + tree := hmap[x][y] + xv := q.scans[x].progressScan(tree) + yv := q.scans[xlen+y].progressScan(tree) + if xv { + visible += 1 + continue + } + if yv { + visible += 1 + continue + } + } + } + return visible +} + +type scan struct { + ahead []byte + visited byte +} + +func NewScan(trees []byte) *scan { + lastTree := len(trees) - 1 + s := scan{ + visited: trees[lastTree], + ahead: []byte{trees[lastTree]}, + } + // stop before tree[0], it's not in the scan technically + for j := lastTree - 1; j > 0; j-- { + if trees[j] >= s.visited { + s.visited = trees[j] + s.ahead = append(s.ahead, trees[j]) + } + } + s.visited = trees[0] + return &s +} + +func (s *scan) progressScan(tree byte) bool { + // tree was greatest in scan ahead + if tree == s.ahead[len(s.ahead)-1] { + // keep last tree + if len(s.ahead) > 1 { + s.ahead = s.ahead[:len(s.ahead)-1] + } + } + + if tree > s.visited { + s.visited = tree + return true + } + + if tree > s.ahead[len(s.ahead)-1] { + return true + } + return false +} + +// Could be less repetitive with closures? But go kind of sucks with iterators +func scenicScore(tree byte, hmap [][]byte, x, xlen, y, ylen int) int { + down := 0 + for i := x + 1; i < xlen; i++ { + other := hmap[i][y] + down = i - x + if other >= tree { + break + } + } + up := 0 + for i := x - 1; i > -1; i-- { + other := hmap[i][y] + up = x - i + if other >= tree { + break + } + } + left := 0 + for i := y + 1; i < ylen; i++ { + other := hmap[x][i] + left = i - y + if other >= tree { + break + } + } + right := 0 + for i := y - 1; i > -1; i-- { + other := hmap[x][i] + right = y - i + if other >= tree { + break + } + } + return up * down * left * right +} + +func main() { + // part 1 + f, err := os.Open("day8.txt") + if err != nil { + log.Fatal("Could not open file", err) + } + + xlen, ylen := 0, 0 + hmap := [][]byte{} + s := bufio.NewScanner(f) + for s.Scan() { + b := s.Bytes() + if ylen == 0 { + ylen = len(b) + } + bcopy := append([]byte(nil), b...) + hmap = append(hmap, bcopy) + xlen += 1 + } + q := &quadcopter{ + scans: make([]*scan, xlen+ylen), + } + q.scanMap(hmap, xlen, ylen) + vis := q.countVisibleTrees(hmap, xlen, ylen) + fmt.Println("Part 1:", vis) + + // part 2... meh not sure how to optimize this further? Each tree can have local best scenic score + runningScore := 0 + for x := 1; x < xlen-1; x++ { + for y := 1; y < ylen-1; y++ { + tree := hmap[x][y] + if s := scenicScore(tree, hmap, x, xlen, y, ylen); s > runningScore { + runningScore = s + } + } + } + fmt.Println("Part 2:", runningScore) +} |
