commit 381896c84f21e2a526c9482edf225bbf671f70a5 Author: Georgios Chatzopoulos Date: Wed May 6 22:21:57 2026 +0300 Uploading my current work to my personal gitea diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7dcef45 --- /dev/null +++ b/Makefile @@ -0,0 +1,147 @@ +# ============================================================ +# C Cross-Platform Build System +# ============================================================ + +# Default Compiler (will be set based on platform) +CC = none + +# Default Compiler Flags +CFLAGS = none + +# Default Platform (will be detected) +PLATFORM = none +ifeq ($(OS),Windows_NT) + PLATFORM = windows +else + PLATFORM = linux +endif + +# Debug flag +DEBUG = -g -DDEBUG=1 + +# ------------------------------------------------------------ +# Include auto-generated dependency files +-include $(OBJ_FILES:.o=.d) + +# ------------------------------------------------------------ +# General information +INCLUDE_FLAGS = -Iinclude + +# Linux-specific information +LINUX_CC = gcc +LINUX_CFLAGS = -O3 $(INCLUDE_FLAGS) -MMD -MP -Wall -Wextra -Werror -pedantic +LINUX_LDFLAGS = -O3 $(INCLUDE_FLAGS) + +# Windows-specific information +WINDOWS_CC = x86_64-w64-mingw32-gcc +WINDOWS_CFLAGS = -O3 $(INCLUDE_FLAGS) -MMD -MP -Wall -Wextra -Werror -pedantic +WINDOWS_LDFLAGS = -O3 $(INCLUDE_FLAGS) + +# ------------------------------------------------------------ +# Project folders +SRC = src +BIN_DIR = ./bin +OBJ_DIR = ./obj + +# ------------------------------------------------------------ +# Detect platform based on make command arguments +ifneq (,$(findstring linux,$(MAKECMDGOALS))) +PLATFORM := linux +endif + +ifneq (,$(findstring windows,$(MAKECMDGOALS))) +PLATFORM := windows +endif + +# ------------------------------------------------------------ +# Project source files +SRC_FILES := $(shell find $(SRC) -name '*.c') +OBJ_FILES := $(patsubst %.c,$(OBJ_DIR)/%.o,$(SRC_FILES)) +TARGET = $(BIN_DIR)/stergios + +# ------------------------------------------------------------ +# Output binary name +ifeq ($(PLATFORM), windows) + CC = $(WINDOWS_CC) + CFLAGS = $(WINDOWS_CFLAGS) + LDFLAGS = $(WINDOWS_LDFLAGS) + OUT = $(TARGET).exe +else ifeq ($(PLATFORM), linux) + CC = $(LINUX_CC) + CFLAGS = $(LINUX_CFLAGS) + LDFLAGS = $(LINUX_LDFLAGS) + OUT = $(TARGET) +endif + +# ------------------------------------------------------------ +# Default Platform (will be detected) +default: $(OUT) + +# ------------------------------------------------------------ +# Help target: Display usage help +help: + @echo "Usage:" + @echo " make - Default Build for your operating system" + @echo " make build linux|windows - Build for your specified platform" + @echo " make debug linux|windows - Build with debug symbols for the engine" + @echo " make run linux|windows - Run the built program" + @echo " make build --debug linux|windows - Build with debug symbols for make" + @echo " make debug --debug linux|windows - Build with debug symbols for make and the engine" + @echo " make run --debug linux|windows - Run with debug symbols" + @echo " make clean - Clean the build directory" + +# ------------------------------------------------------------ +# Ensure build directories exist +check_dirs: + @mkdir -p $(BIN_DIR) + @mkdir -p $(OBJ_DIR) + +# ------------------------------------------------------------ +$(OBJ_DIR)/%.o: %.c | check_dirs + @mkdir -p $(dir $@) + @echo "Compiling $< -> $@" + $(CC) $(CFLAGS) -c $< -o $@ + +# ------------------------------------------------------------ +$(OUT): $(OBJ_FILES) | check_dirs + @echo "Linking final executable: $(OUT)" + $(CC) $(CFLAGS) $(OBJ_FILES) -o $(OUT) $(LDFLAGS) + +# ------------------------------------------------------------ +# Build target +build: $(OUT) + +# ------------------------------------------------------------ +# Run target +run: build +ifeq ($(PLATFORM), windows) + @echo "Running application..." + @start "" "$(OUT)" +else ifeq ($(PLATFORM), linux) + @echo "Running application..." + $(OUT) +else + @echo "Specify a platform: make run linux or make run windows" +endif + +# ------------------------------------------------------------ +# Clean target +clean: + @echo "Cleaning object and bin directories..." + rm -rf $(OBJ_DIR) + rm -rf $(BIN_DIR) + @mkdir -p $(OBJ_DIR) + @mkdir -p $(BIN_DIR) + +# ------------------------------------------------------------ +# Declare linux/windows as fake targets so make doesn’t fail +.PHONY: linux windows +linux: + @true +windows: + @true + +# Debug flag +.PHONY: debug +debug: CFLAGS += DEBUG +debug: $(OUT) \ No newline at end of file diff --git a/include/core.h b/include/core.h new file mode 100755 index 0000000..a7901be --- /dev/null +++ b/include/core.h @@ -0,0 +1,16 @@ +#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/maths.h b/include/maths.h new file mode 100755 index 0000000..11109ca --- /dev/null +++ b/include/maths.h @@ -0,0 +1,28 @@ +#ifndef MATHS_H +#define MATHS_H + +#include "core.h" + +// Check if a 128 bit integer is a prime number or not +int is_prime(int128_t n); + +// Calculate the GCD for 3 128 bit integers +int128_t gcd3(int128_t a, int128_t b, int128_t c); + +// Calculate the GCD for 2 128 bit integers +int128_t gcd2(int128_t a, int128_t b); + +// Return the absolute value of a 128 bit integer +int128_t abs128(int128_t x); + +// Raise a number a certain exponent +int128_t power(int128_t b, int128_t ex); + +// Generate the factor pairs +void generate_factor_pairs(int128_t* sum, int prime_index, int* exponents, + int128_t* values, int128_t n1, int print_mode); + +// Calculate the square root of an unsigned 128 bit integer +uint128_t mysqrt_uint128(uint128_t number); + +#endif \ No newline at end of file diff --git a/src/core.c b/src/core.c new file mode 100755 index 0000000..3f2ac1b --- /dev/null +++ b/src/core.c @@ -0,0 +1,38 @@ +#include "core.h" + +#include +#include + +int read_int128_triplet(const char* prompt, int128_t* a, int128_t* b, int128_t* c) { + char sa[256], sb[256], sc[256]; + + if (printf("%s ", prompt) < 0) return -1; + + if (scanf("%255s %255s %255s", sa, sb, sc) != 3) return -2; + + *a = str_to_int128(sa); + *b = str_to_int128(sb); + *c = str_to_int128(sc); + return 0; +} + +int128_t str_to_int128(const char* s) { + int sign = (*s == '-') ? (s++, -1) : 1; + int128_t v = 0; + while (*s >= '0' && *s <= '9') v = v * 10 + (*s++ - '0'); + return sign * v; +} + +void print_int128(int128_t n) { + if (n == 0) { printf("0"); return; } + char buf[40]; + int i = 0; + int neg = n < 0; + if (neg) n = -n; + while (n > 0) { + buf[i++] = '0' + n % 10; + n /= 10; + } + if (neg) putchar('-'); + while (i--) putchar(buf[i]); +} \ No newline at end of file diff --git a/src/maths.c b/src/maths.c new file mode 100755 index 0000000..ade5918 --- /dev/null +++ b/src/maths.c @@ -0,0 +1,93 @@ +#include "maths.h" + +#include +#include + +extern int128_t LIMIT; +extern int run_bfs(int128_t* sum, int128_t a0, int128_t b0, int128_t c0, int print_mode); + +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; + for (int128_t i = 3; i <= n / i; i += 2) + if (n % i == 0) return 0; + return 1; +} + +int128_t gcd3(int128_t a, int128_t b, int128_t c) { + return gcd2(gcd2(a, b), c); +} + +int128_t gcd2(int128_t a, int128_t b) { + a = a < 0 ? -a : a; + b = b < 0 ? -b : b; + while (b != 0) { + int128_t temp = b; + b = a % b; + a = temp; + } + return a; +} + +int128_t abs128(int128_t x) { + return (x < 0) ? -x : x; +} + +int128_t power(int128_t b, int128_t ex) { + int128_t res = 1; + while (ex > 0) { + if (ex % 2 == 1) res = res * b; + + b = b * b; + ex /= 2; + } + return res; +} + +void generate_factor_pairs(int128_t* sum, int prime_index, int* exponents, + int128_t* values, int128_t n1, int print_mode) { + if (prime_index == NUM_PRIMES) { + int128_t n2 = values[0] / n1; + if (n1 > n2) return; + + if ((n1 + n2) % 2 == 0) { + int128_t val1 = values[1] + values[2] + ((n1 + n2) >> 1); + int128_t val2 = values[1] + values[2] - ((n1 + n2) >> 1); + int128_t greater = values[2] >= val1 ? values[2] : val1; + LIMIT = values[1] >= greater ? values[1] * greater / 2 : values[2] * val1 / 2; + run_bfs(sum, values[1], values[2], val1, print_mode); + if (val2 >= 0) { + greater = values[2] >= val2 ? values[2] : val2; + LIMIT = values[1] >= greater ? values[1] * greater / 2 : values[2] * val2 / 2; + run_bfs(sum, values[1], values[2], val2, print_mode); + } + } + return; + } + + int prime = primes[prime_index]; + int exponent = exponents[prime_index]; + int128_t power_of_prime = 1; + + for (int j = 0; j <= exponent; j++) { + int128_t next_n1 = n1 * power_of_prime; + generate_factor_pairs(sum, prime_index+1, exponents, values, next_n1, print_mode); + if (j < exponent) power_of_prime *= prime; + } +} + +uint128_t mysqrt_uint128(uint128_t number) { + if (number == 0) return 0; + uint128_t x = number; + uint128_t y = (x + 1) >> 1; + + while (y < x) { + x = y; + y = (x + number / x) >> 1; + } + return x; +} \ No newline at end of file diff --git a/src/stergios.c b/src/stergios.c new file mode 100755 index 0000000..a07fd99 --- /dev/null +++ b/src/stergios.c @@ -0,0 +1,283 @@ +#include "core.h" +#include "maths.h" + +#include +#include + +#define HASH_SIZE 200003 +//#define LIMIT 100000000LL + +//#define HASH_SIZE 200000003 +//const int128_t LIMIT = (int128_t)1000000000ULL * 1000000000ULL * 1000000000ULL; + +int128_t LIMIT = 0; + +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; + +static VisEntry* hash_table[HASH_SIZE] = {0}; + +void clear_hash_table() { + for (size_t i = 0; i < HASH_SIZE; ++i) { + VisEntry* cur = hash_table[i]; + while (cur) { + VisEntry* nx = cur->next; + free(cur); + cur = nx; + } + + hash_table[i] = NULL; + } +} + +int run_bfs(int128_t* sum, int128_t a0, int128_t b0, int128_t c0, int print_mode); + +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); +} + +static int visit_and_mark(int128_t a, int128_t b, int128_t 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; + } + VisEntry* e = (VisEntry*)malloc(sizeof(VisEntry)); + if (!e) { fprintf(stderr, "Out of memory\n"); exit(1); } + e->a = a; e->b = b; e->c = c; + e->next = hash_table[h]; + hash_table[h] = e; + return 1; +} + +static Node* q_front = NULL; +static Node* q_back = NULL; + +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; +} + +void drain_queue() { + Node* n; + while ((n = dequeue()) != NULL) free(n); +} + +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)) { + Node* n = (Node*)malloc(sizeof(Node)); + if (!n) { fprintf(stderr, "Out of memory\n"); exit(1); } + 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 main() { + int mode = 0, print_mode = 0; + int128_t a0 = 10, b0 = 6, c0 = 0, sum = 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; + if (scanf(" %i", &mode) != 1) { + fprintf(stderr, "Input error.\n"); + return 1; + } + if (mode != 1 && mode != 2) 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; + if (scanf(" %i", &print_mode) != 1) { + fprintf(stderr, "Input error.\n"); + return 1; + } + if (print_mode != 1 && print_mode != 2) print_mode = 0; + } + + if (mode == 1) { + if (read_int128_triplet("Enter initial a b c:", &a0, &b0, &c0) != 0) { + fprintf(stderr, "Input error.\n"); + return 1; + } + + if (a0 == 0 || b0 == 0 || c0 == 0) { + printf("Already zero present: ("); + print_int128(a0); printf(", "); + print_int128(b0); printf(", "); + print_int128(c0); printf(")\n"); + return 0; + } + + int128_t greater = b0 >= c0 ? b0 : c0; + LIMIT = a0 >= greater ? a0 * greater / 2 : b0 * c0 / 2; + + if (!safe_val(a0) || !safe_val(b0) || !safe_val(c0)) { + fprintf(stderr, "Initial values exceed safe limit.\n"); + return 1; + } + + run_bfs(&sum, a0, b0, c0, print_mode); + } else if (mode == 2) { + int p = 3; + 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); + + printf("Total sum is: "); + print_int128(sum); printf("\n"); + } + return 0; +} + +int run_bfs(int128_t* sum, int128_t a0, int128_t b0, int128_t c0, int print_mode) { + drain_queue(); + clear_hash_table(); + + Node* root = malloc(sizeof(Node)); + if (!root) { fprintf(stderr, "Out of memory\n"); return 0; } + 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; +} \ No newline at end of file diff --git a/temp/calc_i b/temp/calc_i new file mode 100755 index 0000000..7fa6163 Binary files /dev/null and b/temp/calc_i differ diff --git a/temp/calc_i.c b/temp/calc_i.c new file mode 100755 index 0000000..3d9ee19 --- /dev/null +++ b/temp/calc_i.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +// briskei ola ta i + +typedef __int128 int128_t; + +int128_t power(int128_t b, int128_t ex) +{ + int128_t res = (int128_t)1; + while (ex > 0) { + // If the exponent is odd, multiply the result by the current base value + if (ex % 2 == 1) { // Same as (exponent & 1) + res = (int128_t)res * b; + } + + // Square the base for the next iteration + b = (int128_t)b * b; + // Halve the exponent (integer division) + ex /= (int128_t)2; // Same as (exponent >>= 1) + } + return res; +} + +void print_int128(__int128 n) +{ + if (n == 0) { + putchar('0'); + return; + } + if (n < 0) { + putchar('-'); + n = -n; + } + + // A buffer to hold the digits (max digits ~40) + char buf[40]; + int i = 0; + + // Extract digits in reverse order + while (n > 0) { + buf[i++] = (char)((n % 10) + '0'); + n /= 10; + } + + // Print the digits in the correct order + while (i > 0) { + putchar(buf[--i]); + } +} + +const int primes[] = {2, 3, 5}; +int exponents[] = {0, 0, 0}; +const int NUM_PRIMES = 3; + +// Global variable to store the number N (calculated in main) +int128_t N_value = 1; +int128_t a = 1; +int128_t b = 1; +// --- Function to Recursively Generate Factor Pairs --- + +/** + * @brief Recursively generates the first factor (n1) and prints the pair (n1, n2) + * such that n1 * n2 = N. The generation stops when n1 exceeds sqrt(N). + * + * @param prime_index The index of the current prime factor being considered. + * @param n1 The factor built so far. + */ +void generate_factor_pairs(int prime_index, int128_t n1, int f) +{ + // Base Case: If we have considered all unique prime factors, + // n1 is a complete factor of N. + if (prime_index == NUM_PRIMES) { + // Optimization: Stop if n1 exceeds the square root of N. + // This prevents printing the pair (n2, n1) after (n1, n2) has been printed. + // Note: For large N, we should compare n1 * n1 > N_value to avoid + // issues with long long or the sqrt() function if it's less precise. + int128_t n2 = (int128_t)N_value / (int128_t)n1; + if ((int128_t)n1 > (int128_t)n2) { + return; + } + if (((int128_t)n1 + (int128_t)n2) % 2 == 0) { + int128_t i = (int128_t)a + (int128_t)b + (((int128_t)n1 + (int128_t)n2) >> 1); + int128_t k = (((int128_t)n2 - (int128_t)n1) >> 1); + if (f) { + printf("i: "); + print_int128(i); + printf(" k: "); + print_int128(k); + printf(" ("); + print_int128(n1); + printf(" , "); + print_int128(n2); + printf(")"); + printf("\n"); + } + else { + print_int128(i); + printf("\n"); + } + + if ((int128_t)a + (int128_t)b - (((int128_t)n1 + (int128_t)n2) >> 1) >= 0) { + int128_t i = (int128_t)a + (int128_t)b - (((int128_t)n1 + (int128_t)n2) >> 1); + if (f) { + printf("i: "); + print_int128(i); + printf(" k: "); + print_int128(k); + printf(" ("); + print_int128(n1); + printf(" , "); + print_int128(n2); + printf(")"); + printf("\n"); + } + else { + print_int128(i); + printf("\n"); + } + } + } + return; + } + + // Get the current prime and its exponent + int prime = primes[prime_index]; + int exponent = exponents[prime_index]; + int128_t power_of_prime = 1; + + // Recursive Step: Iterate through all possible powers of the current prime + for (int i = 0; i <= exponent; i++) { + // The new factor n1 is the old n1 multiplied by (prime^i) + int128_t next_n1 = (int128_t)n1 * (int128_t)power_of_prime; + + // Recursive call for the next prime factor + generate_factor_pairs(prime_index + 1, next_n1, f); + + // Calculate the next power of the current prime: prime^(i+1) + if (i < exponent) { + power_of_prime *= (int128_t)prime; + } + } +} + +int main(int argc, char **argv) +{ + // long long triple[] = {} + int p; + sscanf(argv[1], "%d", &p); + int f; + sscanf(argv[2], "%d", &f); + a = (int128_t)power(10, p); + b = (int128_t)power(6, p); + N_value = (int128_t)4 * a * b; + exponents[0] = 2 * p + 2; + exponents[1] = p; + exponents[2] = p; + generate_factor_pairs(0, 1, 0); +} + diff --git a/temp/stergios-int128.c b/temp/stergios-int128.c new file mode 100755 index 0000000..b997926 --- /dev/null +++ b/temp/stergios-int128.c @@ -0,0 +1,259 @@ +#include +#include +#include + +typedef __int128 int128_t; +typedef unsigned __int128 uint128_t; + +#define HASH_SIZE 200003 +//static const int128_t LIMIT = (int128_t)1000000000ULL * (int128_t)1000000000ULL * (int128_t)100ULL; +#define LIMIT 1000000000LL + +static int is_prime(int128_t n) { + if (n < 2) return 0; + if (n % 2 == 0) return n == 2; + for (int128_t i = 3; i * i <= n; i += 2) if (n % i == 0) return 0; + return 1; +} + +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; + +static VisEntry *hash_table[HASH_SIZE] = {0}; + +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); +} + +static unsigned int hash_three(int128_t a, int128_t b, int128_t c) { + uint128_t x = (uint128_t)(a + 0x9e3779b97f4a7c15ULL); + x ^= (uint128_t)(b + 0xbf58476d1ce4e5b9ULL) + (x<<6) + (x>>2); + x ^= (uint128_t)(c + 0x94d049bb133111ebULL) + (x<<6) + (x>>2); + return (unsigned int)(x % HASH_SIZE); +} + +static int visit_and_mark(int128_t a, int128_t b, int128_t c) { + //unsigned int h = hash_three(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; + } + VisEntry *e = (VisEntry*)malloc(sizeof(VisEntry)); + if (!e) { fprintf(stderr, "Out of memory\n"); exit(1); } + e->a = a; e->b = b; e->c = c; + e->next = hash_table[h]; + hash_table[h] = e; + return 1; +} + +static Node *q_front = NULL; +static Node *q_back = NULL; + +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(void) { + 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 int128_t gcd(int128_t x, int128_t y) { + while (y != 0) { + int128_t t = y; + y = x % y; + x = t; + } + return x < 0 ? -x : x; +} + + +static void try_push_children(Node *curr) { + int128_t a = curr->a, b = curr->b, c = curr->c; + + int128_t g = gcd(a, gcd(b, c)); + if (g > 1) { + int128_t ga = a / g; + int128_t gb = b / g; + int128_t gc = c / g; + + int prime_count = is_prime(ga) + is_prime(gb) + is_prime(gc); + + if (prime_count >= 1) return; + } + + int128_t na = 2*(b + c) - a; + if (safe_val(na) && safe_val(b) && safe_val(c)) { + if (visit_and_mark(na, b, c)) { + Node *n = (Node*)malloc(sizeof(Node)); + n->a = na; n->b = b; n->c = c; n->move = 'A'; n->parent = curr; n->next = NULL; + enqueue(n); + } + } + + int128_t nb = 2*(a + c) - b; + if (safe_val(a) && safe_val(nb) && safe_val(c)) { + if (visit_and_mark(a, nb, c)) { + Node *n = (Node*)malloc(sizeof(Node)); + n->a = a; n->b = nb; n->c = c; n->move = 'B'; n->parent = curr; n->next = NULL; + enqueue(n); + } + } + + int128_t nc = 2*(a + b) - c; + if (safe_val(a) && safe_val(b) && safe_val(nc)) { + if (visit_and_mark(a, b, nc)) { + Node *n = (Node*)malloc(sizeof(Node)); + n->a = a; n->b = b; n->c = nc; n->move = 'C'; n->parent = curr; n->next = NULL; + enqueue(n); + } + } +} + +// Convert string -> int128 +int128_t str_to_int128(const char *s) { + int128_t value = 0; + int sign = 1; + + if (*s == '-') { + sign = -1; + s++; + } + + while (*s >= '0' && *s <= '9') { + value = value * 10 + (*s - '0'); + s++; + } + + return sign * value; +} + +// Print __int128 (for debugging) +void print_int128(int128_t x) { + if (x == 0) { + printf("0"); + return; + } + + if (x < 0) { + putchar('-'); + x = -x; + } + + char buf[64]; + int i = 0; + + while (x > 0) { + buf[i++] = '0' + (int)(x % 10); + x /= 10; + } + + while (i--) putchar(buf[i]); +} + +int main(void) { + char sa[256], sb[256], sc[256]; + int128_t a0, b0, c0; + if (printf("Enter initial a b c: ") < 0) return 1; + if (scanf("%255s %255s %255s", sa, sb, sc) != 3) { + fprintf(stderr, "Invalid input\n"); + return 1; + } + + a0 = str_to_int128(sa); + b0 = str_to_int128(sb); + c0 = str_to_int128(sc); + + if (a0 == 0 || b0 == 0 || c0 == 0) { + printf("Already zero present: ("); + print_int128(a0); printf(", "); + print_int128(b0); printf(", "); + print_int128(c0); printf(")\n"); + return 0; + } + + if (!safe_val(a0) || !safe_val(b0) || !safe_val(c0)) { + fprintf(stderr, "Initial values exceed safe limit.\n"); + return 1; + } + + Node *root = (Node*)malloc(sizeof(Node)); + if (!root) { fprintf(stderr, "Out of memory\n"); return 1; } + 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"); + return 0; + } + + int max_moves = 0; + Node *p = found; + while (p && p->move != '\0') { max_moves++; p = p->parent; } + + char *moves = (char*)malloc(max_moves + 1); + if (!moves) { fprintf(stderr, "Out of memory\n"); return 1; } + moves[max_moves] = '\0'; + 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); + return 0; +}