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