Task: Sum and product puzzle

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

typedef struct node_t {
    int x, y;
    struct node_t *prev, *next;
} node;

node *new_node(int x, int y) {
    node *n = malloc(sizeof(node));
    n->x = x;
    n->y = y;
    n->next = NULL;
    n->prev = NULL;
    return n;
}

void free_node(node **n) {
    if (n == NULL) {
        return;
    }

    (*n)->prev = NULL;
    (*n)->next = NULL;

    free(*n);

    *n = NULL;
}

typedef struct list_t {
    node *head;
    node *tail;
} list;

list make_list() {
    list lst = { NULL, NULL };
    return lst;
}

void append_node(list *const lst, int x, int y) {
    if (lst == NULL) {
        return;
    }

    node *n = new_node(x, y);

    if (lst->head == NULL) {
        lst->head = n;
        lst->tail = n;
    } else {
        n->prev = lst->tail;
        lst->tail->next = n;
        lst->tail = n;
    }
}

void remove_node(list *const lst, const node *const n) {
    if (lst == NULL || n == NULL) {
        return;
    }

    if (n->prev != NULL) {
        n->prev->next = n->next;
        if (n->next != NULL) {
            n->next->prev = n->prev;
        } else {
            lst->tail = n->prev;
        }
    } else {
        if (n->next != NULL) {
            n->next->prev = NULL;
            lst->head = n->next;
        }
    }

    free_node(&n);
}

void free_list(list *const lst) {
    node *ptr;

    if (lst == NULL) {
        return;
    }
    ptr = lst->head;

    while (ptr != NULL) {
        node *nxt = ptr->next;
        free_node(&ptr);
        ptr = nxt;
    }

    lst->head = NULL;
    lst->tail = NULL;
}

void print_list(const list *lst) {
    node *it;

    if (lst == NULL) {
        return;
    }

    for (it = lst->head; it != NULL; it = it->next) {
        int sum = it->x + it->y;
        int prod = it->x * it->y;
        printf("[%d, %d] S=%d P=%d\n", it->x, it->y, sum, prod);
    }
}

void print_count(const list *const lst) {
    node *it;
    int c = 0;

    if (lst == NULL) {
        return;
    }

    for (it = lst->head; it != NULL; it = it->next) {
        c++;
    }

    if (c == 0) {
        printf("no candidates\n");
    } else    if (c == 1) {
        printf("one candidate\n");
    } else {
        printf("%d candidates\n", c);
    }
}

void setup(list *const lst) {
    int x, y;

    if (lst == NULL) {
        return;
    }

    
    for (x = 2; x <= 98; x++) {
        
        for (y = x + 1; y <= 98; y++) {
            if (x + y <= 100) {
                append_node(lst, x, y);
            }
        }
    }
}

void remove_by_sum(list *const lst, const int sum) {
    node *it;

    if (lst == NULL) {
        return;
    }

    it = lst->head;
    while (it != NULL) {
        int s = it->x + it->y;

        if (s == sum) {
            remove_node(lst, it);
            it = lst->head;
        } else {
            it = it->next;
        }
    }
}

void remove_by_prod(list *const lst, const int prod) {
    node *it;

    if (lst == NULL) {
        return;
    }

    it = lst->head;
    while (it != NULL) {
        int p = it->x * it->y;

        if (p == prod) {
            remove_node(lst, it);
            it = lst->head;
        } else {
            it = it->next;
        }
    }
}

void statement1(list *const lst) {
    short *unique = calloc(100000, sizeof(short));
    node *it, *nxt;

    for (it = lst->head; it != NULL; it = it->next) {
        int prod = it->x * it->y;
        unique[prod]++;
    }

    it = lst->head;
    while (it != NULL) {
        int prod = it->x * it->y;
        nxt = it->next;
        if (unique[prod] == 1) {
            remove_by_sum(lst, it->x + it->y);
            it = lst->head;
        } else {
            it = nxt;
        }
    }

    free(unique);
}

void statement2(list *const candidates) {
    short *unique = calloc(100000, sizeof(short));
    node *it, *nxt;

    for (it = candidates->head; it != NULL; it = it->next) {
        int prod = it->x * it->y;
        unique[prod]++;
    }

    it = candidates->head;
    while (it != NULL) {
        int prod = it->x * it->y;
        nxt = it->next;
        if (unique[prod] > 1) {
            remove_by_prod(candidates, prod);
            it = candidates->head;
        } else {
            it = nxt;
        }
    }

    free(unique);
}

