123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- package main
- import (
- "bufio"
- "fmt"
- "log"
- "os"
- "strings"
- )
- type point struct {
- x int
- y int
- }
- func readPoints(line string) []point {
- parts := strings.Split(line, " -> ")
- if len(parts) == 0 {
- log.Fatal("Wrong input:", line)
- }
- var points []point
- for i := range parts {
- var current point
- n, err := fmt.Sscanf(parts[i], "%d,%d", ¤t.x, ¤t.y)
- if n != 2 || err != nil {
- log.Fatal("Can't parse", line, err)
- }
- points = append(points, current)
- }
- return points
- }
- func readInput(file *os.File) [][]point {
- scanner := bufio.NewScanner(file)
- var points [][]point
- for scanner.Scan() {
- line := scanner.Text()
- if line == "" {
- continue
- }
- points = append(points, readPoints(line))
- }
- return points
- }
- func drawHorizontal(first point, second point, rocks map[point]bool) {
- start := first.x
- end := second.x
- if start > second.x {
- start = second.x
- end = first.x
- }
- for i := start + 1; i < end; i++ {
- rocks[point{i, first.y}] = true
- }
- }
- func drawVertical(first point, second point, rocks map[point]bool) {
- start := first.y
- end := second.y
- if start > second.y {
- start = second.y
- end = first.y
- }
- for i := start + 1; i < end; i++ {
- rocks[point{first.x, i}] = true
- }
- }
- func drawPath(first point, second point, rocks map[point]bool) {
- if first.x == second.x {
- drawVertical(first, second, rocks)
- } else {
- drawHorizontal(first, second, rocks)
- }
- }
- func buildRocks(points [][]point) (map[point]bool, int) {
- rocks := make(map[point]bool)
- bottom := 0
- for i := range points {
- edge := len(points[i])
- prev := points[i][0]
- rocks[prev] = true
- if prev.y > bottom {
- bottom = prev.y
- }
- for j := 1; j < edge; j++ {
- current := points[i][j]
- rocks[current] = true
- if current.y > bottom {
- bottom = current.y
- }
- drawPath(prev, current, rocks)
- prev = current
- }
- }
- return rocks, bottom
- }
- func moveUnit(unit point, rocks map[point]bool) point {
- current := point{unit.x, unit.y + 1}
- if !rocks[current] {
- return current
- }
- current.x--
- if !rocks[current] {
- return current
- }
- current.x += 2
- if !rocks[current] {
- return current
- }
- return unit
- }
- func fall(unit point, rocks map[point]bool, bottom int) bool {
- for {
- current := moveUnit(unit, rocks)
- if current.x == unit.x && current.y == unit.y {
- rocks[current] = true
- break
- }
- if current.y > bottom {
- return true
- }
- unit = current
- }
- return false
- }
- func fall2(unit point, rocks map[point]bool, bottom int) bool {
- for {
- current := moveUnit(unit, rocks)
- if current.x == 500 && current.y == 0 {
- rocks[current] = true
- return true
- }
- if current.x == unit.x && current.y == unit.y || current.y == bottom {
- rocks[current] = true
- break
- }
- unit = current
- }
- return false
- }
- func sandstorm(rocks map[point]bool, bottom int, fall func(point, map[point]bool, int) bool) int {
- initialRocks := len(rocks)
- currentRocks := initialRocks
- for {
- if fall(point{500, 0}, rocks, bottom) {
- break
- }
- if len(rocks) == currentRocks {
- break
- }
- currentRocks = len(rocks)
- }
- return len(rocks) - initialRocks
- }
- func main() {
- if len(os.Args) < 2 {
- log.Fatal("You need to specify a file!")
- }
- filePath := os.Args[1]
- file, err := os.Open(filePath)
- if err != nil {
- log.Fatalf("Failed to open %s!\n", filePath)
- }
- points := readInput(file)
- rocks, bottom := buildRocks(points)
- fmt.Println("Part1:", sandstorm(rocks, bottom, fall))
- rocks, bottom = buildRocks(points)
- fmt.Println("Part2:", sandstorm(rocks, bottom+1, fall2))
- }
|