2022 Day 14 Complete!
This commit is contained in:
180
2022/day14/main.go
Normal file
180
2022/day14/main.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
var debug bool
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToStringSlice()
|
||||
part1(inp)
|
||||
part2(inp)
|
||||
}
|
||||
|
||||
func Check(spot h.Coordinate, walls, sand *h.CoordByteMap) byte {
|
||||
if v := walls.Get(spot); v != 0 {
|
||||
return v
|
||||
}
|
||||
return sand.Get(spot)
|
||||
}
|
||||
|
||||
func part1(inp []string) {
|
||||
m := BuildMap(inp)
|
||||
// Now start dropping sand
|
||||
var err error
|
||||
for err == nil {
|
||||
entry := &h.Coordinate{X: 500, Y: 0}
|
||||
err = Drop(entry, m)
|
||||
if err != nil {
|
||||
} else {
|
||||
m.Put(*entry, 'o')
|
||||
}
|
||||
}
|
||||
fmt.Println("# Part 1")
|
||||
fmt.Println(m.Count('o'), "grains of sand")
|
||||
}
|
||||
|
||||
// Drop 'grain' into the field described by 'walls', and 'sand'
|
||||
// It returns the path that it took
|
||||
// If it flows off the map, error is returned
|
||||
func Drop(grain *h.Coordinate, m *h.CoordByteMap) error {
|
||||
var path []h.Coordinate
|
||||
prevX, prevY := grain.X, grain.Y
|
||||
for {
|
||||
if grain.South().Y > m.BRY {
|
||||
return errors.New("Overflow")
|
||||
} else if m.Get(grain.South()) == 0 {
|
||||
path = append(path, grain.South())
|
||||
grain.MoveSouth()
|
||||
} else if m.Get(grain.SW()) == 0 {
|
||||
path = append(path, grain.SW())
|
||||
grain.MoveSW()
|
||||
} else if m.Get(grain.SE()) == 0 {
|
||||
path = append(path, grain.SE())
|
||||
grain.MoveSE()
|
||||
}
|
||||
if debug {
|
||||
fmt.Println(h.CLEAR_SCREEN)
|
||||
m.Put(*grain, 'o')
|
||||
fmt.Println(m)
|
||||
m.Delete(*grain)
|
||||
time.Sleep(time.Second / 100)
|
||||
}
|
||||
// Grain didn't move, must be at rest
|
||||
if grain.X == prevX && grain.Y == prevY {
|
||||
return nil
|
||||
}
|
||||
prevX, prevY = grain.X, grain.Y
|
||||
}
|
||||
}
|
||||
|
||||
func part2(inp []string) {
|
||||
m := BuildMap(inp)
|
||||
m.BRY += 1
|
||||
// Now start dropping sand
|
||||
var err error
|
||||
for err == nil {
|
||||
entry := &h.Coordinate{X: 500, Y: 0}
|
||||
err = Drop2(entry, m)
|
||||
m.Put(*entry, 'o')
|
||||
}
|
||||
fmt.Println("# Part 2")
|
||||
fmt.Println(m.Count('o'), "grains of sand")
|
||||
}
|
||||
func Drop2(grain *h.Coordinate, m *h.CoordByteMap) error {
|
||||
var path []h.Coordinate
|
||||
prevX, prevY := grain.X, grain.Y
|
||||
var moved bool
|
||||
for {
|
||||
if grain.Y == m.BRY {
|
||||
return nil
|
||||
}
|
||||
if m.Get(grain.South()) == 0 {
|
||||
path = append(path, grain.South())
|
||||
grain.MoveSouth()
|
||||
moved = true
|
||||
} else if m.Get(grain.SW()) == 0 {
|
||||
path = append(path, grain.SW())
|
||||
grain.MoveSW()
|
||||
moved = true
|
||||
} else if m.Get(grain.SE()) == 0 {
|
||||
path = append(path, grain.SE())
|
||||
grain.MoveSE()
|
||||
moved = true
|
||||
}
|
||||
if debug {
|
||||
fmt.Println(h.CLEAR_SCREEN)
|
||||
m.Put(*grain, 'o')
|
||||
fmt.Println(m)
|
||||
m.Delete(*grain)
|
||||
time.Sleep(time.Second / 100)
|
||||
}
|
||||
if grain.X == prevX && grain.Y == prevY {
|
||||
// Grain didn't move, must be at rest
|
||||
if !moved {
|
||||
return errors.New("Full")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
prevX, prevY = grain.X, grain.Y
|
||||
}
|
||||
}
|
||||
|
||||
func BuildMap(inp []string) *h.CoordByteMap {
|
||||
m := h.NewCoordByteMap()
|
||||
m.TLY = 0
|
||||
m.StringEmptyIsSpace = true
|
||||
m.StringEmptyByte = '.'
|
||||
for i := range inp {
|
||||
var start, end *h.Coordinate
|
||||
pts := strings.Split(inp[i], " -> ")
|
||||
for j := range pts {
|
||||
if start == nil {
|
||||
start = h.CoordinateFromString(pts[j])
|
||||
} else if end == nil {
|
||||
end = h.CoordinateFromString(pts[j])
|
||||
}
|
||||
if start != nil && end != nil {
|
||||
puts := GetLine(start, end)
|
||||
for _, coord := range puts {
|
||||
m.Put(*coord, '#')
|
||||
}
|
||||
start, end = end, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return &m
|
||||
}
|
||||
|
||||
func GetLine(c1, c2 *h.Coordinate) []*h.Coordinate {
|
||||
var ret []*h.Coordinate
|
||||
if c1.X == c2.X {
|
||||
if c1.Y < c2.Y {
|
||||
for y := c1.Y; y <= c2.Y; y++ {
|
||||
ret = append(ret, &h.Coordinate{X: c1.X, Y: y})
|
||||
}
|
||||
return ret
|
||||
} else if c1.Y > c2.Y {
|
||||
for y := c2.Y; y <= c1.Y; y++ {
|
||||
ret = append(ret, &h.Coordinate{X: c1.X, Y: y})
|
||||
}
|
||||
}
|
||||
} else if c1.Y == c2.Y {
|
||||
if c1.X < c2.X {
|
||||
for x := c1.X; x <= c2.X; x++ {
|
||||
ret = append(ret, &h.Coordinate{X: x, Y: c1.Y})
|
||||
}
|
||||
} else if c1.X > c2.X {
|
||||
for x := c2.X; x <= c1.X; x++ {
|
||||
ret = append(ret, &h.Coordinate{X: x, Y: c1.Y})
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user