Files
AdventOfCode2023/03/03-part2.c
2023-12-04 19:40:03 -05:00

158 lines
3.8 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define STRBUF_SIZE 200
#define DEFAULT_FILE "input.txt"
#define ISDIGIT(X) (X >= '0' && X <= '9')
// Parses a found number.
// The provided location can be any digit of the
// number; this function will automatically
// seek the first digit before processing.
// Erases numbers as they are processed.
uint16_t parse_num_at(char *str, uint8_t idx)
{
// Check input
if (str[idx] < '0' || str[idx] > '9') return 0;
// Find first digit of number
while (ISDIGIT(str[idx]) && idx) idx--;
if (!ISDIGIT(str[idx])) idx++;
uint16_t num = 0;
// Add up all digits
while (ISDIGIT(str[idx]))
{
num = (num * 10) + (str[idx] - '0');
// Erase the number to make sure we don't count it twice
str[idx] = '.';
idx++;
}
return num;
}
// If the character is a * with two adjacent numbers,
// returns the gear ratio. Returns zero if the symbol
// is not a gear.
uint64_t get_gear_ratio( uint8_t idx,
char *above,
char *current,
char *below)
{
char *above_copy = malloc(sizeof(char) * STRBUF_SIZE);
char *current_copy = malloc(sizeof(char) * STRBUF_SIZE);
char *below_copy = malloc(sizeof(char) * STRBUF_SIZE);
memcpy(above_copy, above, STRBUF_SIZE);
memcpy(current_copy, current, STRBUF_SIZE);
memcpy(below_copy, below, STRBUF_SIZE);
uint16_t nums[8] = {0};
if (idx) nums[0] = parse_num_at(above_copy, idx - 1);
nums[1] = parse_num_at(above_copy, idx);
nums[2] = parse_num_at(above_copy, idx + 1);
nums[3] = parse_num_at(current_copy, idx + 1);
nums[4] = parse_num_at(current_copy, idx - 1);
if (idx) nums[5] = parse_num_at(below_copy, idx - 1);
nums[6] = parse_num_at(below_copy, idx);
nums[7] = parse_num_at(below_copy, idx + 1);
free(above_copy);
free(current_copy);
free(below_copy);
uint8_t i = 0;
uint16_t num1 = 0;
uint16_t num2 = 0;
for (i = 0; i < 8; i++)
{
// More than 2 adjacent numbers
if (nums[i] && num1 && num2) return 0;
// The second number
if (nums[i] && num1) num2 = nums[i];
// The first number
else if (nums[i]) num1 = nums[i];
}
return num1 * num2;
}
// Search through a line of *current for symbols.
uint64_t parse_line(char *above, char *current, char *below)
{
uint64_t sum = 0;
uint8_t idx;
char c;
for (idx = 0; current[idx] != 0; idx++)
{
c = current[idx];
if (c == '*')
{
// We've found a symbol,
// add up all numbers around it
sum += get_gear_ratio(idx, above, current, below);
}
}
return sum;
}
int main(int argc, char **argv)
{
// Get filename as an argument, defaults to "input.txt"
char *path = (argc > 1) ? argv[1] : DEFAULT_FILE;
if (!path)
{
printf("Requires input file.\n");
return 1;
}
FILE *file = fopen(path, "r");
if (!file)
{
printf("Could not find file.");
return 1;
}
char *above = malloc(sizeof(char) * STRBUF_SIZE);
char *current = malloc(sizeof(char) * STRBUF_SIZE);
char *below = malloc(sizeof(char) * STRBUF_SIZE);
memset(above, '.', STRBUF_SIZE);
fgets(current, STRBUF_SIZE, file);
uint64_t sum = 0;
while (fgets(below, 200, file))
{
sum += parse_line(above, current, below);
free(above);
above = current;
current = below;
below = malloc(sizeof(char) * STRBUF_SIZE);
memset(below, '.', STRBUF_SIZE);
}
// Process the last line of the file
sum += parse_line(above, current, below);
printf("Sum: %lud\n", sum);
return 0;
}