void statement3(list *const candidates) {
    short *unique = calloc(100, sizeof(short));
    node *it, *nxt;

    for (it = candidates->head; it != NULL; it = it->next) {
        int sum = it->x + it->y;
        unique[sum]++;
    }

    it = candidates->head;
    while (it != NULL) {
        int sum = it->x + it->y;
        nxt = it->next;
        if (unique[sum] > 1) {
            remove_by_sum(candidates, sum);
            it = candidates->head;
        } else {
            it = nxt;
        }
    }

    free(unique);
}

int main() {
    list candidates = make_list();

    setup(&candidates);
    print_count(&candidates);

    statement1(&candidates);
    print_count(&candidates);

    statement2(&candidates);
    print_count(&candidates);

    statement3(&candidates);
    print_count(&candidates);

    print_list(&candidates);

    free_list(&candidates);
    return 0;
}


C++: #include <algorithm>
#include <iostream>
#include <map>
#include <vector>

std::ostream &operator<<(std::ostream &os, std::vector<std::pair<int, int>> &v) {
    for (auto &p : v) {
        auto sum = p.first + p.second;
        auto prod = p.first * p.second;
        os << '[' << p.first << ", " << p.second << "] S=" << sum << " P=" << prod;
    }
    return os << '\n';
}

void print_count(const std::vector<std::pair<int, int>> &candidates) {
    auto c = candidates.size();
    if (c == 0) {
        std::cout << "no candidates\n";
    } else if (c == 1) {
        std::cout << "one candidate\n";
    } else {
        std::cout << c << " candidates\n";
    }
}

auto setup() {
    std::vector<std::pair<int, int>> candidates;

    
    for (int x = 2; x <= 98; x++) {
        
        for (int y = x + 1; y <= 98; y++) {
            if (x + y <= 100) {
                candidates.push_back(std::make_pair(x, y));
            }
        }
    }

    return candidates;
}

void remove_by_sum(std::vector<std::pair<int, int>> &candidates, const int sum) {
    candidates.erase(std::remove_if(
        candidates.begin(), candidates.end(),
        [sum](const std::pair<int, int> &pair) {
            auto s = pair.first + pair.second;
            return s == sum;
        }
    ), candidates.end());
}

void remove_by_prod(std::vector<std::pair<int, int>> &candidates, const int prod) {
    candidates.erase(std::remove_if(
        candidates.begin(), candidates.end(),
        [prod](const std::pair<int, int> &pair) {
            auto p = pair.first * pair.second;
            return p == prod;
        }
    ), candidates.end());
}

void statement1(std::vector<std::pair<int, int>> &candidates) {
    std::map<int, int> uniqueMap;

    std::for_each(
        candidates.cbegin(), candidates.cend(),
        [&uniqueMap](const std::pair<int, int> &pair) {
            auto prod = pair.first * pair.second;
            uniqueMap[prod]++;
        }
    );

    bool loop;
    do {
        loop = false;
        for (auto &pair : candidates) {
            auto prod = pair.first * pair.second;
            if (uniqueMap[prod] == 1) {
                auto sum = pair.first + pair.second;
                remove_by_sum(candidates, sum);

                loop = true;
                break;
            }
        }
    } while (loop);
}

void statement2(std::vector<std::pair<int, int>> &candidates) {
    std::map<int, int> uniqueMap;

    std::for_each(
        candidates.cbegin(), candidates.cend(),
        [&uniqueMap](const std::pair<int, int> &pair) {
            auto prod = pair.first * pair.second;
            uniqueMap[prod]++;
        }
    );

    bool loop;
    do {
        loop = false;
        for (auto &pair : candidates) {
            auto prod = pair.first * pair.second;
            if (uniqueMap[prod] > 1) {
                remove_by_prod(candidates, prod);

                loop = true;
                break;
            }
        }
    } while (loop);
}

void statement3(std::vector<std::pair<int, int>> &candidates) {
    std::map<int, int> uniqueMap;

    std::for_each(
        candidates.cbegin(), candidates.cend(),
        [&uniqueMap](const std::pair<int, int> &pair) {
            auto sum = pair.first + pair.second;
            uniqueMap[sum]++;
        }
    );

    bool loop;
    do {
        loop = false;
        for (auto &pair : candidates) {
            auto sum = pair.first + pair.second;
            if (uniqueMap[sum] > 1) {
                remove_by_sum(candidates, sum);

                loop = true;
                break;
            }
        }
    } while (loop);
}

int main() {
    auto candidates = setup();
    print_count(candidates);

    statement1(candidates);
    print_count(candidates);

    statement2(candidates);
    print_count(candidates);

    statement3(candidates);
    print_count(candidates);

    std::cout << candidates;

    return 0;
}