From 7a00e2f9ccd4427c6e8cc363071ce578b56fd6c5 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Thu, 7 Nov 2019 10:23:29 -0600 Subject: [PATCH] 2018 Day 17 Complete! --- 2018/day17/day17.go | 187 ++--------------------------------------- 2018/day17/map.go | 200 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+), 179 deletions(-) create mode 100644 2018/day17/map.go diff --git a/2018/day17/day17.go b/2018/day17/day17.go index 066c13f..24a3290 100644 --- a/2018/day17/day17.go +++ b/2018/day17/day17.go @@ -3,182 +3,20 @@ package main import ( "bufio" "fmt" - "log" "os" - "strconv" - "strings" - "time" -) - -const ( - MAX_INT = int(^uint(0) >> 1) - MIN_INT = -MAX_INT - 1 - CLEAR_SCREEN = "\033[H\033[2J" - DEBUG = true - SLOW_IT_DOWN = true - - FLOW_NO = iota - FLOW_D - FLOW_LR - FLOW_L - FLOW_R - FLOW_ERR ) func main() { - input := stdinToStringSlice() - part1(input) - //part2(input) + inp := StdinToStringSlice() + m := NewMap(inp) + m.Flood() + fmt.Println("# Part 1") + fmt.Printf("Water Spots: %d\n", m.Count(KindWater|KindFlow)) + fmt.Println("# Part 2") + fmt.Printf("Water Spots: %d\n", m.Count(KindWater)) } -var scan [2000][2000]byte -var minX, maxX int = MAX_INT, MIN_INT -var minY, maxY int = MAX_INT, MIN_INT - -func part1(input []string) { - for _, v := range input { - pts := strings.Split(v, ", ") - fst := strings.Split(pts[0], "=") - scd := strings.Split(pts[1], "=") - scdRange := strings.Split(scd[1], "..") - var x, y int - if fst[0] == "x" { - x = Atoi(fst[1]) - for y = Atoi(scdRange[0]); y <= Atoi(scdRange[1]); y++ { - if y < 50 && x > 450 && x < 550 { - minmax(x, y) - scan[x][y] = '#' - } - } - } else if fst[0] == "y" { - y = Atoi(fst[1]) - for x := Atoi(scdRange[0]); x <= Atoi(scdRange[1]); x++ { - if y < 50 && x > 450 && x < 550 { - minmax(x, y) - scan[x][y] = '#' - } - } - } - } - // The water starts at 500, 0 - for { - printScan() - if SLOW_IT_DOWN { - time.Sleep(time.Millisecond * 250) - } - if !fillSpot(500, 1) { - break - } - } - printScan() -} - -func part2(input []string) { -} - -func fillSpot(x, y int) bool { - if y > maxY { - return false - } else if !canFill(x, y) { - return false - } - - if scan[x][y] == 0 { - scan[x][y] = '|' - return true - } - - if canFill(x, y+1) { - return fillSpot(x, y+1) - } else if canFill(x-1, y) && canFill(x+1, y) { - return fillLeft(x-1, y) || fillRight(x+1, y) - } else if canFill(x-1, y) { - return fillLeft(x-1, y) - } else if canFill(x+1, y) { - return fillRight(x+1, y) - } - - scan[x][y] = '~' - return true -} - -func fillLeft(x, y int) bool { - if !canFill(x, y) { - return false - } - - if scan[x][y] == 0 { - scan[x][y] = '|' - return true - } - - if canFill(x, y+1) { - return fillSpot(x, y+1) - } else if canFill(x-1, y) { - return fillLeft(x-1, y) - } - - scan[x][y] = '~' - return true -} - -func fillRight(x, y int) bool { - if !canFill(x, y) { - return false - } - - if scan[x][y] == 0 { - scan[x][y] = '|' - return true - } - - if canFill(x, y+1) { - return fillSpot(x, y+1) - } else if canFill(x+1, y) { - return fillRight(x+1, y) - } - - scan[x][y] = '~' - return true -} - -func gud(x, y int) bool { - return x != MIN_INT && y != MIN_INT -} - -func printScan() { - fmt.Print(CLEAR_SCREEN) - for y := minY; y <= maxY; y++ { - for x := minX; x <= maxX; x++ { - if scan[x][y] == 0 { - fmt.Print(".") - } else { - fmt.Print(string(scan[x][y])) - } - } - fmt.Println() - } -} -func canFill(x, y int) bool { - return scan[x][y] == 0 || scan[x][y] == '|' -} - -func minmax(x, y int) { - if x < minX { - minX = x - } - if x > maxX { - maxX = x - } - if y < minY { - minY = y - } - if y > maxY { - maxY = y - } -} - -func stdinToStringSlice() []string { +func StdinToStringSlice() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { @@ -186,12 +24,3 @@ func stdinToStringSlice() []string { } return input } - -func Atoi(i string) int { - var ret int - var err error - if ret, err = strconv.Atoi(i); err != nil { - log.Fatal("Invalid Atoi: " + i) - } - return ret -} diff --git a/2018/day17/map.go b/2018/day17/map.go new file mode 100644 index 0000000..95d8758 --- /dev/null +++ b/2018/day17/map.go @@ -0,0 +1,200 @@ +package main + +import ( + "fmt" + "math" +) + +const ( + springX = 500 + springY = 0 +) +const ( + KindSand = 1 << iota + KindClay + KindWater + KindFlow + KindSpring + NumKinds +) + +var KindRunes = [NumKinds]rune{ + KindSand: '.', + KindClay: '#', + KindWater: '~', + KindFlow: '|', + KindSpring: '+', +} + +type Map struct { + data map[int]map[int]int + minX int + minY int + maxX int + maxY int + done bool + changed bool +} + +func (m *Map) Set(kind, x, y int) { + if m.data[y] == nil { + m.data[y] = make(map[int]int) + } + if m.data[y][x] != kind { + m.data[y][x] = kind + m.changed = true + } + if x < m.minX { + m.minX = x + } + if x > m.maxX { + m.maxX = x + } +} + +func (m *Map) Get(x, y int) int { + if m.data[y] == nil { + return KindSand + } + if k, ok := m.data[y][x]; ok { + return k + } + return KindSand +} + +func (m *Map) ParseInput(input []string) { + m.minY = math.MaxInt32 + m.maxY = 0 + m.minX = math.MaxInt32 + m.maxX = 0 + + m.Set(KindSpring, springX, springY) + + for _, line := range input { + var a, b rune + var posA, startB, endB int + _, err := fmt.Sscanf(line, "%c=%d, %c=%d..%d", &a, &posA, &b, &startB, &endB) + if err != nil { + panic(err) + } + if a == 'x' { + for y := startB; y <= endB; y++ { + m.Set(KindClay, posA, y) + } + if posA < m.minX { + m.minX = posA + } + if posA > m.maxX { + m.maxX = posA + } + if startB < m.minY { + m.minY = startB + } + if endB > m.maxY { + m.maxY = endB + } + } else { + for x := startB; x <= endB; x++ { + m.Set(KindClay, x, posA) + } + if posA < m.minY { + m.minY = posA + } + if posA > m.maxY { + m.maxY = posA + } + if startB < m.minX { + m.minX = startB + } + if endB > m.maxX { + m.maxX = endB + } + } + } +} + +func (m *Map) Print() { + for y := 0; y <= m.maxY; y++ { + for x := m.minX; x <= m.maxX; x++ { + fmt.Printf("%c", KindRunes[m.Get(x, y)]) + } + fmt.Println() + } +} + +func (m *Map) Count(mask int) int { + var sum int + for y := m.minY; y <= m.maxY; y++ { + for x := m.minX; x <= m.maxX; x++ { + if m.Get(x, y)&mask != 0 { + sum++ + } + } + } + return sum +} + +func NewMap(input []string) *Map { + m := &Map{} + m.data = make(map[int]map[int]int) + m.ParseInput(input) + return m +} + +type Coordinate struct { + X int + Y int +} + +func (m *Map) Tick() { + m.changed = false + for y := 0; y <= m.maxY; y++ { + for x := m.minX; x <= m.maxX; x++ { + switch m.Get(x, y) { + case KindSpring, KindFlow: + switch m.Get(x, y+1) { + case KindSand: + m.Set(KindFlow, x, y+1) + case KindClay, KindWater: + m.HorizontalFlow(x, y, -1) + m.HorizontalFlow(x, y, +1) + } + case KindClay: + m.HorizontalSettle(x+1, y, +1) + } + } + } + m.done = !m.changed +} + +func (m *Map) HorizontalSettle(x, y, dir int) bool { + if m.Get(x, y) != KindFlow { + return false + } + switch m.Get(x+dir, y) { + case KindClay, KindWater: + if m.Get(x, y+1)&(KindClay|KindWater) != 0 { + m.Set(KindWater, x, y) + return true + } + case KindFlow: + if m.HorizontalSettle(x+dir, y, dir) && m.Get(x, y+1)&(KindClay|KindWater) != 0 { + m.Set(KindWater, x, y) + return true + } + } + return false +} + +func (m *Map) HorizontalFlow(x, y, dir int) { + if m.Get(x+dir, y) == KindSand && m.Get(x, y+1)&(KindClay|KindWater) != 0 { + m.Set(KindFlow, x+dir, y) + m.HorizontalFlow(x+dir, y, dir) + } +} + +func (m *Map) Flood() { + for !m.done { + m.Tick() + } +}