Advent of Code 2020 Day 11

Author

Nathan Moore

— Day 11: Seating System —

You have to find the best to sit on the ferry and of course there are some complicated rules about where to sit and how people are going to move.

Simulate your seating area by applying the seating rules repeatedly until no seats change state. How many seats end up occupied?

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.6
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.1     ✔ tibble    3.3.0
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.2.0     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# read
seats_map <- read.delim("data-2020-11.txt", header = FALSE)

# length of character
xx <- nrow(seats_map)
yy <- nchar(seats_map$V1[[1]])

# separators for columns
w = rep(1, yy)

# read into matrix for nice indexing
seat_map <- read.fwf("data-2020-11.txt", 
                     widths = w, 
                     header = FALSE) %>% 
            as.matrix()
Warning in readLines(file, n = thisblock): incomplete final line found on
'data-2020-11.txt'

Create some functions for filling and emptying seats

fill_seats <- function(seats) { 
  seat_copy = seats
  change = 0
  for (x in seq_len(xx)) {
    for (y in seq_len(yy)) { 
      if (seat_set[x, y] == TRUE) {
        # pass
        # we don't need to check these again
      } else if (seats[x,y] == ".") {
        # pass
        # the floor does not change
      } else if (seats[x,y] == "L") { 
        # st_cnt <- count_adjacent(seat_copy, x, y)
        st_cnt <- count_visible(seat_copy, x, y)
        if (st_cnt == 0) {
          seats[x,y] = "#"
          change = change + 1
        } else {
          seat_set[x, y] <<- TRUE
        }
      } else {
        # pass
        # already # 
      }
    }
  }
  change_count <<- change
  return(seats)
}

empty_seats <- function(seats, lim) {
  seat_copy = seats
  change = 0
  for (x in seq_len(xx)) {
    for (y in seq_len(yy)) { 
      if (seat_set[x, y] == TRUE) {
        # pass
      } else if (seats[x, y] == ".") {
        # pass
      } else if (seats[x, y] == "#") { 
        # st_cnt <- count_adjacent(seat_copy, x, y)
        st_cnt <- count_visible(seat_copy, x, y)
        if (st_cnt >= lim) {
          seats[x, y] = "L"
          change = change + 1
        } else {
          seat_set[x, y] <<- TRUE
        }
      } else {
        # pass
        # already L
      }
    }
  }
  change_count <<- change
  return(seats)  
}

# part one assessment
count_adjacent <- function(sub_seat, x, y) {
  cnt = 0
  j1 = max(1,x-1)
  j2 = min(xx,x+1)
  k1 = max(1,y-1)
  k2 = min(yy,y+1)
  for (j in seq(j1,j2)) {
    for (k in seq(k1,k2)) {
      if (j == x & k == y) {
        # pass
      } else if (sub_seat[j,k] == "#") {
        cnt = cnt + 1
      }
    }
  }
  return(cnt)
}

# part two assessment
count_visible <- function(st_vis, x, y) {
  cnt = 0
  #       N  NE  E SE  S  SW   W  NW
  jj = c(-1, -1, 0, 1, 1,  1,  0, -1)
  kk = c( 0,  1, 1, 1, 0, -1, -1, -1)
  
  for (dir in seq(1,8)) {
    # reset variables for another search
    j = x
    k = y
    found = FALSE
    # loop while we are still looking
    while (found == FALSE) {
      j = j + jj[dir]
      k = k + kk[dir]
      if ((1 <= j) & (j <= xx) & (1 <= k) & (k <= yy)) {
        if (st_vis[j,k] == "#") {
          cnt = cnt + 1
          break
        } else if (st_vis[j,k] == "L") {
          # found an unoccupied seat 
          break
        }
      } else {
        found = TRUE
        # off the edge of the ferry
      }
    }
  }
  return(cnt)
}

Use these functions

# 
# # tracking for easier testing
# seat_set <- matrix(FALSE, nrow = xx, ncol = yy)
# 
# # manually test the functions
# seats1 <- fill_seats(seat_map)
# seats2 <- empty_seats(seats1, 4)
# seats3 <- fill_seats(seats2)
# seats4 <- empty_seats(seats3, 4)
# 
# seat_set <- matrix(FALSE, nrow = xx, ncol = yy)
# change_count <- 1
# loop_seats <- seat_map
# 
# while (change_count > 0) {
#   print(change_count)
#   loop_seats <- fill_seats(loop_seats)
#   loop_seats <- empty_seats(loop_seats, 4)
# }
# 
# seats_fill <- 0
# 
# for (x in seq_len(xx)) {
#   for (y in seq_len(yy)) { 
#     if (loop_seats[x,y] == "#") {
#       seats_fill = seats_fill + 1
#     }
#   }
# }

— Part Two —

New problem with different parameters - what can you see, rather than who is next to you.

Given the new visibility method and the rule change for occupied seats becoming empty, once equilibrium is reached, how many seats end up occupied?

# 
# # tracking for easier testing
# seat_set <- matrix(FALSE, nrow = xx, ncol = yy)
# 
# # manually test the functions
# seats1 <- fill_seats(seat_map)
# seats2 <- empty_seats(seats1, 5)
# seats3 <- fill_seats(seats2)
# seats4 <- empty_seats(seats3, 5)
# 
# seat_set <- matrix(FALSE, nrow = xx, ncol = yy)
# change_count <- 1
# loop_seats <- seat_map
# 
# while (change_count > 0) {
#   print(change_count)
#   loop_seats <- fill_seats(loop_seats)
#   loop_seats <- empty_seats(loop_seats, 5)
# }
# 
# seats_fill <- 0
# 
# for (x in seq_len(xx)) {
#   for (y in seq_len(yy)) { 
#     if (loop_seats[x,y] == "#") {
#       seats_fill = seats_fill + 1
#     }
#   }
# }