#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include "../../lib/aoc.h"

typedef struct Map {
  char *data;
  int data_length;
  int width;
  int height;
  int current_level;
  int positions[10000];
  int positions_count;
} Map;

void ascend(Map *map, bool dedupe) {
  char search_for = map->current_level + 1 + '0';
  int positions[10000];
  int positions_count = 0;
  for (int i = 0; i < map->positions_count; i++) {
    int p = map->positions[i];
    if (p - map->width >= 0 && map->data[p - map->width] == search_for) positions[positions_count++] = p - map->width;
    if (map->data[p - 1] == search_for) positions[positions_count++] = p - 1;
    if (map->data[p + 1] == search_for) positions[positions_count++] = p + 1;
    if (p + map->width < map->data_length && map->data[p + map->width] == search_for) positions[positions_count++] = p + map->width;
  }

  if (dedupe) {
    qsort(positions, positions_count, sizeof(int), aoc_sort_int);

    int deduped_positions[10000];
    int deduped_positions_count = 0;

    for (int i = 0; i < positions_count - 1; i++) {
      if (positions[i] != positions[i+1]) {
	deduped_positions[deduped_positions_count++] = positions[i];
      }
    }
    deduped_positions[deduped_positions_count++] = positions[positions_count - 1];

    map->positions_count = deduped_positions_count;
    memcpy(&(map->positions), &deduped_positions, deduped_positions_count * sizeof(int));
    map->current_level++;
  } else {
    map->positions_count = positions_count;
    memcpy(&(map->positions), &positions, positions_count * sizeof(int));
    map->current_level++;
  }
}

int calculate_score(Map *map, int index, bool dedupe) {
  if (map->data[index] != '0') return 0;
  map->current_level = 0;

  map->positions[0] = index; 
  map->positions_count = 1;
  for (int i = 0; i < 9; i++) {
    ascend(map, dedupe);
  }
  return map->positions_count;
}

int main() {
  char *input = aoc_read_input();
  int input_length = strlen(input);

  Map m;
  m.data = input;
  m.data_length = input_length;
  m.width = strchr(input, '\n') - input + 1;
  m.height = input_length - m.width;

  int score = 0;
  int big_score = 0;

  for (int i = 0; i < input_length; i++) {
    score += calculate_score(&m, i, true);
    big_score += calculate_score(&m, i, false);
  }

  printf("Part 1: %ld\n", score);
  printf("Part 2: %ld\n", big_score);
  
  aoc_free();
  return 0;
}