Pouring sand

advent day 14

Kind of cool because running the code you can visualize dripping sand across an obstacle course.

package problems

import (
	"fmt"
	"strings"

	"github.com/sooflee/advent/internal"
)

type day14 struct {
	lines []string
}

func Day14(part int, file string) int {

	in := day14{
		lines: internal.Read(file),
	}

	switch part {
	case 1:
		return in.part_one()
	case 2:
		return in.part_two()
	default:
		return 0
	}

}

func create_cavern(lines []string, part2 bool) ([][]string, int, int) {

	sequences := [][]coordinate{}
	max_x := 0
	max_y := 0

	for _, line := range lines {
		sequence := []coordinate{}
		for _, coordinate_str := range strings.Split(line, "->") {
			coordinates := strings.Split(coordinate_str, ",")
			x := internal.StrToInt(coordinates[0])
			y := internal.StrToInt(coordinates[1])
			sequence = append(sequence, coordinate{x, y})

			if x > max_x {
				max_x = x
			}

			if y > max_y {
				max_y = y
			}
		}
		sequences = append(sequences, sequence)
	}

	if part2 {
		max_y = max_y + 2
		max_x = max_x + max_x
	}

	cavern := make([][]string, max_y+1)
	for i := range cavern {
		cavern_row := make([]string, max_x+1)
		for j := range cavern_row {
			cavern_row[j] = "."
		}
		cavern[i] = cavern_row
	}

	if part2 {
		cavern_row := make([]string, max_x+1)
		for j := range cavern_row {
			cavern_row[j] = "#"
		}
		cavern[max_y] = cavern_row
	}

	for _, sequence := range sequences {
		last_c := coordinate{}
		for i, c := range sequence {
			cavern[c.y][c.x] = "#"
			if i != 0 {
				if last_c.x < c.x {
					for x := last_c.x; x <= c.x; x++ {
						cavern[c.y][x] = "#"
					}
				} else if last_c.x > c.x {
					for x := last_c.x; x >= c.x; x-- {
						cavern[c.y][x] = "#"
					}
				} else if last_c.y < c.y {
					for y := last_c.y; y <= c.y; y++ {
						cavern[y][c.x] = "#"
					}
				} else if last_c.y > c.y {
					for y := last_c.y; y >= c.y; y-- {
						cavern[y][c.x] = "#"
					}
				}
			}
			last_c = coordinate{c.x, c.y}
		}
	}

	return cavern, max_x, max_y
}

func draw_cavern(cavern [][]string) {
	for i, cavern_row := range cavern {
		fmt.Println(i, cavern_row)
	}
}

func (input day14) part_one() int {

	cavern, max_x, max_y := create_cavern(input.lines, false)

	sand_count := 0

	for {
		sand_count++
		sand_x := 500
		sand_y := 0

		for {

			if sand_y == max_y || sand_x == max_x {
				break
			}

			if cavern[sand_y+1][sand_x] == "." {
				sand_y++
			} else if cavern[sand_y+1][sand_x-1] == "." {
				sand_x--
				sand_y++
			} else if cavern[sand_y+1][sand_x+1] == "." {
				sand_x++
				sand_y++
			} else {
				break
			}
		}

		if sand_y >= max_y || sand_x >= max_x {
			break
		}

		draw_cavern(cavern)

		if sand_y >= max_y {
			break
		}
		cavern[sand_y][sand_x] = "o"
	}

	return sand_count - 1
}

func (input day14) part_two() int {
	cavern, max_x, max_y := create_cavern(input.lines, true)

	sand_count := 0

	for {
		sand_count++
		sand_x := 500
		sand_y := 0
		not_move := true

		for {

			if sand_y == max_y || sand_x == max_x {
				break
			}

			if cavern[sand_y+1][sand_x] == "." {
				sand_y++
				not_move = false
			} else if cavern[sand_y+1][sand_x-1] == "." {
				sand_x--
				sand_y++
				not_move = false
			} else if cavern[sand_y+1][sand_x+1] == "." {
				sand_x++
				sand_y++
				not_move = false
			} else {
				break
			}
		}

		// if sand_count%50 == 0 {
		// 	draw_cavern(cavern)
		// }

		if not_move {
			break
		}

		if sand_y >= max_y {
			break
		}
		cavern[sand_y][sand_x] = "o"
	}

	return sand_count
}