diff options
| -rw-r--r-- | 08.c | 212 | ||||
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | input.c | 17 | 
3 files changed, 234 insertions, 2 deletions
@@ -0,0 +1,212 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <math.h> +#include "input.h" + +#define INPUT "input/08.txt" + +#define INPUT_DIGIT_SIZE 10 +#define OUTPUT_DIGIT_SIZE 4 + +#define EXPECTED1 504L +#define EXPECTED2 1073431L + +void part1(struct input_str* input) { +	long sum = 0; +	for(size_t i = 0; i < input->line_count; i++) { +		// copy string as strtok will mess with it +		int len = strlen(input->lines[i]); +		char* line = malloc(len * sizeof(char)); +		memset(line, '\0', len); +		strncpy(line, input->lines[i], len); +		char* output_start = strchr(line, '|'); +		char* token = strtok(output_start + 1, " "); +		while(token != NULL) { +			int token_length = strlen(token); +			// respectively digists 1, 4, 7 and 8 +			if(token_length == 2 || token_length == 4 || token_length == 3 || token_length == 7) +				sum++; + +			token = strtok(NULL, " "); +		} +		//free(line); TODO causes memory corruption +	} + +	CHECK(sum, EXPECTED1); +} + +int count_segment(int digit) { +	int count = 0; +	for(int p = 0; p < 10; p++) { +		int segment_mask = 1 << p; +		if((digit & segment_mask) == segment_mask) +			count++; +	} +	return count; +} + +int parse_digit(char* token) { +	// digits are parsed with segments mapped to bits as follows : 0abcdefg +	int result = 0; +	int p = 0; +	while(token[p] != '\0') { +		switch(token[p]) { +			case 'a': +				result |= (1 << 6); +				break; +			case 'b': +				result |= (1 << 5); +				break; +			case 'c': +				result |= (1 << 4); +				break; +			case 'd': +				result |= (1 << 3); +				break; +			case 'e': +				result |= (1 << 2); +				break; +			case 'f': +				result |= (1 << 1); +				break; +			case 'g': +				result |= 1; +				break; +			default: +				err(1, "unexpected token"); +		} +		p++; +	} +	return result; +} + +void part2(struct input_str* input) { +	long sum = 0; +	for(size_t i = 0; i < input->line_count; i++) { +		int digits[INPUT_DIGIT_SIZE]; +		// copy string as strtok will mess with it +		int len = strlen(input->lines[i]); +		char* line = malloc(len * sizeof(char)); +		memset(line, '\0', len); +		strncpy(line, input->lines[i], len); +		char* token = strtok(line, " "); +		for(int t = 0; t < INPUT_DIGIT_SIZE; t++) { +			digits[t] = parse_digit(token); +			token = strtok(NULL, " "); +		} + +		int digits_code[10] = { 0 }; +		// first pass to identify 1, 4, 7, 8 +		for(int p = 0; p < 10; p++) { +			int digit = digits[p]; +			int segment_count = count_segment(digit); +			if(segment_count == 3) { +				digits_code[7] = digit; // this is 7 +				digits[p] = 0; +			} +			else if(segment_count == 4) { +				digits_code[4] = digit; // this is 4 +				digits[p] = 0; +			} +			else if(segment_count == 2) { +				digits_code[1] = digit; // this is 0 +				digits[p] = 0; +			} +			else if(segment_count == 7) { +				digits_code[8] = digit; // this is 8 +				digits[p] = 0; +			} +		} +		// second pass identifies 2, 3 and 5 +		for(int p = 0; p < 10; p++) { +			int digit = digits[p]; +			if(digit == 0) +				continue; // this digit was identified by previous pass + +			int digit_segment_count = count_segment(digit); +			if(digit_segment_count == 5) { +				if(count_segment(digits[p] & digits_code[7]) == 3) { +					digits_code[3] = digit; // this is 3 (5 segments and those of 7) +					digits[p] = 0; +				} +				else if(count_segment(digits[p] & digits_code[4]) == 2) { +					digits_code[2] = digit; // this is 2 (5 segments and 2 in common with 4) +					digits[p] = 0; +				} +				else if(count_segment(digits[p] & digits_code[4]) == 3) { +					digits_code[5] = digit; // this si 5 (5 segments and 3 in common with 4) +					digits[p] = 0; +				} +			} +		} +		// third pass identifies 0, 6 and 9 +		for(int p = 0; p < 10; p++) { +			int digit = digits[p]; +			if(digit == 0) +				continue; + +#ifdef DEBUG +			// at this stage the remaining digits should have 6 segments +			if(count_segment(digit) != 6) +				printf("digit has %d segments while 6 expected\n", count_segment(digit)); +#endif + +			int segments_five_and_one = digits_code[5] | digits_code[1]; +			if((segments_five_and_one & digit) == segments_five_and_one) { +				digits_code[9] = digit; // this is 9 (6 segments and has those of 5 and 1) +				digits[p] = 0; +			} +			else if((digits_code[5] & digit) == digits_code[5]) { +				digits_code[6] = digit; // this is 6 (6 segments, has those of 5 but not 1) +				digits[p] = 0; +			} +			else { +				digits_code[0] = digit; // this is 0 +				digits[p] = 0; +			} +		} + +#ifdef DEBUG +		// check that we found all digits +		for(int d = 0; d < 10; d++) { +			if(digits_code[d] == 0) +				printf("missing digit %d\n", d); +		} +#endif + +		// use the table to parse output digits +		token = strtok(NULL, " "); // skip the '|' separator +		int current_number = 0; +		for(int n = 0; n < OUTPUT_DIGIT_SIZE && token != NULL; n++) { +			int parsed_digit = parse_digit(token); +			// search real digit +			for(int d = 0; d < 10; d++) { +				if(parsed_digit == digits_code[d]) { +					current_number += (int) pow(10, OUTPUT_DIGIT_SIZE - 1 - n) * d; +					break; +				} +			} +			// next digit +			token = strtok(NULL, " "); +		} +		sum += current_number; +		//free(line); TODO causes memory corruption +	} +	CHECK(sum, 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; +} @@ -1,7 +1,7 @@  CC=cc  CFLAGS=-std=c1x -W -Wall -g -LDFLAGS= -EXEC=01 02 03 04 05 06 07 +LDFLAGS=-lm +EXEC=01 02 03 04 05 06 07 08  all: $(EXEC) @@ -29,5 +29,8 @@ all: $(EXEC)  07: input.o 07.o  	$(CC) -o $@ $> $(LDFLAGS) +08: input.o 08.o +	$(CC) -o $@ $> $(LDFLAGS) +  clean:  	rm -rf *.o $(EXEC) @@ -40,6 +40,20 @@ void input_int_read(struct input_int* result, char* filename) {  	fclose(file);  } +int str_replace(char* string, char a, char b) { +	size_t i = 0; +	int replace_count = 0; +	while(string[i] != '\0') { +		if(string[i] == a) { +			string[i] = b; +			replace_count++; +		} +		i++; +	} + +	return replace_count; +} +  void input_str_read(struct input_str* result, char* filename) {  	// open input file  	FILE* file=fopen(filename, "r"); @@ -57,6 +71,9 @@ void input_str_read(struct input_str* result, char* filename) {  		char** dst = &(result->lines[lineIndex]);  		if(getline(dst, &lineSize, file) < 0)  			err(1, "read error line %ld\n", lineIndex); + +		// cleanup line end char +		str_replace(result->lines[lineIndex], '\n', '\0');  	}  	fclose(file);  | 
