05: How About a Nice Game of Chess?

library(mistlecode)
To install `mistlecode` yourself, run `devtools::install_github('guslipkin/mistlecode')`.

 Also loading:  cipheR data.table dplyr purrr slider stringr tidyverse glue
library(Rcpp)
library(digest)

dt <- "reyedfim"

I initially did everything in pure R, but it was kinda slow and the solution seemed easy enough to dip my toes into Rcpp. All things considered, it went pretty smoothly. Some of the trickier bits were getting the StringVector<>std::string relationship straight, and not crashing everything when trying to sub-string a StringVector with string_vector[x][y] which is why I ended up just using std::string.

After re-writing, I was able to speed up Part 1 by ~37 seconds and Part 2 by ~ 10 minutes…

Part 1

This isn’t as bad as it looks. Only annoying thing was serialize = FALSE but StackOverflow cleared that up pretty quick.

cppFunction('
  StringVector part1(StringVector dt) {
    std::string string_x, dig, string_dt = as<std::string>(dt);
    StringVector password(8);
    int x = 0, j = 0, p_size = password.size();
    Function md5("digest");
    Function paste0("paste0");
  
    while (j < p_size) {
      string_x = std::to_string(x);
      dig = string_dt + string_x;
      dig = as<std::string>(md5(dig, _["algo"]="md5", _["serialize"]=0));
      if (dig.substr(0, 5) == "00000") {
        password[j] = dig.substr(5, 1);
        j++;
      }
      //if (x % 100000 == 0) { std::cout << "\\r" << string_x << password; }
      x++;
    }
    std::cout << std::endl;
    return paste0(password, _["collapse"]="");
  }
')
part1(dt)
[1] "f97c354d"
x <- 0
password <- c()
while(length(password) != 8) {
  dig <- 
    paste0(dt, x) |>
    digest::digest(algo = "md5", serialize = FALSE)
  if (substr(dig, 1, 5) == "00000") password <- c(password, substr(dig, 6, 6))
  x <- x + 1
}
paste0(password, collapse = "")

Part 2

That’s not so bad. Just a few small changes and a lot slower…

cppFunction('
  StringVector part2(StringVector dt) {
    std::string string_x, dig, string_dt = as<std::string>(dt);
    StringVector password(8);
    int x = 0, j = 0, p_size = password.size(), int_six;
    Function md5("digest");
    Function paste0("paste0");
  
    while (j < p_size) {
      string_x = std::to_string(x);
      dig = string_dt + string_x;
      dig = as<std::string>(md5(dig, _["algo"]="md5", _["serialize"]=0));
      if (dig.substr(0, 5) == "00000") {
        try { 
          int_six = stoi(dig.substr(5, 1)); 
        } catch(...) {
          int_six = -1;
        }
        if (int_six > -1 && int_six < p_size && password[int_six] == "") {
          password[int_six] = dig.substr(6, 1);
          j++;
        }
      }
      //if (x % 100000 == 0) { std::cout << "\\r" << string_x << password; }
      x++;
    }
    std::cout << std::endl;
    return paste0(password, _["collapse"]="");
  }
')
old <- Sys.time()
part2(dt)
[1] "863dde27"
Sys.time() - old
Time difference of 4.88216 mins
old <- Sys.time()
x <- 0
password <- rep("", 8)
while(any(password == "")) {
  dig <- 
    paste0(dt, x) |>
    digest::digest(algo = "md5", serialize = FALSE)
  z <- 
    dig |>
    substr(6, 6) |>
    as.numeric() |>
    suppressWarnings()
  if (
    substr(dig, 1, 5) == "00000" & !is.na(z) & 
    !is.na(password[z + 1]) & password[z + 1] == "") {
    password[z + 1] <- substr(dig, 7, 7)
  }
  x <- x + 1
}
paste0(password, collapse = "")
Sys.time() - old