solve_day3_part1<-function(input){# find and extract numbers in each linenum_locs<-stringi::stri_locate_all(input, regex ="\\d+")nums<-stringi::stri_extract_all(input, regex ="\\d+")# find symbol locations in each linesym_locs<-stringi::stri_locate_all(input, regex ="(?![.|\\d]).")sym_locs<-lapply(sym_locs, \(x)x[, 1])# list to store which numbers are part numbersnum_check<-vector("list", length(input))# for each line with numbersfor(rowinseq_along(num_locs)){# skip rows with no numbersif(is.na(num_locs[[row]][[1]]))next# for each number in the linefor(numinseq_len(NROW(num_locs[[row]]))){num_loc<-num_locs[[row]][num, ]# search surrounding positions to confirm if the number# is a part numberis_part<-is_part_number(row, num_loc, sym_locs)# store whether it is or notnum_check[[row]]<-c(num_check[[row]], is_part)}# store NA if no part numbers foundif(is.null(num_check[[row]])){num_check[[row]]<-NA}}nums<-as.numeric(unlist(nums))num_check<-unlist(num_check)# sum any numbers where is_part_number returned TRUEsum(nums[num_check], na.rm =TRUE)}is_part_number<-function(row_loc, num_loc, sym_locs){# columns to check start before and after the numbercol_range<-(num_loc[[1]]-1):(num_loc[[2]]+1)# check rows from the previous row to the next rowfor(rowin(row_loc-1):(row_loc+1)){# skipping out of boundsif(row<=0)nextif(row>NROW(sym_locs))break# we have a part number if the checking range# intersects with a symbol positionif(any(col_range%in%sym_locs[[row]])){return(TRUE)}}FALSE}
Run
aoc_source(day =3, part =1)input=aoc_read(day =3)aoc_run(solve_day3_part1(input))
Elapsed: 0.013 seconds
Memory: 747 KB
— R Day 3 Part 2 —
solve_day3_part2<-function(input){# find and extract numbers in each line (in the same list structure)num_locs<-stringi::stri_locate_all(input, regex ="\\d+")nums<-stringi::stri_extract_all(input, regex ="\\d+")# find "*" locations (column) in each linegear_locs<-stringi::stri_locate_all(input, regex ="\\*")# location has start and end, but they are length 1, so we need only onegear_locs<-lapply(gear_locs, \(x)x[, 1])ratio_sum<-0# iterate through every `*` locationfor(rowinseq_along(gear_locs)){for(colingear_locs[[row]]){if(length(col)==1&is.na(col))break# skip if no gears in line# search surrounding area for numbers# store their product if there are 2ratio_sum<-ratio_sum+find_gear_ratio(row, col, num_locs, nums)}}sum(ratio_sum)}find_gear_ratio<-function(row, col, num_locs, nums){# 9 position grid search area around `*`search_rows<-(row-1):(row+1)search_cols<-(col-1):(col+1)# store potential gear numbersgear_nums<-numeric()for(search_rowinsearch_rows){# skipping out of boundsif(search_row<=0)nextif(search_row>NROW(num_locs))break# iterate through the number locations in the search rowrow_nums<-num_locs[[search_row]]for(indexinseq_len(NROW(row_nums))){# get the column positions for the numbernumber_cols<-row_nums[index, 1]:row_nums[index, 2]# if the number intersects the search areaif(any(number_cols%in%search_cols)){# add it to the list of potential gear numbers# take the actual number based on the current number locationgear_num<-nums[[search_row]][[index]]gear_nums<-c(gear_nums, as.numeric(gear_num))}}}# if there are two numbers we've found a gearif(length(gear_nums)==2){# multiply numbers to get the gear ratiogear_nums[[1]]*gear_nums[[2]]}else{# found a `*` that wasn't a gear0}}
Run
aoc_source(day =3, part =2)input=aoc_read(day =3)aoc_run(solve_day3_part2(input))