library(tidyverse)

Read in the problem:

dat <- read_lines("aoc03.txt")

Line breaks aren’t special, so paste the lot together:

longmess <- paste(dat, collapse = "")

Part 1

Regex time. Try with an easy test:

easy_test <- "mul(2,4)ggsrjkgjdfmul(224,221)gielmul(1234,12)fskjd"
str_extract_all(easy_test, "mul\\([0-9]{1,3},[0-9]{1,3}\\)")
[[1]]
[1] "mul(2,4)"     "mul(224,221)"

It worked. Now do it for longmess.

mults <- str_extract_all(longmess, "mul\\([0-9]{1,3},[0-9]{1,3}\\)")[[1]]
mults |> head(20)
 [1] "mul(363,974)" "mul(307,210)" "mul(542,323)" "mul(238,474)"
 [5] "mul(251,668)" "mul(184,693)" "mul(279,48)"  "mul(96,310)" 
 [9] "mul(393,809)" "mul(95,723)"  "mul(2,997)"   "mul(114,838)"
[13] "mul(981,859)" "mul(137,289)" "mul(632,274)" "mul(963,844)"
[17] "mul(398,724)" "mul(87,650)"  "mul(373,567)" "mul(683,987)"

I’m going to let R parse each string.

mul <- function(x,y) x * y

mult_one <- function(str) {
  str |> parse(text = _) |> eval()
}

Here’s a test:

mult_one("mul(6,7)")
[1] 42

The answer to part 1:

map_int(mults, mult_one) |> sum()
[1] 175015740

Part 2

The logic is, hike out anything between a “don’t()” and a “do()”, then run the code above on what remains. This also deals with consecutive “do()”s automatically.

get_do <- function(str) {
  doing_do <- TRUE
  dont_exp <- "don't\\(\\)"
  do_exp   <- "do\\(\\)"

  res  <- ""
  rest <- str

  while (str_length(rest) != 0) {
    if (doing_do) {
      loc <- str_locate(rest, dont_exp)
      
      if (!is.na(loc[1])) {
        res  <- paste0(res, str_sub(rest, 1, loc[1] - 1))
        rest <- str_sub(rest, loc[2] + 1)
      }
      else {
        res  <- paste0(res, str_sub(rest, 1))
        rest <- ""
      }
      
      doing_do <- FALSE
    }
    else {
      loc <- str_locate(rest, do_exp)
      
      if (!is.na(loc[1])) {
        rest <- str_sub(rest, loc[2] + 1)
      }
      else {
        rest <- ""
      }
      
      doing_do <- TRUE
    }
  }
  
  res
}

Give it a go:

new_longmess <- longmess |> get_do()

A bit of copy and paste…

mults <- str_extract_all(new_longmess, "mul\\([0-9]{1,3},[0-9]{1,3}\\)")[[1]]
map_int(mults, mult_one) |> sum()
[1] 112272912

And it works!

