DEV Community

Neil Gall
Neil Gall

Posted on

Advent of Code 2021 Day 1

No rules this year, I'll pick a language on the day. How about some production quality C? (I really hope there's no bugs!)

If I do more C I'll no doubt factor out the reusable bits.

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

// ----------------------------------------------
// Abstract reader

struct Reader;
typedef void (*reader_delete_f)(struct Reader *);
typedef char (*reader_next_f)(struct Reader *);

struct Reader {
    reader_next_f next;
    reader_delete_f delete;
};


// ----------------------------------------------
// String reader

struct StringReader {
    struct Reader reader;
    const char *p;
};

char string_reader_f(struct StringReader *sr) {
    return *(sr->p++);
}

struct Reader *string_reader(const char *s) {
    struct StringReader *sr = (struct StringReader *)malloc(sizeof(struct StringReader));
    sr->reader.next = (reader_next_f)&string_reader_f;
    sr->reader.delete = (reader_delete_f)&free;
    sr->p = s;
    return (struct Reader *)sr;
}


// ----------------------------------------------
// File reader

struct FileReader {
    struct Reader reader;
    FILE *fd;
};

char file_reader_f(struct FileReader *fr) {
    int c = fgetc(fr->fd);
    return (c == EOF) ? 0 : (char)c;
}

void file_reader_delete(struct FileReader *fr) {
    fclose(fr->fd);
    free(fr);
}

struct Reader *file_reader(const char *filename) {
    FILE *f = fopen(filename, "rt");
    if (f == NULL) {
        perror("can't open file");
        abort();
    }
    struct FileReader *fr = (struct FileReader *)malloc(sizeof(struct FileReader));
    fr->reader.next = (reader_next_f)&file_reader_f;
    fr->reader.delete = (reader_delete_f)&file_reader_delete;
    fr->fd = f;
    return (struct Reader *)fr;
}


// ----------------------------------------------
// Report structure

struct Report {
    size_t capacity;
    size_t count;
    int entries[];
};

size_t report_size(size_t count) {
    return sizeof(struct Report) + sizeof(int) * count;
}

struct Report *empty_report(size_t capacity) {
    struct Report *report = (struct Report *)malloc(report_size(capacity));
    report->capacity = capacity;
    report->count = 0;
    return report;
}

void append_entry(struct Report **report_p, int entry) {
    struct Report *report = *report_p;
    if (report->count == report->capacity) {
        report->capacity *= 2;
        *report_p = report = (struct Report *)realloc(report, report_size(report->capacity));
    }
    report->entries[report->count++] = entry;

}

struct Report *read_report(struct Reader *reader) {
    struct Report *report = empty_report(100);
    int entry = 0;
    int entry_digits = 0;
    char c;
    while ((c = reader->next(reader)) != 0) {
        if (isdigit(c)) {
            entry = (entry * 10) + (c - '0');
            entry_digits += 1;
        } else {
            append_entry(&report, entry);
            entry = 0;
            entry_digits = 0;
        }
    }
    if (entry_digits > 0) {
        append_entry(&report, entry);
    }
    reader->delete(reader);
    return report;
}


// ----------------------------------------------
// Problems

int part1(struct Report *report) {
    size_t increments = 0;
    for (size_t pos = 1; pos < report->count; ++pos) {
        if (report->entries[pos] > report->entries[pos-1])
            increments++;
    }
    return increments;
}


int window(struct Report *report, int pos) {
    int *es = report->entries + pos;
    return es[0] + es[1] + es[2];
}

int part2(struct Report *report) {
    size_t increments = 0;
    for (size_t pos = 3; pos < report->count; ++pos) {
        int prev = window(report, pos-3);
        int curr = window(report, pos-2);
        if (curr > prev) 
            increments++;
    }
    return increments;
}

// ----------------------------------------------
// tests

void test(const char *input, int (*f)(struct Report *), int expect) {
    struct Report *report = read_report(string_reader(input));
    int actual = f(report);
    free(report);
    if (actual != expect) {
        fprintf(stderr, "test failed input='%s' expect=%d actual=%d\n",
            input, expect, actual);
        abort();
    }
}


// ----------------------------------------------

static const char test_data[] = 
    "199\n200\n208\n210\n200\n207\n240\n269\n260\n263";

int main() {
    test(test_data, part1, 7);
    test(test_data, part2, 5);

    struct Report *report = read_report(file_reader("day1/input.txt"));

    printf("Part 1: %d\n", part1(report));
    printf("Part 2: %d\n", part2(report));

    free(report);
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

Best practices for optimal infrastructure performance with Magento

Running a Magento store? Struggling with performance bottlenecks? Join us and get actionable insights and real-world strategies to keep your store fast and reliable.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️