package main
import (
"bufio"
"fmt"
"os"
col "github.com/fatih/color"
)
func waitEnter() {
bufio.NewReader(os.Stdin).ReadBytes('\n')
}
var (
sandColor = col.New(col.FgRed)
clayColor = col.New(col.FgWhite)
fallingWaterColor = col.New(col.FgHiBlue)
stillWaterColor = col.New(col.FgBlue)
)
type Puzzle struct {
gridW, gridH int
gridSize int
grid []rune
ssY, seY int
}
func (p *Puzzle) AddVein(x1, y1, x2, y2 int) {
oldW, oldH := p.gridW, p.gridH
if x2+2 > p.gridW {
p.gridW = x2 + 2
}
if y2+2 > p.gridH {
p.gridH = y2 + 2
}
if y1 < p.ssY {
p.ssY = y1
}
if y2 > p.seY {
p.seY = y2
}
p.gridSize = p.gridW * p.gridH
if p.grid == nil {
p.grid = make([]rune, p.gridSize)
}
updated := make([]rune, p.gridSize)
for y := 0; y < p.gridH; y++ {
for x := 0; x < p.gridW; x++ {
i := (y * p.gridW) + x
if i == 500 {
updated[i] = '+'
continue
}
if x >= x1 && x <= x2 && y >= y1 && y <= y2 {
updated[i] = '#'
continue
}
if x < oldW && y < oldH {
j := (y * oldW) + x
updated[i] = p.grid[j]
continue
}
updated[i] = '.'
}
}
p.grid = updated
}
func (p *Puzzle) PrintState() {
for y := 0; y < p.gridH; y++ {
for x := 300; x < p.gridW; x++ {
/*if y == p.ssY {
fmt.Printf("%c", '-')
continue
}
if y == p.seY {
fmt.Printf("%c", '-')
continue
}*/
r := p.grid[(y*p.gridW)+x]
switch r {
case '.':
sandColor.Printf("%c", r)
case '#':
clayColor.Printf("%c", r)
case '+', '|', '/', '\\':
fallingWaterColor.Printf("%c", r)
case '~':
stillWaterColor.Printf("%c", r)
default:
fmt.Printf("%c", r)
}
}
fmt.Printf("\n")
}
}
func (p *Puzzle) flow(x, y int) bool {
for ; y < p.gridH; y++ {
i := (y * p.gridW) + x
r := p.grid[i]
switch r {
case '#', '~':
y--
i := (y * p.gridW)
var rend int
var rhole int
for ; x < p.gridW; x++ {
if p.grid[i+x] == '#' {
rend = x - 1
break
}
if p.grid[i+x] == '\\' && p.grid[i+x+p.gridW] == '~' {
p.grid[i+x] = '|'
return true
}
if p.grid[i+x] == '\\' || p.grid[i+x+p.gridW] == '.' {
rhole = x
break
}
if p.grid[i+x] == '.' {
p.grid[i+x] = '|'
return true
}
}
x--
var lend int
var lhole int
for ; x > 0; x-- {
if p.grid[i+x] == '#' {
lend = x + 1
break
}
if p.grid[i+x] == '/' && p.grid[i+x+p.gridW] == '~' {
p.grid[i+x] = '|'
return true
}
if p.grid[i+x] == '/' || p.grid[i+x+p.gridW] == '.' {
lhole = x
break
}
if p.grid[i+x] == '.' {
p.grid[i+x] = '|'
return true
}
}
if rhole > 0 || lhole > 0 {
if rhole > 0 {
p.grid[i+rhole] = '\\'
if p.flow(rhole, y+1) {
return true
}
}
if lhole > 0 {
p.grid[i+lhole] = '/'
if p.flow(lhole, y+1) {
return true
}
}
return false
}
for x = lend; x <= rend; x++ {
p.grid[i+x] = '~'
}
return true
case '.':
p.grid[i] = '|'
return true
}
}
return false
}
func abs(a int) int {
if a < 0 {
return a
}
return a
}
func (p *Puzzle) Sim() {
/*p.PrintState()
fmt.Printf("\n")*/
tick := 0
for p.flow(500, 0) {
//p.PrintState()
//fmt.Printf("\n")
//time.Sleep(100 * time.Millisecond)
//waitEnter()
fmt.Println(tick)
tick++
/*if tick > 1231 {
p.PrintState()
fmt.Printf("\n")
}*/
}
total := 0
atRest := 0
for y := p.ssY; y < p.seY+1; y++ {
for x := 0; x < p.gridW; x++ {
r := p.grid[(y*p.gridW)+x]
if r == '|' || r == '\\' || r == '/' || r == '~' {
total++
}
if r == '~' {
atRest++
}
}
}
p.PrintState()
fmt.Println("DONE")
fmt.Println("Total water:", total)
fmt.Println("Water at rest:", atRest)
}
func main() {
input, err := os.Open("input.txt")
if err != nil {
panic(err.Error())
}
defer input.Close()
scanner := bufio.NewScanner(input)
p := Puzzle{
ssY: 99999,
}
for scanner.Scan() {
var xs, xe, ys, ye int
fmt.Sscanf(scanner.Text(), "x=%d, y=%d..%d", &xs, &ys, &ye)
if xs == 0 && ys == 0 && ye == 0 {
fmt.Sscanf(scanner.Text(), "y=%d, x=%d..%d", &ys, &xs, &xe)
ye = ys
} else {
xe = xs
}
p.AddVein(xs, ys, xe, ye)
}
if err := scanner.Err(); err != nil {
panic(err.Error())
}
p.Sim()
}