2020, Day 11: Seating System
standard day with a grid. Highlights:
- a clean refactoring after part1 to solve part2
- ran into an expected issue when copying a sequence inside a proc (fixed with Orc, see: forum)
import
strutils, nimoji
when defined(gcOrc):
echo "using Orc :japanese_ogre:".emojize
using Orc 👹
First we parse and show the example grid.
type
SeatGridKind = enum
sgFloor = ".", sgEmpty = "L", sgOccupied = "#"
SeatGrid = object
data: seq[SeatGridKind]
ncols: int
let example = """L.LL.LL.LL
LLLLLLL.LL
L.L.L..L..
LLLL.LL.LL
L.LL.LL.LL
L.LLLLL.LL
..L.L.....
LLLLLLLLLL
L.LLLLLL.L
L.LLLLL.LL""".replace(
"\c", "")
proc parse(text: string): SeatGrid =
for i, c in text:
case c
of '.':
result.data.add sgFloor
of 'L':
result.data.add sgEmpty
of '\n':
if result.ncols == 0:
result.ncols = result.data.len
elif result.data.len mod result.ncols != 0:
echo "ERROR expect same number of columns ", i, " ", c
else:
echo "ERROR cannot parse ", i, " ", c
proc `$`(g: SeatGrid): string =
for i, d in g.data:
result.add:
case d
of sgFloor:
"."
of sgEmpty:
"L"
of sgOccupied:
"#"
if (i + 1) mod g.ncols == 0:
result.add "\n"
var exGrid = parse example
echo exGrid
func nrows(g: SeatGrid): int =
g.data.len div g.ncols
echo exGrid.nrows
L.LL.LL.LL LLLLLLL.LL L.L.L..L.. LLLL.LL.LL L.LL.LL.LL L.LLLLL.LL ..L.L..... LLLLLLLLLL L.LLLLLL.L L.LLLLL.LL 10
now we define a function to get adjacent indices. In part 2 we refactored this to use a dir
function:
when defined(part1):
iterator adjIdx(i: int; g: SeatGrid): int =
if i >= g.ncols:
yield i - g.ncols ## up
if i >= g.ncols and (i + 1) mod g.ncols != 0:
yield i - g.ncols + 1 ## up-right
if (i + 1) mod g.ncols != 0:
yield i + 1 ## right
if (i + 1) mod g.ncols != 0 and (i + g.ncols) < g.data.len:
yield i + g.ncols + 1 ## right-down
if (i + g.ncols) < g.data.len:
yield i + g.ncols ## down
if (i + g.ncols) < g.data.len and i mod g.ncols != 0:
yield i + g.ncols - 1 ## down-left
if i mod g.ncols != 0:
yield i - 1 ## left
if i mod g.ncols != 0 and i >= g.ncols:
yield i - g.ncols - 1 ## left-up
else:
type
Direction = enum
up, upright, right, rightdown, down, downleft, left, leftup
func dir(i: int; d: Direction; g: SeatGrid): (bool, int) =
result = (false, i)
case d
of up:
if i >= g.ncols:
result = (true, i - g.ncols) ## up
of upright:
if i >= g.ncols and (i + 1) mod g.ncols != 0:
result = (true, i - g.ncols + 1) ## up-right
of right:
if (i + 1) mod g.ncols != 0:
result = (true, i + 1) ## right
of rightdown:
if (i + 1) mod g.ncols != 0 and (i + g.ncols) < g.data.len:
result = (true, i + g.ncols + 1) ## right-down
of down:
if (i + g.ncols) < g.data.len:
result = (true, i + g.ncols) ## down
of downleft:
if (i + g.ncols) < g.data.len and i mod g.ncols != 0:
result = (true, i + g.ncols - 1) ## down-left
of left:
if i mod g.ncols != 0:
result = (true, i - 1) ## left
of leftup:
if i mod g.ncols != 0 and i >= g.ncols:
result = (true, i - g.ncols - 1) ## left-up
iterator adjIdx(i: int; g: SeatGrid): int =
var r = (false, 0)
for d in Direction:
r = dir(i, d, g)
if r[0]:
yield r[1]
for i in [0, 5, 9, 40, 45, 49, 90, 95, 99]:
echo "adjIdx ", i
for j in adjIdx(i, exGrid):
echo " ", j
adjIdx 0 1 11 10 adjIdx 5 6 16 15 14 4 adjIdx 9 19 18 8 adjIdx 40 30 31 41 51 50 adjIdx 45 35 36 46 56 55 54 44 34 adjIdx 49 39 59 58 48 38 adjIdx 90 80 81 91 adjIdx 95 85 86 96 94 84 adjIdx 99 89 98 88
a step
proc to solve part1. this is where I ran in the issue
proc step(g: var SeatGrid): int =
when defined(gcOrc):
let data = g.data ## snapshot of grid
else:
var data = g.data
var numOcc: int
for i in 0 .. g.data.high:
numOcc = 0
for j in adjIdx(i, g):
if data[j] == sgOccupied:
inc numOcc
if data[i] == sgEmpty and numOcc == 0:
g.data[i] = sgOccupied
inc result
elif data[i] == sgOccupied and numOcc >= 4:
g.data[i] = sgEmpty
inc result
func countOcc(g: SeatGrid): int =
for s in g.data:
if s == sgOccupied:
inc result
var i = 1
while step(exGrid) > 0:
echo "step: ", i
echo exGrid
inc i
echo "numOcc: ", countOcc(exGrid) ## 37
let input = "2020/input11.txt".readFile.replace("\c", "")
var inpGrid = parse input
echo (inpGrid.ncols, inpGrid.nrows)
i = 1
while step(inpGrid) > 0:
inc i
echo "stops at step: ", i ## 98
echo "numOcc: ", countOcc(inpGrid) ## 2334
step: 1 #.##.##.## #######.## #.#.#..#.. ####.##.## #.##.##.## #.#####.## ..#.#..... ########## #.######.# #.#####.## step: 2 #.LL.L#.## #LLLLLL.L# L.L.L..L.. #LLL.LL.L# #.LL.LL.LL #.LLLL#.## ..L.L..... #LLLLLLLL# #.LLLLLL.L #.#LLLL.## step: 3 #.##.L#.## #L###LL.L# L.#.#..#.. #L##.##.L# #.##.LL.LL #.###L#.## ..#.#..... #L######L# #.LL###L.L #.#L###.## step: 4 #.#L.L#.## #LLL#LL.L# L.L.L..#.. #LLL.##.L# #.LL.LL.LL #.LL#L#.## ..L.L..... #L#LLLL#L# #.LLLLLL.L #.#L#L#.## step: 5 #.#L.L#.## #LLL#LL.L# L.#.L..#.. #L##.##.L# #.#L.LL.LL #.#L#L#.## ..L.L..... #L#L##L#L# #.LLLLLL.L #.#L#L#.## numOcc: 37 (97, 92) stops at step: 98 numOcc: 2334
That's the right answer! You are one gold star closer to saving your vacation.
and a step2
proc to solve part2
when not defined(part1):
echo "\n---Part2---\n"
proc step2(g: var SeatGrid): int =
when defined(gcOrc):
let data = g.data ## snapshot of grid
else:
var data = g.data
var numOcc: int
var r = (false, 0)
for i in 0 .. g.data.high:
numOcc = 0
for d in Direction:
r = dir(i, d, g)
while r[0] and data[r[1]] == sgFloor:
r = dir(r[1], d, g)
if r[0] and data[r[1]] == sgOccupied:
inc numOcc
if data[i] == sgEmpty and numOcc == 0:
g.data[i] = sgOccupied
inc result
elif data[i] == sgOccupied and numOcc >= 5:
g.data[i] = sgEmpty
inc result
i = 1
exGrid = parse example
while step2(exGrid) > 0:
echo "step: ", i
echo exGrid
inc i
echo "numOcc: ", countOcc(exGrid) ## 26
inpGrid = parse input
i = 1
while step2(inpGrid) > 0:
inc i
echo "stops at step: ", i ## 86
echo "numOcc: ", countOcc(inpGrid) ## 2100
---Part2--- step: 1 #.##.##.## #######.## #.#.#..#.. ####.##.## #.##.##.## #.#####.## ..#.#..... ########## #.######.# #.#####.## step: 2 #.LL.LL.L# #LLLLLL.LL L.L.L..L.. LLLL.LL.LL L.LL.LL.LL L.LLLLL.LL ..L.L..... LLLLLLLLL# #.LLLLLL.L #.LLLLL.L# step: 3 #.L#.##.L# #L#####.LL L.#.#..#.. ##L#.##.## #.##.#L.## #.#####.#L ..#.#..... LLL####LL# #.L#####.L #.L####.L# step: 4 #.L#.L#.L# #LLLLLL.LL L.L.L..#.. ##LL.LL.L# L.LL.LL.L# #.LLLLL.LL ..L.L..... LLLLLLLLL# #.LLLLL#.L #.L#LL#.L# step: 5 #.L#.L#.L# #LLLLLL.LL L.L.L..#.. ##L#.#L.L# L.L#.#L.L# #.L####.LL ..#.#..... LLL###LLL# #.LLLLL#.L #.L#LL#.L# step: 6 #.L#.L#.L# #LLLLLL.LL L.L.L..#.. ##L#.#L.L# L.L#.LL.L# #.LLLL#.LL ..#.L..... LLL###LLL# #.LLLLL#.L #.L#LL#.L# numOcc: 26 stops at step: 86 numOcc: 2100
That's the right answer! You are one gold star closer to saving your vacation.