advent-of-code

Perserverance, or the lack thereof

git clone git://git.shimmy1996.com/advent-of-code.git

main.go (2604B)

    1 package main
    2 
    3 import (
    4 	"bufio"
    5 	"fmt"
    6 	"os"
    7 )
    8 
    9 const (
   10 	FLOOR    = '.'
   11 	EMPTY    = 'L'
   12 	OCCUPIED = '#'
   13 )
   14 
   15 type seats struct {
   16 	width  int
   17 	height int
   18 	v      []rune
   19 }
   20 
   21 func (this *seats) val(x, y int) rune {
   22 	return this.v[x*this.width+y]
   23 }
   24 
   25 func (this *seats) valChecked(x, y int) (rune, bool) {
   26 	if x >= 0 && x < this.height && y >= 0 && y < this.width {
   27 		return this.v[x*this.width+y], true
   28 	} else {
   29 		return 0, false
   30 	}
   31 }
   32 
   33 func (this *seats) set(x, y int, val rune) {
   34 	this.v[x*this.width+y] = val
   35 }
   36 
   37 func (this seats) copy() seats {
   38 	return seats{this.width, this.height, append([]rune(nil), this.v...)}
   39 }
   40 
   41 func readInput(filename string) (res seats) {
   42 	file, _ := os.Open(filename)
   43 	defer file.Close()
   44 	scanner := bufio.NewScanner(file)
   45 	for scanner.Scan() {
   46 		row := scanner.Text()
   47 		res.height += 1
   48 		res.width = len(row)
   49 		for _, ch := range row {
   50 			res.v = append(res.v, ch)
   51 		}
   52 	}
   53 	return
   54 }
   55 
   56 func main() {
   57 	input := readInput("./input.txt")
   58 	// 2281
   59 	fmt.Println(part(input, update1))
   60 	// 2085
   61 	fmt.Println(part(input, update2))
   62 }
   63 
   64 func update1(input seats, x, y int) rune {
   65 	old := input.val(x, y)
   66 	if old == FLOOR {
   67 		return FLOOR
   68 	}
   69 	dx := []int{-1, +0, +1, -1, +1, -1, +0, +1}
   70 	dy := []int{-1, -1, -1, +0, +0, +1, +1, +1}
   71 	occCount := 0
   72 	for i := 0; i < len(dx); i++ {
   73 		val, ok := input.valChecked(x+dx[i], y+dy[i])
   74 		if ok && val == OCCUPIED {
   75 			occCount += 1
   76 		}
   77 	}
   78 	if old == EMPTY && occCount == 0 {
   79 		return OCCUPIED
   80 	}
   81 	if old == OCCUPIED && occCount >= 4 {
   82 		return EMPTY
   83 	}
   84 	return old
   85 }
   86 
   87 func update2(input seats, x, y int) rune {
   88 	old := input.val(x, y)
   89 	if old == FLOOR {
   90 		return FLOOR
   91 	}
   92 	dx := []int{-1, +0, +1, -1, +1, -1, +0, +1}
   93 	dy := []int{-1, -1, -1, +0, +0, +1, +1, +1}
   94 	occCount := 0
   95 	for i := 0; i < len(dx); i++ {
   96 		xNew, yNew := x, y
   97 		for val, ok := FLOOR, true; ok; val, ok = input.valChecked(xNew, yNew) {
   98 			if val == FLOOR {
   99 				xNew += dx[i]
  100 				yNew += dy[i]
  101 			} else {
  102 				if val == OCCUPIED {
  103 					occCount += 1
  104 				}
  105 				break
  106 			}
  107 		}
  108 	}
  109 	if old == EMPTY && occCount == 0 {
  110 		return OCCUPIED
  111 	}
  112 	if old == OCCUPIED && occCount >= 5 {
  113 		return EMPTY
  114 	}
  115 	return old
  116 }
  117 
  118 func part(input seats, updater func(seats, int, int) rune) (occCount int) {
  119 	curr := input.copy()
  120 	next := input.copy()
  121 	for updated := true; updated; {
  122 		updated = false
  123 		for x := 0; x < curr.height; x++ {
  124 			for y := 0; y < curr.width; y++ {
  125 				old := next.val(x, y)
  126 				next.set(x, y, updater(curr, x, y))
  127 				updated = updated || old != next.val(x, y)
  128 			}
  129 		}
  130 		curr, next = next, curr
  131 	}
  132 	for _, v := range curr.v {
  133 		if v == OCCUPIED {
  134 			occCount += 1
  135 		}
  136 	}
  137 	return
  138 }