Created
December 11, 2020 18:11
-
-
Save humbhenri/c00fe72ffc18416ad2e682052f68aa9b to your computer and use it in GitHub Desktop.
advent of code 2020 problem 11 solution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"io/ioutil" | |
"log" | |
"reflect" | |
"strings" | |
) | |
type seatState int | |
type grid struct { | |
seats []seatState | |
columns, rows int | |
} | |
const ( | |
empty seatState = iota | |
occupied | |
floor | |
) | |
func seatRule(seat seatState, adjacents []seatState, maxOccupieds int) seatState { | |
occupieds := 0 | |
for _, s := range adjacents { | |
if s == occupied { | |
occupieds++ | |
} | |
} | |
if seat == empty && occupieds == 0 { | |
return occupied | |
} | |
if seat == occupied && occupieds >= maxOccupieds { | |
return empty | |
} | |
return seat | |
} | |
func seatRule1(seat seatState, adjacents []seatState) seatState { | |
return seatRule(seat, adjacents, 4) | |
} | |
func seatRule2(seat seatState, adjacents []seatState) seatState { | |
return seatRule(seat, adjacents, 5) | |
} | |
func parse(s string) grid { | |
var g grid | |
for i, rune := range s { | |
switch rune { | |
case 'L': | |
g.seats = append(g.seats, empty) | |
case '.': | |
g.seats = append(g.seats, floor) | |
case '#': | |
g.seats = append(g.seats, occupied) | |
case '\n': | |
if g.columns == 0 { | |
g.columns = i | |
} | |
} | |
} | |
g.rows = len(g.seats) / g.columns | |
return g | |
} | |
func (g grid) seat(x, y int) seatState { | |
return g.seats[x*g.columns+y] | |
} | |
func (g grid) setSeat(x, y int, s seatState) { | |
g.seats[x*g.columns+y] = s | |
} | |
func clamp(x, min, max int) int { | |
if x < min { | |
return min | |
} | |
if x > max { | |
return max | |
} | |
return x | |
} | |
func adjacents(g *grid, x, y int) []seatState { | |
var adjacents []seatState | |
for i := clamp(-1+x, 0, g.rows-1); i <= clamp(1+x, 0, g.rows-1); i++ { | |
for j := clamp(-1+y, 0, g.columns-1); j <= clamp(1+y, 0, g.columns-1); j++ { | |
if i == x && j == y { | |
continue | |
} | |
adjacents = append(adjacents, g.seat(i, j)) | |
} | |
} | |
return adjacents | |
} | |
func directions(g *grid, x, y int) []seatState { | |
var adjacents []seatState | |
for i := -1; i <= 1; i++ { | |
for j := -1; j <= 1; j++ { | |
if (i == 0 && j == 0) || (x+i < 0 || x+i >= g.rows || y+j < 0 || y+j >= g.columns) { | |
continue | |
} | |
_x := x + i | |
_y := y + j | |
for _x >= 0 && _x < g.rows && _y >= 0 && _y < g.columns && g.seat(_x, _y) == floor { | |
_x += i | |
_y += j | |
} | |
if _x >= 0 && _x < g.rows && _y >= 0 && _y < g.columns { | |
adjacents = append(adjacents, g.seat(_x, _y)) | |
} | |
} | |
} | |
return adjacents | |
} | |
type neighbours func(g *grid, x, y int) []seatState | |
type rule func(seat seatState, seats []seatState) seatState | |
func step(g *grid, rule rule, neighbours neighbours) { | |
var g2 grid | |
g2.seats = make([]seatState, len(g.seats)) | |
g2.rows = g.rows | |
g2.columns = g.columns | |
copy(g2.seats, g.seats) | |
for i := 0; i < g.rows; i++ { | |
for j := 0; j < g.columns; j++ { | |
newSeat := rule(g2.seat(i, j), neighbours(&g2, i, j)) | |
g.setSeat(i, j, newSeat) | |
} | |
} | |
} | |
func (g grid) String() string { | |
var b strings.Builder | |
for i := 0; i < g.rows; i++ { | |
for j := 0; j < g.columns; j++ { | |
var seat string | |
switch g.seat(i, j) { | |
case empty: | |
seat = "L" | |
case occupied: | |
seat = "#" | |
case floor: | |
seat = "." | |
} | |
fmt.Fprintf(&b, "%s", seat) | |
} | |
fmt.Fprintln(&b) | |
} | |
return b.String() | |
} | |
func loop(g *grid, rule rule, neighbours neighbours) { | |
for { | |
before := make([]seatState, len(g.seats)) | |
copy(before, g.seats) | |
step(g, rule, neighbours) | |
if reflect.DeepEqual(g.seats, before) { | |
break | |
} | |
} | |
} | |
func part1(input string) *grid { | |
g := parse(input) | |
loop(&g, seatRule1, adjacents) | |
return &g | |
} | |
func part2(input string) *grid { | |
g := parse(input) | |
loop(&g, seatRule2, directions) | |
return &g | |
} | |
func main() { | |
input, err := ioutil.ReadFile("i11") | |
if err != nil { | |
log.Fatal(err) | |
} | |
g := part2(string(input)) | |
occupieds := 0 | |
for _, seat := range g.seats { | |
if seat == occupied { | |
occupieds++ | |
} | |
} | |
fmt.Println(occupieds) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment