Advent of Code 2021 Day 2
Tags: adventofcode
Published: 2021-12-02 20:59:52

---
title: Advent of Code 2021 Day 2
published: true
description: Oh let's just do C again!
tags: adventofcode
series: Advent Of Code 2021
---

I created a Kotlin project and the configuration boilerplate and noise is just awful, so I deleted it. I started writing a Haskell solution but my tooling seems all broken. So I factored out the reading code from yesterday to a common library and did it in C again!

Building the linked list by appending rather than prepending brought back an old pointer-to-pointer trick. And you can get a lot of parsing done with a simple state machine.

```c
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "reader.h"

// ----------------------------------------------
// Data model

enum Direction {
	FORWARD,
	DOWN,
	UP
};

struct Instruction {
	enum Direction direction;
	int amount;
};

struct Course {
	struct Instruction instruction;
	struct Course *next;
};

struct Course **add_instruction(struct Course **next, enum Direction direction, int amount) {
	struct Course *step = (struct Course *)malloc(sizeof(struct Course));
	step->instruction.direction = direction;
	step->instruction.amount = amount;
	step->next = NULL;
	*next = step;
	return &step->next;
}

struct Course *parse_course(struct Reader *reader) {
	struct Course *course = NULL;
	struct Course **next = &course;
	enum Direction direction;
	int amount;
	int state = 0;

	char c;
	while ((c = reader->next(reader)) != 0) {
		switch (state) {
			case 0:
				switch (c) {
					case 'f': 
						direction = FORWARD;
						state = 1;
						break;
					case 'd':
						direction = DOWN;
						state = 1;
						break;
					case 'u':
						direction = UP;
						state = 1;
						break;
				}
				break;
			case 1:
				if (isdigit(c)) {
					amount = c - '0';
					state = 2;
				}
				break;
			case 2:
				if (isdigit(c)) {
					amount = (amount * 10) + (c - '0');
				} else {
					next = add_instruction(next, direction, amount);
					state = 0;
				}
				break;
		}
	}
	if (state == 2) {
		add_instruction(next, direction, amount);
	}

	reader->delete(reader);

	return course;
}

void delete_course(struct Course *course) {
	while (course) {
		struct Course *next = course->next;
		free(course);
		course = next;
	}
}


// ----------------------------------------------
// Part 1

struct Position {
	int horizontal;
	int depth;
};

struct Position follow_course(struct Course *course) {
	struct Position pos = { .horizontal = 0, .depth = 0 };
	for (; course; course = course->next) {
		switch (course->instruction.direction) {
			case FORWARD:
				pos.horizontal += course->instruction.amount;
				break;
			case DOWN:
				pos.depth += course->instruction.amount;
				break;
			case UP:
				pos.depth -= course->instruction.amount;
				break;
		}
	}
	return pos;
}

int part1(struct Course *course) {
	struct Position pos = follow_course(course);
	return pos.horizontal * pos.depth;
}


// ----------------------------------------------
// Part 2

struct Position2 {
	int horizontal;
	int depth;
	int aim;
};

struct Position2 follow_course2(struct Course *course) {
	struct Position2 pos = { .horizontal = 0, .depth = 0, .aim = 0 };
	for (; course; course = course->next) {
		switch (course->instruction.direction) {
			case FORWARD:
				pos.horizontal += course->instruction.amount;
				pos.depth += pos.aim * course->instruction.amount;
				break;
			case DOWN:
				pos.aim += course->instruction.amount;
				break;
			case UP:
				pos.aim -= course->instruction.amount;
				break;
		}
	}
	return pos;
}

int part2(struct Course *course) {
	struct Position2 pos = follow_course2(course);
	return pos.horizontal * pos.depth;
}


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

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

static const char test_data[] = "forward 5\ndown 5\nforward 8\nup 3\ndown 8\nforward 2";

int main() {
	test(test_data, part1, 150);
	test(test_data, part2, 900);

	struct Course *course = parse_course(file_reader("day2/input.txt"));

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

	delete_course(course);
	return 0;

}
```

Full code on [github](https://github.com/neilgall/advent-of-code-2021)