2018 Day 17 Complete!
This commit is contained in:
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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user