diff --git a/include/bfs.h b/include/bfs.h new file mode 100644 index 0000000..695ec63 --- /dev/null +++ b/include/bfs.h @@ -0,0 +1,17 @@ +#ifndef BFS_H +#define BFS_H + +#include "utils.h" + +/** + * @brief Runs a BFS to find the minimum moves to reach a triplet with zero + * @param sum Pointer to store the sum of moves for the found solution + * @param a0 The initial value of a + * @param b0 The initial value of b + * @param c0 The initial value of c + * @param print_mode The mode for printing the results (1 for full, 2 for minimal) + * @return 1 if a solution is found, 0 otherwise + */ +int run_bfs(int128_t* sum, int128_t a0, int128_t b0, int128_t c0, int print_mode); + +#endif /* BFS_H */ \ No newline at end of file diff --git a/include/core.h b/include/core.h deleted file mode 100755 index a7901be..0000000 --- a/include/core.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CORE_H -#define CORE_H - -__extension__ typedef __int128 int128_t; -__extension__ typedef unsigned __int128 uint128_t; - -// Read 128 bit integers as string -int read_int128_triplet(const char* prompt, int128_t* a, int128_t* b, int128_t* c); - -// Convert the read string into 128 bit integers -int128_t str_to_int128(const char* s); - -// Print 128 but integers -void print_int128(int128_t n); - -#endif \ No newline at end of file diff --git a/include/hash.h b/include/hash.h new file mode 100644 index 0000000..51a3c27 --- /dev/null +++ b/include/hash.h @@ -0,0 +1,25 @@ +#ifndef HASH_H +#define HASH_H + +#include "utils.h" + +#define HASH_SIZE 2000003 + +/** + * @brief Hashes three 128-bit integers into a single unsigned int + * @param a The first integer + * @param b The second integer + * @param c The third integer + * @return A hash value for the three integers + */ +unsigned int hash_three128(uint128_t a, uint128_t b, uint128_t c); + +/** + * @brief Sorts a triplet of 128-bit integers in ascending order + * @param a Pointer to the first integer + * @param b Pointer to the second integer + * @param c Pointer to the third integer + */ +void sort_triplet(int128_t* a, int128_t* b, int128_t* c); + +#endif /* HASH_H */ \ No newline at end of file diff --git a/include/io.h b/include/io.h new file mode 100755 index 0000000..fddaad1 --- /dev/null +++ b/include/io.h @@ -0,0 +1,29 @@ +#ifndef IO_H +#define IO_H + +#include "utils.h" + +/* + * @brief Reads three 128 bit integers from the user with a prompt + * @param prompt The message to display to the user before reading input + * @param a Pointer to store the first integer + * @param b Pointer to store the second integer + * @param c Pointer to store the third integer + * @return 0 on success, -1 on printf error, -2 on scanf error + */ +int read_int128_triplet(const char* prompt, int128_t* a, int128_t* b, int128_t* c); + +/* + * @brief Converts a string to a 128 bit integer + * @param s The string to convert + * @return The converted 128 bit integer + */ +int128_t str_to_int128(const char* s); + +/** + * @brief Prints a 128 bit integer + * @param n The integer to print + */ +void print_int128(int128_t n); + +#endif \ No newline at end of file diff --git a/include/maths.h b/include/maths.h index 11109ca..9fde19d 100755 --- a/include/maths.h +++ b/include/maths.h @@ -1,28 +1,71 @@ #ifndef MATHS_H #define MATHS_H -#include "core.h" +#include "utils.h" -// Check if a 128 bit integer is a prime number or not -int is_prime(int128_t n); +/** + * @brief Checks if a 128 bit integer is a prime number + * @param n The integer to check + * @return true if the integer is prime, false otherwise + */ +bool is_prime(int128_t n); -// Calculate the GCD for 3 128 bit integers +/** + * @brief Checks if a 128 bit integer is within the safe limit + * @param x The integer to check + * @return true if the integer is within the safe limit, false otherwise + */ +bool safe_val(int128_t x); + +/** + * @brief Calculates the GCD for 3 128 bit integers + * @param a The first integer + * @param b The second integer + * @param c The third integer + * @return The GCD of the three integers + */ int128_t gcd3(int128_t a, int128_t b, int128_t c); -// Calculate the GCD for 2 128 bit integers +/** + * @brief Calculates the GCD for 2 128 bit integers + * @param a The first integer + * @param b The second integer + * @return The GCD of the two integers + */ int128_t gcd2(int128_t a, int128_t b); -// Return the absolute value of a 128 bit integer +/** + * @brief Returns the absolute value of a 128 bit integer + * @param x The integer to get the absolute value of + * @return The absolute value of the integer + */ int128_t abs128(int128_t x); -// Raise a number a certain exponent +/** + * @brief Calculates b raised to the power of ex for 128 bit integers + * @param b The base integer + * @param ex The exponent integer + * @return The result of b raised to the power of ex + */ int128_t power(int128_t b, int128_t ex); -// Generate the factor pairs +/** + * @brief Generates factor pairs for a 128 bit integer + * @param sum Pointer to store the sum of the factor pairs + * @param prime_index The index of the prime number to use + * @param exponents Pointer to the array of exponents + * @param values Pointer to the array of values + * @param n1 The first integer + * @param print_mode The mode for printing the results + */ void generate_factor_pairs(int128_t* sum, int prime_index, int* exponents, - int128_t* values, int128_t n1, int print_mode); + int128_t* values, int128_t n1, int print_mode); -// Calculate the square root of an unsigned 128 bit integer +/** + * @brief Calculates the square root of an unsigned 128 bit integer + * @param number The integer to calculate the square root of + * @return The square root of the integer + */ uint128_t mysqrt_uint128(uint128_t number); #endif \ No newline at end of file diff --git a/include/node.h b/include/node.h new file mode 100644 index 0000000..515ef64 --- /dev/null +++ b/include/node.h @@ -0,0 +1,66 @@ +#ifndef NODES_H +#define NODES_H + +#include "utils.h" + +typedef struct Node { + int128_t a, b, c; + char move; + struct Node* parent; + struct Node* next; +} Node; + +/** + * @brief Initializes the node pool with a specified maximum number of nodes + * @param max_nodes The maximum number of nodes the pool can hold + */ +void node_pool_init(int max_nodes); + +/** + * @brief Allocates a node from the pool + * @return A pointer to the allocated node, or NULL if the pool is exhausted + */ +Node* node_pool_alloc(); + +/** + * @brief Resets the node pool without freeing memory + */ +void node_pool_reset(); + +/** + * @brief Frees the node pool memory + */ +void node_pool_destroy(); + +/** + * @brief Returns the current usage of the node pool + * @return The number of nodes currently allocated from the pool + */ +int node_pool_usage(); + +/** + * @brief Tries to push child nodes based on the current node's move + * @param curr The current node + */ +void try_push_children(Node* curr); + +typedef struct VisitedEntry { + int128_t a, b, c; + struct VisitedEntry* next; +} VisitedEntry; + +/** + * @brief Marks a triplet as visited and checks if it's new + * @param a The first integer of the triplet + * @param b The second integer of the triplet + * @param c The third integer of the triplet + * @return 1 if the triplet is new and marked, 0 if it was already visited + */ +int visit_and_mark(int128_t a, int128_t b, int128_t c); + +/** + * @brief Clears the hash table + */ +void clear_hash_table(); + +#endif /* NODES_H */ \ No newline at end of file diff --git a/include/queue.h b/include/queue.h new file mode 100644 index 0000000..55975bb --- /dev/null +++ b/include/queue.h @@ -0,0 +1,41 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include "utils.h" +#include "node.h" + +/** + * @brief Initializes the queue with a maximum number of elements + * @param max_elements The maximum number of elements the queue can hold + */ +void q_init(int max_elements); + +/** + * @brief Pushes a node into the queue + * @param n The node to push into the queue + */ +void q_push(Node* n); + +/** + * @brief Returns the node from the front of the queue + * @return The node from the front of the queue + */ +Node* q_pop(); + +/** + * @brief Returns the current size of the queue + * @return The current size of the queue + */ +int q_size(); + +/** + * @brief Clears the queue without freeing memory + */ +void q_clear(); + +/** + * @brief Reset the queue memory + */ +void q_destroy(); + +#endif \ No newline at end of file diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..fa8d958 --- /dev/null +++ b/include/utils.h @@ -0,0 +1,9 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +__extension__ typedef __int128 int128_t; +__extension__ typedef unsigned __int128 uint128_t; + +#endif /* UTILS_H */ \ No newline at end of file diff --git a/src/bfs.c b/src/bfs.c new file mode 100644 index 0000000..89cc743 --- /dev/null +++ b/src/bfs.c @@ -0,0 +1,77 @@ +#include "bfs.h" +#include "node.h" +#include "queue.h" +#include "io.h" + +#include +#include + +int run_bfs(int128_t* sum, int128_t a0, int128_t b0, int128_t c0, int print_mode) { + node_pool_reset(); + q_clear(); + clear_hash_table(); + + Node* root = node_pool_alloc(); + if (!root) return 0; + + root->a = a0; root->b = b0; root->c = c0; + root->move = '\0'; root->parent = NULL; + + q_push(root); + visit_and_mark(a0, b0, c0); + + Node* found = NULL; + while (q_size() > 0) { + Node* curr = q_pop(); + + /* Goal Check */ + if (curr->a == 0 || curr->b == 0 || curr->c == 0) { + found = curr; + break; + } + + try_push_children(curr); + } + + if (!found) { + if (print_mode == 1) printf("No solution found.\n"); + return 0; + } + + int max_moves = 0; + for (Node* p = found; p && p->move != '\0'; p = p->parent) max_moves++; + + char* moves; + if (print_mode == 1) { + moves = malloc(max_moves + 1); + if (!moves) { fprintf(stderr, "Out of memory\n"); return 0; } + moves[max_moves] = '\0'; + + Node* p = found; + int idx = max_moves - 1; + while (p && p->move != '\0') { + moves[idx--] = p->move; + p = p->parent; + } + + printf("\nSolution found!\n"); + printf("Initial: ("); + print_int128(a0); printf(", "); + print_int128(b0); printf(", "); + print_int128(c0); printf(")\n"); + + printf("Final: ("); + print_int128(found->a); printf(", "); + print_int128(found->b); printf(", "); + print_int128(found->c); printf(")\n"); + + printf("Moves (%d): %s\n", max_moves, moves); + } else if (print_mode == 2) { + print_int128(c0); + printf(" the required amount of moves is: %d\n", max_moves); + } + *sum+=max_moves; + + if (print_mode == 1) free(moves); + return 1; +} \ No newline at end of file diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..8f2ae40 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,15 @@ +#include "hash.h" + +unsigned int hash_three128(uint128_t a, uint128_t b, uint128_t c) { + uint128_t x = a + (uint128_t)0x9e3779b97f4a7c15ULL + ((uint128_t)0x9e3779b97f4a7c15ULL << 64); + x ^= b + ((uint128_t)0xbf58476d1ce4e5b9ULL + ((uint128_t)0xbf58476d1ce4e5b9ULL << 64)) + (x << 6) + (x >> 2); + x ^= c + ((uint128_t)0x94d049bb133111ebULL + ((uint128_t)0x94d049bb133111ebULL << 64)) + (x << 6) + (x >> 2); + return (unsigned int)(x % HASH_SIZE); +} + +void sort_triplet(int128_t* a, int128_t* b, int128_t* c) { + int128_t tmp; + if (*a > *b) { tmp = *a; *a = *b; *b = tmp; } + if (*b > *c) { tmp = *b; *b = *c; *c = tmp; } + if (*a > *b) { tmp = *a; *a = *b; *b = tmp; } +} \ No newline at end of file diff --git a/src/core.c b/src/io.c similarity index 97% rename from src/core.c rename to src/io.c index 3f2ac1b..2fb3f25 100755 --- a/src/core.c +++ b/src/io.c @@ -1,4 +1,4 @@ -#include "core.h" +#include "io.h" #include #include diff --git a/src/maths.c b/src/maths.c index dfed2a1..113f041 100755 --- a/src/maths.c +++ b/src/maths.c @@ -10,13 +10,18 @@ extern int is_new_root(int128_t a, int128_t b, int128_t c); const int NUM_PRIMES = 3; const int primes[] = {2, 3, 5}; -int is_prime(int128_t n) { - if (n < 2) return 0; - if (n == 2) return 1; - if (n % 2 == 0) return 0; +bool is_prime(int128_t n) { + if (n < 2) return false; + if (n == 2) return true; + if (n % 2 == 0) return false; for (int128_t i = 3; i <= n / i; i += 2) - if (n % i == 0) return 0; - return 1; + if (n % i == 0) return false; + return true; +} + +bool safe_val(int128_t x) { + if (x > LIMIT || x < -LIMIT) return false; + return true; } int128_t gcd3(int128_t a, int128_t b, int128_t c) { @@ -50,7 +55,7 @@ int128_t power(int128_t b, int128_t ex) { } void generate_factor_pairs(int128_t* sum, int prime_index, int* exponents, - int128_t* values, int128_t n1, int print_mode) { + int128_t* values, int128_t n1, int print_mode) { if (prime_index == NUM_PRIMES) { int128_t n2 = values[0] / n1; if (n1 > n2) return; diff --git a/src/node.c b/src/node.c new file mode 100644 index 0000000..a4d0e1c --- /dev/null +++ b/src/node.c @@ -0,0 +1,123 @@ +#include "node.h" +#include "hash.h" +#include "maths.h" +#include "queue.h" + +#include +#include + +static Node* pool = NULL; +static VisitedEntry* visited_pool = NULL; +static VisitedEntry* hash_table[HASH_SIZE] = {0}; +static int pool_ptr = 0; +static int pool_capacity = 0; +static int visited_ptr = 0; + +void node_pool_init(int max_nodes) { + pool_capacity = max_nodes; + pool = malloc(pool_capacity * sizeof(Node)); + visited_pool = malloc(pool_capacity * sizeof(VisitedEntry)); + if (!pool || !visited_pool) { + fprintf(stderr, "Fatal: Could not allocate Node Pool for %d nodes.\n", max_nodes); + exit(1); + } + pool_ptr = 0; + visited_ptr = 0; + for (size_t i = 0; i < HASH_SIZE; ++i) hash_table[i] = NULL; +} + +Node* node_pool_alloc() { + if (pool_ptr >= pool_capacity) { + fprintf(stderr, "\nNode Pool Overflow! Need more than %d nodes.\n", pool_capacity); + return NULL; + } + return &pool[pool_ptr++]; +} + +void node_pool_reset() { + pool_ptr = 0; +} + +void node_pool_destroy() { + if (pool) free(pool); +} + +int node_pool_usage() { + return pool_ptr; +} + +static void make_move(char move, Node* curr) { + int128_t na = curr->a, nb = curr->b, nc = curr->c; + + /* Calculate the new triplet based on the move type */ + if (move == 'A') { + na = 2 * (curr->b + curr->c) - curr->a; + } else if (move == 'B') { + nb = 2 * (curr->a + curr->c) - curr->b; + } else if (move == 'C') { + nc = 2 * (curr->a + curr->b) - curr->c; + } + + /* Validation and Enqueue */ + if (safe_val(na) && safe_val(nb) && safe_val(nc)) { + if (visit_and_mark(na, nb, nc)) { + if (pool_ptr >= pool_capacity) return; /* Pool safety */ + Node* n = &pool[pool_ptr++]; + n->a = na; n->b = nb; n->c = nc; + n->move = move; + n->parent = curr; + n->next = NULL; + q_push(n); + } + } +} + +void try_push_children(Node* curr) { + char last = curr->move; + + if (last == '\0') { + make_move('A', curr); + make_move('B', curr); + make_move('C', curr); + return; + } + + if (last == 'A') { + make_move('C', curr); + make_move('B', curr); + } + else if (last == 'B') { + make_move('C', curr); + make_move('A', curr); + } + else if (last == 'C') { + make_move('B', curr); + make_move('A', curr); + } +} + +int visit_and_mark(int128_t a, int128_t b, int128_t c) { + sort_triplet(&a, &b, &c); + unsigned int h = hash_three128(a,b,c); + VisitedEntry* cur = hash_table[h]; + while (cur) { + if (cur->a == a && cur->b == b && cur->c == c) return 0; + cur = cur->next; + } + + if (visited_ptr >= pool_capacity) { + fprintf(stderr, "VisPool Overflow! Increase MAX_NODES.\n"); + exit(1); + } + + VisitedEntry* e = &visited_pool[visited_ptr++]; + e->a = a; e->b = b; e->c = c; + e->next = hash_table[h]; + hash_table[h] = e; + return 1; +} + +void clear_hash_table() { + visited_ptr = 0; + for (size_t i = 0; i < HASH_SIZE; ++i) hash_table[i] = NULL; +} \ No newline at end of file diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000..254b7a9 --- /dev/null +++ b/src/queue.c @@ -0,0 +1,63 @@ +#include "queue.h" +#include +#include + +static Node* q_front = NULL; +static Node* q_back = NULL; +static int current_size = 0; +static int capacity = 0; + +void q_init(int max_elements) { + capacity = max_elements; + q_front = NULL; + q_back = NULL; + current_size = 0; +} + +void q_push(Node* n) { + if (current_size >= capacity) return; /* Pool safety */ + + /* Exact logic from your 'enqueue' function */ + n->next = NULL; + if (!q_back) { + q_front = q_back = n; + } else { + q_back->next = n; + q_back = n; + } + current_size++; +} + +Node* q_pop() { + /* Exact logic from your 'dequeue' function */ + if (!q_front) return NULL; + + Node* r = q_front; + q_front = q_front->next; + + if (!q_front) { + q_back = NULL; + } + + r->next = NULL; /* Clean up the link */ + current_size--; + + return r; +} + +int q_size() { + return current_size; +} + +void q_clear() { + q_front = NULL; + q_back = NULL; + current_size = 0; +} + +void q_destroy() { + q_front = NULL; + q_back = NULL; + current_size = 0; + capacity = 0; +} \ No newline at end of file diff --git a/src/stergios.c b/src/stergios.c old mode 100755 new mode 100644 index 7215928..d8d85b4 --- a/src/stergios.c +++ b/src/stergios.c @@ -1,12 +1,15 @@ -#include "core.h" +#include "utils.h" #include "maths.h" +#include "hash.h" +#include "node.h" +#include "queue.h" +#include "bfs.h" +#include "io.h" #include #include -#define HASH_SIZE 2000003 -#define MAX_NODES 40000000 // 40 Million nodes (~4.5GB RAM) -int128_t LIMIT = 0; +int LIMIT = 0; typedef struct GlobalEntry { int128_t a, b, c; @@ -15,27 +18,6 @@ typedef struct GlobalEntry { static GlobalEntry* global_root_table[HASH_SIZE] = {0}; -// Helper to sort the triplet so order doesn't matter -static void sort_triplet(int128_t* a, int128_t* b, int128_t* c) { - int128_t tmp; - if (*a > *b) { tmp = *a; *a = *b; *b = tmp; } - if (*b > *c) { tmp = *b; *b = *c; *c = tmp; } - if (*a > *b) { tmp = *a; *a = *b; *b = tmp; } -} - -static inline uint128_t mix128(uint128_t a, uint128_t b, uint128_t c) { - uint128_t x = a + (uint128_t)0x9e3779b97f4a7c15ULL + ((uint128_t)0x9e3779b97f4a7c15ULL << 64); - x ^= b + ((uint128_t)0xbf58476d1ce4e5b9ULL + ((uint128_t)0xbf58476d1ce4e5b9ULL << 64)) + (x << 6) + (x >> 2); - x ^= c + ((uint128_t)0x94d049bb133111ebULL + ((uint128_t)0x94d049bb133111ebULL << 64)) + (x << 6) + (x >> 2); - return x; -} - -static unsigned int hash_three128(uint128_t a, uint128_t b, uint128_t c) { - uint128_t x = mix128(a, b, c); - return (unsigned int)(x % HASH_SIZE); -} - -// Returns 1 if this is a new root, 0 if we've already calculated it int is_new_root(int128_t a, int128_t b, int128_t c) { sort_triplet(&a, &b, &c); unsigned int h = hash_three128((uint128_t)a, (uint128_t)b, (uint128_t)c); @@ -47,14 +29,13 @@ int is_new_root(int128_t a, int128_t b, int128_t c) { } GlobalEntry* e = malloc(sizeof(GlobalEntry)); - if (!e) return 1; // Fallback to running BFS if malloc fails + if (!e) return 1; /* Fallback to running BFS if malloc fails */ e->a = a; e->b = b; e->c = c; e->next = global_root_table[h]; global_root_table[h] = e; return 1; } -// Call this at the start of 'auto' mode void clear_global_table() { for (int i = 0; i < HASH_SIZE; i++) { GlobalEntry* cur = global_root_table[i]; @@ -67,220 +48,14 @@ void clear_global_table() { } } -typedef struct Node { - int128_t a, b, c; - char move; - struct Node* parent; - struct Node* next; -} Node; - -typedef struct VisEntry { - int128_t a, b, c; - struct VisEntry* next; -} VisEntry; - -// Pre-allocated Pools -static Node* node_pool = NULL; -static VisEntry* vis_pool = NULL; -static int node_ptr = 0; -static int vis_ptr = 0; -static Node* q_front = NULL; -static Node* q_back = NULL; - -static VisEntry* hash_table[HASH_SIZE] = {0}; - -// O(1) Clear: Just reset the pointers and null the hash table -void clear_hash_table() { - vis_ptr = 0; - for (size_t i = 0; i < HASH_SIZE; ++i) hash_table[i] = NULL; -} - -void drain_queue() { - node_ptr = 0; - q_front = q_back = NULL; -} - -static int visit_and_mark(int128_t a, int128_t b, int128_t c) { - sort_triplet(&a, &b, &c); - unsigned int h = hash_three128(a,b,c); - VisEntry* cur = hash_table[h]; - while (cur) { - if (cur->a == a && cur->b == b && cur->c == c) return 0; - cur = cur->next; - } - - if (vis_ptr >= MAX_NODES) { - fprintf(stderr, "VisPool Overflow! Increase MAX_NODES.\n"); - exit(1); - } - - VisEntry* e = &vis_pool[vis_ptr++]; - e->a = a; e->b = b; e->c = c; - e->next = hash_table[h]; - hash_table[h] = e; - return 1; -} - - -static void enqueue(Node* n) { - n->next = NULL; - if (!q_back) q_front = q_back = n; - else { - q_back->next = n; - q_back = n; - } -} - -static Node* dequeue() { - if (!q_front) return NULL; - Node* r = q_front; - q_front = q_front->next; - if (!q_front) q_back = NULL; - r->next = NULL; - return r; -} - -static int safe_val(int128_t x) { - if (x > LIMIT || x < -LIMIT) return 0; - return 1; -} - -static void make_move(char move, Node* curr) { - int128_t na = curr->a, nb = curr->b, nc = curr->c; - - // Calculate the new triplet based on the move type - if (move == 'A') { - na = 2 * (curr->b + curr->c) - curr->a; - } else if (move == 'B') { - nb = 2 * (curr->a + curr->c) - curr->b; - } else if (move == 'C') { - nc = 2 * (curr->a + curr->b) - curr->c; - } - - // Validation and Enqueue - if (safe_val(na) && safe_val(nb) && safe_val(nc)) { - if (visit_and_mark(na, nb, nc)) { - if (node_ptr >= MAX_NODES) return; // Pool safety - Node* n = &node_pool[node_ptr++]; - n->a = na; n->b = nb; n->c = nc; - n->move = move; - n->parent = curr; - n->next = NULL; - enqueue(n); - } - } -} - -static void try_push_children(Node* curr) { - char last = curr->move; - - // Root node doesn't have a 'last' move, so try all three. - if (last == '\0') { - make_move('A', curr); - make_move('B', curr); - make_move('C', curr); - return; - } - - // To avoid AAAA, BBBB, or CCCC, we only pick from the other two moves. - // We also prioritize B and C to favor the alternating CBCB pattern. - if (last == 'A') { - // Just did A: try C then B (the two non-A moves) - make_move('C', curr); - make_move('B', curr); - } - else if (last == 'B') { - // Just did B: try C (alternating) then A (neutral) - // We skip B because it would just take us back to the parent. - make_move('C', curr); - make_move('A', curr); - } - else if (last == 'C') { - // Just did C: try B (alternating) then A (neutral) - // We skip C because it's redundant. - make_move('B', curr); - make_move('A', curr); - } -} - -int run_bfs(int128_t* sum, int128_t a0, int128_t b0, int128_t c0, int print_mode) { - drain_queue(); - clear_hash_table(); - - if (node_ptr >= MAX_NODES) return 0; - Node* root = &node_pool[node_ptr++]; - root->a = a0; root->b = b0; root->c = c0; - root->move = '\0'; root->parent = NULL; root->next = NULL; - enqueue(root); - visit_and_mark(a0, b0, c0); - - Node* found = NULL; - while ((root = dequeue()) != NULL) { - if (root->a == 0 || root->b == 0 || root->c == 0) { found = root; break; } - try_push_children(root); - } - - if (!found) { - printf("No solution found within bounds/search limits.\n"); - drain_queue(); - clear_hash_table(); - return 0; - } - - int max_moves = 0; - for (Node* p = found; p && p->move != '\0'; p = p->parent) max_moves++; - - char* moves; - if (print_mode == 1) { - moves = malloc(max_moves + 1); - if (!moves) { fprintf(stderr, "Out of memory\n"); return 0; } - moves[max_moves] = '\0'; - - Node* p = found; - int idx = max_moves - 1; - while (p && p->move != '\0') { - moves[idx--] = p->move; - p = p->parent; - } - - printf("\nSolution found!\n"); - printf("Initial: ("); - print_int128(a0); printf(", "); - print_int128(b0); printf(", "); - print_int128(c0); printf(")\n"); - - printf("Final: ("); - print_int128(found->a); printf(", "); - print_int128(found->b); printf(", "); - print_int128(found->c); printf(")\n"); - - printf("Moves (%d): %s\n", max_moves, moves); - } else if (print_mode == 2) { - print_int128(c0); - printf(" the required amount of moves is: %d\n", max_moves); - } - *sum+=max_moves; - - if (print_mode == 1) free(moves); - drain_queue(); - clear_hash_table(); - - return 1; -} - int main() { - // Allocate the giant pools once - node_pool = malloc(sizeof(Node) * MAX_NODES); - vis_pool = malloc(sizeof(VisEntry) * MAX_NODES); + node_pool_init(20000000); + q_init(20000000); - if (!node_pool || !vis_pool) { - fprintf(stderr, "Failed to allocate memory pools. Try a smaller MAX_NODES.\n"); - return 1; - } + int mode = 0, print_mode = 0; + int128_t a0 = 10, b0 = 6, c0 = 0, sum = 0; - int mode = 0, print_mode = 0; - int128_t a0 = 10, b0 = 6, c0 = 0, sum = 0; - while (mode == 0) { + while (mode == 0) { if (printf("1: manual\n") < 0) return 1; if (printf("2: auto\n") < 0) return 1; if (printf("Choose what mode you want to enter: ") < 0) return 1; @@ -289,9 +64,9 @@ int main() { return 1; } if (mode != 1 && mode != 2) mode = 0; - } + } - while (print_mode == 0) { + while (print_mode == 0) { if (printf("1: Print full?\n") < 0) return 1; if (printf("2: Print minimal?\n") < 0) return 1; if (printf("Choose what mode you want to enter: ") < 0) return 1; @@ -302,7 +77,7 @@ int main() { if (print_mode != 1 && print_mode != 2) print_mode = 0; } - if (mode == 1) { + if (mode == 1) { if (read_int128_triplet("Enter initial a b c:", &a0, &b0, &c0) != 0) { fprintf(stderr, "Input error.\n"); return 1; @@ -315,20 +90,17 @@ int main() { print_int128(c0); printf(")\n"); return 0; } + int128_t gcd = gcd3(a0, b0, c0); + int128_t a = a0 / gcd, b = b0 / gcd, c = c0 / gcd; + + int128_t greater = b >= c ? b : c; + LIMIT = a >= greater ? a * greater : b * c; - int128_t greater = b0 >= c0 ? b0 : c0; - int128_t gcd = gcd3(a0, b0, c0); - LIMIT = a0 >= greater ? a0 * greater / (2 * gcd * gcd) : b0 * c0 / (2 * gcd * gcd); - - if (!safe_val(a0) || !safe_val(b0) || !safe_val(c0)) { - fprintf(stderr, "Initial values exceed safe limit.\n"); - return 1; - } - - run_bfs(&sum, a0 / gcd, b0 / gcd, c0 / gcd, print_mode); - } else if (mode == 2) { - clear_global_table(); // Reset unique root tracker - int p = 3; + run_bfs(&sum, a, b, c, print_mode); + } + else if (mode == 2) { + clear_global_table(); /* Reset unique root tracker */ + int p = 6; int exponents[3] = {2*p + 2, p, p}; int128_t values[3] = {4 * power(a0, p) * power(b0, p), power(a0, p), power(b0, p)}; generate_factor_pairs(&sum, 0, exponents, values, 1, print_mode); @@ -336,5 +108,8 @@ int main() { printf("Total sum is: "); print_int128(sum); printf("\n"); } - return 0; + + node_pool_destroy(); + q_destroy(); + return 0; } \ No newline at end of file