2018 Day 17 Complete!
This commit is contained in:
parent
f03772c578
commit
7a00e2f9cc
@ -3,182 +3,20 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"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() {
|
func main() {
|
||||||
input := stdinToStringSlice()
|
inp := StdinToStringSlice()
|
||||||
part1(input)
|
m := NewMap(inp)
|
||||||
//part2(input)
|
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
|
func StdinToStringSlice() []string {
|
||||||
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 {
|
|
||||||
var input []string
|
var input []string
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
@ -186,12 +24,3 @@ func stdinToStringSlice() []string {
|
|||||||
}
|
}
|
||||||
return input
|
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
200
2018/day17/map.go
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user