For day 2, I started exploring what I would like my own String library to look like. Despite knowing what would need to be done, I’ve never really built a resizeable string in c.

I tried to contain my changes to just what was needed. By coincidence, I stumbled on a C string library post on HackerNews after completing this challenge.

As usual, the comments section is spread from “love it” to “hate it”. Regardless, it was a useful thread to see different arguments about string libraries in general and common complaints.

In this puzzle, I mostly just focused on the struct. You can see the initialization code duplicated twice across the two parts.

As mentioned in my day 1 post, I am playing around with a slight focus on memory safety. In the solution below, I still have raw array accesses. After a few manual combs of the code, I can’t see any possible buffer overruns.

It might be interesting to do a future advent of code puzzle in Rust to see if I ever run in to a memory safety error that is detected by the compiler.

Final Solution

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>

struct String {
  char *data;
  int length;
  int size;
} typedef String;

int partOne(String *contents) {
  int score = 0;
  for (int i = 0; i < contents->length; i += 4) {
    char opponent_char = contents->data[i];
    char my_char = contents->data[i + 2];

    int opponent_move_val = opponent_char - 'A' + 1;
    int my_move_val = my_char - 'X' + 1;

    score += my_move_val;

    // DRAW
    if (opponent_move_val == my_move_val) {
      score += 3;
    }
    if (opponent_char == 'A') {
      if (my_char == 'Y') {
        score += 6;
      }
    }
    if (opponent_char == 'B') {
      if (my_char == 'Z') {
        score += 6;
      }
    }
    if (opponent_char == 'C') {
      if (my_char == 'X') {
        score += 6;
      }
    }
  }

  return score;
}

int partTwo(String *contents) {
  int score = 0;
  for (int i = 0; i < contents->length; i += 4) {
    char opponent_char = contents->data[i];
    char my_char = contents->data[i + 2];

    int opponent_move_val = opponent_char - 'A' + 1;
    int my_move_val = 0;

    if (my_char == 'X') {
      if (opponent_char == 'A') {
        score += 3;
      } else if (opponent_char == 'B') {
        score += 1;
      } else {
        score += 2;
      }
    } else if (my_char == 'Y') {
      score += 3;

      if (opponent_char == 'A') {
        score += 1;
      } else if (opponent_char == 'B') {
        score += 2;
      } else {
        score += 3;
      }
    } else if (my_char == 'Z') {
      score += 6;

      if (opponent_char == 'A') {
        score += 2;
      } else if (opponent_char == 'B') {
        score += 3;
      } else {
        score += 1;
      }
    }
  }

  return score;
}

int main() {
  int total_elapsed = 0;

  struct timeval st, et;
  gettimeofday(&st,NULL);
  FILE *fp = fopen("input.txt", "r");
  String contents;

  contents.length = 0;
  contents.size = 10000;
  contents.data = malloc(contents.size);

  int num_read = fread(contents.data, 1, contents.size - contents.length, fp);
  contents.length = num_read;

  gettimeofday(&et,NULL);
  int elapsed = ((et.tv_sec - st.tv_sec) * 1000000) + (et.tv_usec - st.tv_usec);
  total_elapsed += elapsed;
  printf("Read: %d micro seconds\n",elapsed);

  
  printf("%d\n", partOne(&contents));
  gettimeofday(&et,NULL);
  elapsed = ((et.tv_sec - st.tv_sec) * 1000000) + (et.tv_usec - st.tv_usec);
  total_elapsed += elapsed;
  printf("Part One: %d micro seconds\n",elapsed);

  gettimeofday(&st,NULL);
  printf("%d\n", partTwo(&contents));
  gettimeofday(&et,NULL);
  elapsed = ((et.tv_sec - st.tv_sec) * 1000000) + (et.tv_usec - st.tv_usec);
  printf("Part Two: %d micro seconds\n",elapsed);

  total_elapsed += elapsed;

  printf("Total: %d micro seconds", total_elapsed);
}