LS0tDQp0aXRsZTogIkRheSAzOiBNdWxsIEl0IE92ZXIiDQphdXRob3I6IEFuZGlGDQpkYXRlOiAzIERlYyAyMDI0DQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOiANCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUNCi0tLQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCg0KUmVhZCBpbiB0aGUgcHJvYmxlbToNCg0KYGBge3J9DQpkYXQgPC0gcmVhZF9saW5lcygiYW9jMDMudHh0IikNCmBgYA0KDQpMaW5lIGJyZWFrcyBhcmVuJ3Qgc3BlY2lhbCwgc28gcGFzdGUgdGhlIGxvdCB0b2dldGhlcjoNCg0KYGBge3J9DQpsb25nbWVzcyA8LSBwYXN0ZShkYXQsIGNvbGxhcHNlID0gIiIpDQpgYGANCg0KIyMjIFBhcnQgMQ0KDQpSZWdleCB0aW1lLiBUcnkgd2l0aCBhbiBlYXN5IHRlc3Q6DQoNCmBgYHtyfQ0KZWFzeV90ZXN0IDwtICJtdWwoMiw0KWdnc3Jqa2dqZGZtdWwoMjI0LDIyMSlnaWVsbXVsKDEyMzQsMTIpZnNramQiDQpzdHJfZXh0cmFjdF9hbGwoZWFzeV90ZXN0LCAibXVsXFwoWzAtOV17MSwzfSxbMC05XXsxLDN9XFwpIikNCmBgYA0KDQpJdCB3b3JrZWQuIE5vdyBkbyBpdCBmb3IgX2xvbmdtZXNzXy4NCg0KYGBge3J9DQptdWx0cyA8LSBzdHJfZXh0cmFjdF9hbGwobG9uZ21lc3MsICJtdWxcXChbMC05XXsxLDN9LFswLTldezEsM31cXCkiKVtbMV1dDQptdWx0cyB8PiBoZWFkKDIwKQ0KYGBgDQoNCkknbSBnb2luZyB0byBsZXQgUiBwYXJzZSBlYWNoIHN0cmluZy4NCg0KYGBge3J9DQptdWwgPC0gZnVuY3Rpb24oeCx5KSB4ICogeQ0KDQptdWx0X29uZSA8LSBmdW5jdGlvbihzdHIpIHsNCiAgc3RyIHw+IHBhcnNlKHRleHQgPSBfKSB8PiBldmFsKCkNCn0NCmBgYA0KDQpIZXJlJ3MgYSB0ZXN0Og0KDQpgYGB7cn0NCm11bHRfb25lKCJtdWwoNiw3KSIpDQpgYGANCg0KVGhlIGFuc3dlciB0byBwYXJ0IDE6DQoNCmBgYHtyfQ0KbWFwX2ludChtdWx0cywgbXVsdF9vbmUpIHw+IHN1bSgpDQpgYGANCg0KIyMjIFBhcnQgMg0KDQpUaGUgbG9naWMgaXMsIGhpa2Ugb3V0IGFueXRoaW5nIGJldHdlZW4gYSAiZG9uJ3QoKSIgYW5kIGEgImRvKCkiLCB0aGVuIHJ1biB0aGUgY29kZSBhYm92ZSBvbiB3aGF0IHJlbWFpbnMuIFRoaXMgYWxzbyBkZWFscyB3aXRoIGNvbnNlY3V0aXZlICJkbygpInMgYXV0b21hdGljYWxseS4NCg0KYGBge3J9DQpnZXRfZG8gPC0gZnVuY3Rpb24oc3RyKSB7DQogIGRvaW5nX2RvIDwtIFRSVUUNCiAgZG9udF9leHAgPC0gImRvbid0XFwoXFwpIg0KICBkb19leHAgICA8LSAiZG9cXChcXCkiDQoNCiAgcmVzICA8LSAiIg0KICByZXN0IDwtIHN0cg0KDQogIHdoaWxlIChzdHJfbGVuZ3RoKHJlc3QpICE9IDApIHsNCiAgICBpZiAoZG9pbmdfZG8pIHsNCiAgICAgIGxvYyA8LSBzdHJfbG9jYXRlKHJlc3QsIGRvbnRfZXhwKQ0KICAgICAgDQogICAgICBpZiAoIWlzLm5hKGxvY1sxXSkpIHsNCiAgICAgICAgcmVzICA8LSBwYXN0ZTAocmVzLCBzdHJfc3ViKHJlc3QsIDEsIGxvY1sxXSAtIDEpKQ0KICAgICAgICByZXN0IDwtIHN0cl9zdWIocmVzdCwgbG9jWzJdICsgMSkNCiAgICAgIH0NCiAgICAgIGVsc2Ugew0KICAgICAgICByZXMgIDwtIHBhc3RlMChyZXMsIHN0cl9zdWIocmVzdCwgMSkpDQogICAgICAgIHJlc3QgPC0gIiINCiAgICAgIH0NCiAgICAgIA0KICAgICAgZG9pbmdfZG8gPC0gRkFMU0UNCiAgICB9DQogICAgZWxzZSB7DQogICAgICBsb2MgPC0gc3RyX2xvY2F0ZShyZXN0LCBkb19leHApDQogICAgICANCiAgICAgIGlmICghaXMubmEobG9jWzFdKSkgew0KICAgICAgICByZXN0IDwtIHN0cl9zdWIocmVzdCwgbG9jWzJdICsgMSkNCiAgICAgIH0NCiAgICAgIGVsc2Ugew0KICAgICAgICByZXN0IDwtICIiDQogICAgICB9DQogICAgICANCiAgICAgIGRvaW5nX2RvIDwtIFRSVUUNCiAgICB9DQogIH0NCiAgDQogIHJlcw0KfQ0KYGBgDQoNCkdpdmUgaXQgYSBnbzoNCg0KYGBge3J9DQpuZXdfbG9uZ21lc3MgPC0gbG9uZ21lc3MgfD4gZ2V0X2RvKCkNCmBgYA0KDQpBIGJpdCBvZiBjb3B5IGFuZCBwYXN0ZS4uLg0KDQpgYGB7cn0NCm11bHRzIDwtIHN0cl9leHRyYWN0X2FsbChuZXdfbG9uZ21lc3MsICJtdWxcXChbMC05XXsxLDN9LFswLTldezEsM31cXCkiKVtbMV1dDQptYXBfaW50KG11bHRzLCBtdWx0X29uZSkgfD4gc3VtKCkNCmBgYA0KDQpBbmQgaXQgd29ya3MhDQo=