mirror of
https://codeberg.org/andyscott/advent-of-code.git
synced 2024-12-22 17:43:10 -05:00
221 lines
4.8 KiB
C
221 lines
4.8 KiB
C
|
#include <ctype.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#define MAX_LINE 512
|
||
|
#define NUM_LINES 512
|
||
|
#define NUM_STACKS 9
|
||
|
|
||
|
struct Stack {
|
||
|
int top;
|
||
|
char items[MAX_LINE];
|
||
|
};
|
||
|
typedef struct Stack stack;
|
||
|
|
||
|
// Push onto a stack
|
||
|
void push(stack *st, char crate) {
|
||
|
if (st->top == MAX_LINE) {
|
||
|
fprintf(stderr, "Stack is full\n");
|
||
|
} else {
|
||
|
st->top++;
|
||
|
st->items[st->top] = crate;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Pop from a stack
|
||
|
char pop(stack *st) {
|
||
|
char c = '\0';
|
||
|
if (st->top == -1) {
|
||
|
fprintf(stderr, "Stack is empty\n");
|
||
|
return -1;
|
||
|
} else {
|
||
|
c = st->items[st->top];
|
||
|
st->items[st->top] = '\0';
|
||
|
st->top--;
|
||
|
return c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Prints top index, top item, and each stack
|
||
|
void print_crates(stack **crates) {
|
||
|
for (size_t i = 0; i < NUM_STACKS; i++) {
|
||
|
printf("\nStack %lu - Top: %d"
|
||
|
"\n Top Crate: %c"
|
||
|
"\n Crates: %s\n",
|
||
|
i + 1, crates[i]->top, crates[i]->items[crates[i]->top],
|
||
|
crates[i]->items);
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Allocate memeory and initialize stacks of crates with their initial order
|
||
|
stack **crates_init() {
|
||
|
|
||
|
stack **crates = calloc(NUM_STACKS, sizeof(stack *));
|
||
|
if (crates == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < NUM_STACKS; i++) {
|
||
|
crates[i] = (stack *)malloc(sizeof(stack));
|
||
|
if (crates[i] == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
crates[i]->top = -1;
|
||
|
memset(crates[i]->items, 0, MAX_LINE);
|
||
|
}
|
||
|
|
||
|
crates[0]->top = 7;
|
||
|
strcpy(crates[0]->items, "PFMQWGRT");
|
||
|
crates[1]->top = 2;
|
||
|
strcpy(crates[1]->items, "HFR");
|
||
|
crates[2]->top = 7;
|
||
|
strcpy(crates[2]->items, "PZRVGHSD");
|
||
|
crates[3]->top = 6;
|
||
|
strcpy(crates[3]->items, "QHPBFWG");
|
||
|
crates[4]->top = 4;
|
||
|
strcpy(crates[4]->items, "PSMJH");
|
||
|
crates[5]->top = 7;
|
||
|
strcpy(crates[5]->items, "MZTHSRPL");
|
||
|
crates[6]->top = 5;
|
||
|
strcpy(crates[6]->items, "PTHNML");
|
||
|
crates[7]->top = 3;
|
||
|
strcpy(crates[7]->items, "FDQR");
|
||
|
crates[8]->top = 6;
|
||
|
strcpy(crates[8]->items, "DSCNLPH");
|
||
|
|
||
|
return crates;
|
||
|
}
|
||
|
|
||
|
// Parses moves from input file and stores in an array
|
||
|
void parse_moves(FILE *file, int moves[NUM_LINES][3], size_t *line_num) {
|
||
|
|
||
|
int idx = 0;
|
||
|
char line[MAX_LINE] = {0};
|
||
|
|
||
|
while (fgets(line, MAX_LINE, file) != NULL) {
|
||
|
|
||
|
if (line[0] != 'm') {
|
||
|
memset(line, 0, MAX_LINE);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
for (size_t i = 0; i < strlen(line); i++) {
|
||
|
if (isdigit(line[i])) {
|
||
|
if (isdigit(line[i + 1])) {
|
||
|
char temp[2];
|
||
|
temp[0] = line[i];
|
||
|
temp[1] = line[i + 1];
|
||
|
moves[*line_num][idx] = atoi(temp);
|
||
|
i++;
|
||
|
} else {
|
||
|
moves[*line_num][idx] = atoi(&line[i]);
|
||
|
}
|
||
|
idx++;
|
||
|
if (idx > 2) {
|
||
|
*line_num += 1;
|
||
|
idx = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
memset(line, 0, MAX_LINE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Part 1 - Processes each move stored in the moves array one crate at a time
|
||
|
void part1_moves(stack **crates, int moves[NUM_LINES][3], size_t move_count) {
|
||
|
|
||
|
size_t idx = 0;
|
||
|
while (idx <= move_count) {
|
||
|
|
||
|
for (int i = 0; i < moves[idx][0]; i++) {
|
||
|
|
||
|
char c = pop(crates[moves[idx][1] - 1]);
|
||
|
if (c == -1) {
|
||
|
fprintf(stderr, "part1_moves: move num: %lu", idx);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
push(crates[moves[idx][2] - 1], c);
|
||
|
}
|
||
|
idx++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void crates_free(stack **crates) {
|
||
|
for (size_t i = 0; i < NUM_STACKS; i++) {
|
||
|
free(crates[i]);
|
||
|
}
|
||
|
free(crates);
|
||
|
}
|
||
|
|
||
|
// Part 2 - Processes the moves array multiple crates at a time
|
||
|
void part2_moves(stack **crates, int moves[NUM_LINES][3], size_t move_count) {
|
||
|
|
||
|
size_t idx = 0;
|
||
|
while (idx <= move_count) {
|
||
|
|
||
|
char c_arr[moves[idx][0]];
|
||
|
memset(c_arr, 0, moves[idx][0]);
|
||
|
|
||
|
for (int i = 0; i < moves[idx][0]; i++) {
|
||
|
c_arr[i] = pop(crates[moves[idx][1] - 1]);
|
||
|
if (c_arr[i] == -1) {
|
||
|
fprintf(stderr, "part2_moves: move num: %lu", idx);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (int j = moves[idx][0] - 1; j >= 0; j--) {
|
||
|
push(crates[moves[idx][2] - 1], c_arr[j]);
|
||
|
}
|
||
|
idx++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[]) {
|
||
|
|
||
|
if (argc != 2) {
|
||
|
fprintf(stderr, "USAGE: %s input_file\n", argv[0]);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
FILE *file = fopen(argv[1], "r");
|
||
|
if (!file) {
|
||
|
perror("fopen");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
size_t move_count = 0;
|
||
|
int moves[NUM_LINES][3] = {0};
|
||
|
stack **crates = crates_init();
|
||
|
if (crates == NULL) {
|
||
|
fprintf(stderr, "Part 2: unable to allocate memory for crates\n");
|
||
|
fclose(file);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
printf("\n--- PART 1 ---\n");
|
||
|
parse_moves(file, moves, &move_count);
|
||
|
part1_moves(crates, moves, move_count);
|
||
|
print_crates(crates);
|
||
|
|
||
|
printf("\n--- PART 2 ---\n");
|
||
|
crates_free(crates);
|
||
|
crates = crates_init();
|
||
|
if (crates == NULL) {
|
||
|
fprintf(stderr, "Part 2: unable to allocate memory for crates\n");
|
||
|
fclose(file);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
part2_moves(crates, moves, move_count);
|
||
|
print_crates(crates);
|
||
|
crates_free(crates);
|
||
|
|
||
|
fclose(file);
|
||
|
return 0;
|
||
|
}
|