AoC2020 Days 5 to 7

2020-12-07

Days 5 and 6 were pretty uneventful, still relatively easy; the first one solvable trivially by transforming the input into a binary sequence and translating it into an integer, the second one needed to be carefully parsed but once done was solved just by applying table to it, so nothing unsurmontable. Day 7 however was a notch more complicated, in that it needed recursion, which is always an head-scratcher.

Technically it was reminiscent from day 14 of last year but simpler: the input consisted of sentences like "light red bags contain 1 bright white bag, 2 muted yellow bags." and "faded blue bags contain no other bags." and one needed to figure out how many bags a "shiny gold" bag contained, which necessited to go through the whole "reaction" path (i. e. a=2b+4c; c=3d+4b; etc.). For the parser I used the same method as for day 2 (i. e. parse.one) and then, lazily, use an operator that is normally a no-go in R: repeat. I am sure there would have been more elegant ways to do the job, but at least it worked and was fairly fast.

input <- readLines("input07.txt")
res <- lapply(input,parse_reac) #parse_reac is the parser I made, check out in the github repo to read it. It's fairly tedious though.
# res is the parsed input, each element contains:
# an element "a" that is the containing color,
# "b" a dataframe of what is contained in "a", where n is the number of bags and col their color.
# If the bag contains no other bags, b is NULL.
step <- res[sapply(res,function(x)x$a=="shiny gold")][[1]]$b # I know it's ugly: go through all elements and return dataframe b if a is he color we need
step$n <- as.integer(step$n) # Why didn't I made the parser converts that to integer directly, i'll never know
step$end <- FALSE # This vector is where we'll say if we reached the end of a path (i. e. "contains no bags")
repeat{ # The dreaded repeat
  replacement <- data.frame(n=NULL, col=NULL, end=NULL) # Empty dataframe in which we will put the result
  for(i in 1:nrow(step)){
    if(!step$end[i]){ #If we didn't already reach the end of that particular path
      sub <- res[sapply(res,function(x)x$a==step$col[i])][[1]]$b
      if(!is.null(sub)){
        sub$n <- as.integer(sub$n)*step$n[i]
        sub$end <- FALSE
        step$end[i] <- TRUE
        #One needs to keep the step that is done because we need to count those bags too.
        replacement <- rbind(replacement, sub, step[i,])
      }else{
        step$end[i]<-TRUE
        replacement <- rbind(replacement, step[i,])
      }
    }else{
      replacement <- rbind(replacement, step[i,])
    }
  }
  step <- replacement
  if(all(step$end)){break} #If every path reached its end, we can stop
}
sum(step$n)