2018 Day 17 Complete!

This commit is contained in:
Brian Buller 2019-11-07 10:23:29 -06:00
parent f03772c578
commit 7a00e2f9cc
2 changed files with 208 additions and 179 deletions

View File

@ -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
}

200
2018/day17/map.go Normal file
View File

@ -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()
}
}