summaryrefslogtreecommitdiff
path: root/04.c
blob: 499461b2d34baad75b3e252230a8f86a331f51fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <stdbool.h>
#include "input.h"

#define INPUT "input/04.txt"
#define EXPECTED1 51776L
#define EXPECTED2 16830L

#define BOARD_COUNT 100
#define BOARD_SIZE 5
#define MAX_DRAW 500

typedef struct {
	long board[BOARD_SIZE][BOARD_SIZE];
	bool board_marks[BOARD_SIZE][BOARD_SIZE];
} t_board;

bool board_is_winning(t_board* board) {
	for(int i = 0; i < BOARD_SIZE; i++) {
		bool winning_i = true;
		bool winning_j = true;
		for(int j = 0; j < BOARD_SIZE; j++) {
			winning_i &= board->board_marks[i][j];
			winning_j &= board->board_marks[j][i];
		}
		if(winning_i || winning_j)
			return true;
	}
	return false;
}

bool board_mark(t_board* board, long draw) {
	for(int i = 0; i < BOARD_SIZE; i++) {
		for(int j = 0; j < BOARD_SIZE; j++) {
			if(board->board[i][j] == draw)
				board->board_marks[i][j] = true;
		}
	}
	return board_is_winning(board);
}

void board_init(t_board* board) {
	for(int i = 0; i < BOARD_SIZE; i++) {
		for(int j = 0; j < BOARD_SIZE; j++) {
			board->board[i][j] = 0;
			board->board_marks[i][j] = false;
		}
	}
}

void board_read(t_board* board_list, struct input_str* input) {
	for(int i = 0; i < BOARD_COUNT; i++) {
		board_init(&(board_list[i]));
		// read each line of the board
		for(int j = 0; j < BOARD_SIZE; j++) {
			// + 2 is for first line and empty line at start of board
			int line_index = i * (BOARD_SIZE + 1) + j + 2;
			char* line = input->lines[line_index];
			char* start = line;
			char* end = NULL;
			// read each int
			for(int k = 0; k < BOARD_SIZE; k++) {
				board_list[i].board[j][k] = strtol(start, &end, 0);
				start = end;
			}
		}
	}
}

size_t draw_read(long* draw_list, struct input_str* input) {
	size_t i = 0;
	char *start = input->lines[0];
	char *end = start;
	while(i < MAX_DRAW && *end != '\n') {
		draw_list[i] = strtol(start, &end, 0);
		start = end + 1;
		i++;
	}
	if(i == MAX_DRAW && *end != '\n')
		err(1, "draw list was truncated");

	return i;
}

long board_unmarked_sum(t_board* board) {
	long sum = 0;
	for(int i = 0; i < BOARD_SIZE; i++) {
		for(int j = 0; j < BOARD_SIZE; j++) {
			if(!(board->board_marks)[i][j])
				sum += (board->board)[i][j];
		}
	}
	return sum;
}

void part1(struct input_str* input) {
	t_board board_list[BOARD_COUNT];
	long draw_list[MAX_DRAW];
	board_read(board_list, input);
	size_t draw_count = draw_read(draw_list, input);
	
	// apply draw to each board until one is winning
	for(size_t i = 0; i < draw_count; i++) {
		for(size_t j = 0; j < BOARD_COUNT; j++) {
			if(board_mark(&(board_list[j]), draw_list[i])) {
				// winning board found, print score
				long score = board_unmarked_sum(&(board_list[j]));
				CHECK(draw_list[i] * score, EXPECTED1)
				return;
			}
		}
	}
	
	err(1, "no winning board");
}

void part2(struct input_str* input) {
	t_board board_list[BOARD_COUNT];
	long draw_list[MAX_DRAW];
	board_read(board_list, input);
	size_t draw_count = draw_read(draw_list, input);
	
	// apply draw to each board until one is winning
	long last_score;
	for(size_t i = 0; i < draw_count; i++) {
		for(size_t j = 0; j < BOARD_COUNT; j++) {
			// skip already winning boards
			if(board_is_winning(&(board_list[j])))
					continue;

			if(board_mark(&(board_list[j]), draw_list[i])) {
				// winning board found
				last_score = draw_list[i] * board_unmarked_sum(&(board_list[j]));
			}
		}
	}
	// print last winning
	CHECK(last_score, EXPECTED2)
}

int main() {
	// read input
	struct input_str input;
	input_str_read(&input, INPUT);

	// do stuff
	part1(&input);
	part2(&input);

	// cleanup & exit
	input_str_free(&input);
	return 0;
}