2
\$\begingroup\$

I am relatively new to C programming and am currently completeing challenges of Advent of Code 2021 to elevate my skills. I am excited to share my solution for the puzzle on Day 3 and am eager to receive constructive feedback to enhance the quality of my code.

Problem Summary

The problem is divided into two distinct parts, each requiring careful computation to derive a numerical score.

Part One

In this segment, the task involves processing a file input. For each line in the file, the line is split into two halves. The goal is to identify the first repeating character in each pair and assign a score to it based on the rule described below. The accumulated scores contribute to the overall total.

Part Two

The second part continues with file input processing, where every three consecutive lines form a group. The objective is to find the common letter among the three lines and score it according to the provided rules. The resulting scores are added to the final cumulative score.

Scoring Rule

  • Lowercase item types 'a' through 'z' are assigned priorities 1 through 26.
  • Uppercase item types 'A' through 'Z' have priorities 27 through 52.

Code Implementation

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAX_BUFFER_SIZE 100

bool fileOpener(int argc, char *argv[], FILE **file) {
    if (argc == 1) {
        printf("No file has been provided\n");
        return false;
    }

    *file = fopen(argv[1], "r"); // Use "r" for reading text files
    if (*file == NULL) {
        perror("Error opening file");
        return false;
    }

    return true;
}

int len_str(const char *str) {
    int len = 0;
    while (str[len] != '\0') {
        len++;
    }
    return len;
}

char find_repeat_chr(const char *buf) {
    int str_len = len_str(buf);
    for (int i = 0; i < str_len / 2; i++) {
        for (int j = str_len / 2; j < str_len; j++) {
            if (buf[i] == buf[j]) {
                return buf[i];
            }
        }
    }
    return '\0';
}

char* intersection_str(const char *buf1, const char *buf2) {
    int str_len1 = len_str(buf1);
    int str_len2 = len_str(buf2);

    // Allocate memory for the intersection buffer
    char buf[str_len1 > str_len2 ? str_len1 + 1 : str_len2 + 1];

    int i = 0;
    for (int j = 0; j < str_len1; j++) {
        for (int k = 0; k < str_len2; k++) {
            if (buf1[j] == buf2[k]) {
                bool flag = true;
                for (int l = 0; l<i; l++){
                    if (buf1[j] == buf[l]){
                        flag = false;
                    }
                }
                if (flag){
                    buf[i] = buf1[j];
                    i++;
                }
            }
        }
    }
    // copy to malloc
    char *return_buf = (char*)malloc( sizeof(char) * (i+1));
    if (return_buf == NULL) {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }
    for (int j = 0; j < i; j++){
        return_buf[j]=buf[j];
    }
    return_buf[i] = '\0';
    return return_buf;
}

bool update_score(char repeat, int *score) {
    if (repeat != '\0') {
        if (repeat >= 'A' && repeat <= 'Z') {
            *score += 27;
            *score += repeat - 'A';
        } else if (repeat >= 'a' && repeat <= 'z') {
            *score += 1;
            *score += repeat - 'a';
        }
        return true;
    } else {
        return false;
    }
}

bool tally_part1(FILE *file, int *score) {
    char buf[MAX_BUFFER_SIZE];

    while (fgets(buf, sizeof buf, file) != NULL) {
        char repeat = find_repeat_chr(buf);
        if (!update_score(repeat, score)) {
            return false;
        }
    }

    return true;
}

bool tally_part2(FILE *file, int *score) {
    char buf1[MAX_BUFFER_SIZE];
    char buf2[MAX_BUFFER_SIZE];
    char buf3[MAX_BUFFER_SIZE];

    while (1) {
        if (fgets(buf1, sizeof buf1, file) == NULL || fgets(buf2, sizeof buf2, file) == NULL ||
            fgets(buf3, sizeof buf3, file) == NULL) {
            break;
        }

        char *buf = intersection_str(intersection_str(buf1, buf2), buf3);

        if (!update_score(buf[0], score)) {
            free(buf);
            return false;
        }

        free(buf);
    }

    return true;
}

void report_result(int score) {
    printf("%i\n", score);
}

int main(int argc, char *argv[]) {
    FILE *file = NULL;
    if (!fileOpener(argc, argv, &file)) {
        return 1;
    }

    int score = 0;
    if (!tally_part1(file, &score)) {
        printf("Tally part 1 failed\n");
        fclose(file);
        return 1;
    }
    report_result(score);

    fseek(file, 0, SEEK_SET);
    score = 0;
    if (!tally_part2(file, &score)) {
        printf("Tally part 2 failed\n");
        fclose(file);
        return 1;
    }
    report_result(score);

    fclose(file);
    return 0;
}

Your insights and guidance on optimizing and refining the presented code would be immensely valuable. Any constructive feedback or advice you can provide will be highly appreciated.

Thank you for your time and assistance!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Why not use strlen() from string.h instead of writing your own len_str()? \$\endgroup\$
    – Harith
    Commented Jan 30 at 11:39
  • \$\begingroup\$ I think this is a inadequately well defined programming challenge. It doesn't say how long the lines can be, something which can make a big difference to how it should be coded. The link you provided doesn't say anything about groups of lines as mentioned in your 'Part 2'. Where does that come from? \$\endgroup\$ Commented Feb 6 at 22:51

0

Browse other questions tagged or ask your own question.