diff --git a/src/base.h b/src/base.h index f98c833..835dc00 100644 --- a/src/base.h +++ b/src/base.h @@ -30,6 +30,18 @@ typedef double f64; // 64 byte programs #define SIZEOF_PROGRAM (1LU << 6) +#define NUM_PROGRAMS_POW_2 17 +#define NUM_PROGRAMS (1LU << NUM_PROGRAMS_POW_2) +#define SIMULATION_SIZE (SIZEOF_PROGRAM * NUM_PROGRAMS) +#define THREAD_POOL 4 + +// GUI stuff +#define WIDTH 800 +#define HEIGHT 600 +// Our grid will be of length sqrt(NUM_PROGRAMS). This is the same as +// 1LU<<(NUM_PROGRAMS_POW_2/2). +static const size_t GRID_WIDTH = 1LU << (NUM_PROGRAMS_POW_2 / 2); + #endif /* Copyright (C) 2026 Aryadev Chavali diff --git a/src/main.c b/src/main.c index 757d270..d7c805e 100644 --- a/src/main.c +++ b/src/main.c @@ -17,12 +17,6 @@ #include "program_iter.h" #include "simulation.h" -#define WIDTH 800 -#define HEIGHT 600 - -// Our grid will be of length sqrt(NUM_PROGRAMS). This is the same as -// 1LU<<(NUM_PROGRAMS_POW_2/2). -static const size_t GRID_WIDTH = 1LU << (NUM_PROGRAMS_POW_2 / 2); static const size_t CELL_WIDTH = WIDTH / GRID_WIDTH; static const char *VALID_OPS = "<>{}-+.,[]"; diff --git a/src/simulation.c b/src/simulation.c index c8921ae..37c8de2 100644 --- a/src/simulation.c +++ b/src/simulation.c @@ -21,33 +21,71 @@ bool any_threads_using(const struct ThreadState *const states, u64 n) return false; } +void get_neighbours(u64 index, u64 ret[4]) +{ + memset(ret, 0xFF, sizeof(*ret) * 4); + u64 x = index / GRID_WIDTH; + u64 y = index % GRID_WIDTH; + u64 ptr = 0; + if (x > 0) + { + ret[ptr++] = ((x - 1) * GRID_WIDTH) + y; + } + if (x < GRID_WIDTH - 1) + { + ret[ptr++] = ((x + 1) * GRID_WIDTH) + y; + } + if (y > 0) + { + ret[ptr++] = (x * GRID_WIDTH) + (y + 1); + } + if (y < GRID_WIDTH - 1) + { + ret[ptr++] = (x * GRID_WIDTH) + (y - 1); + } +} + void thread_pick(struct ThreadState *state) { struct Simulation *sim = state->sim; + u64 p1 = 0, p2 = 0; while (true) { - u64 p1 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); + p1 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); if (any_threads_using(sim->states, p1)) { continue; } - // TODO: Instead of picking a RANDOM p2, why not choose a neighbour of p1? - // This way programs that are likely to replicate are replicating closer to - // themselves, and thus have a higher chance of further replication. - u64 p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); - while (p1 * 8 <= ((p2 * 8) + SIZEOF_PROGRAM) && - p2 * 8 <= ((p1 * 8) + SIZEOF_PROGRAM)) + u64 neighbours[4]; + get_neighbours(p1, neighbours); + + u64 p2 = -1; + for (u64 i = 0; i < 4; ++i) + { + if (neighbours[i] == UINT64_MAX || + any_threads_using(sim->states, neighbours[i])) + continue; + p2 = neighbours[i]; + break; + } + + if (p2 < GRID_WIDTH) + { + break; + } + + // Otherwise pick randomly. + p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); + while ((p1 * 8 <= ((p2 * 8) + SIZEOF_PROGRAM) && + p2 * 8 <= ((p1 * 8) + SIZEOF_PROGRAM)) || + any_threads_using(sim->states, p2)) { p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); } - if (any_threads_using(sim->states, p2)) - { - continue; - } - state->p1 = p1; - state->p2 = p2; break; } + state->p1 = p1; + state->p2 = p2; } const struct timespec THREAD_DEFAULT_SLEEP = {.tv_sec = 1}; diff --git a/src/simulation.h b/src/simulation.h index 16e46cd..05f6aac 100644 --- a/src/simulation.h +++ b/src/simulation.h @@ -12,12 +12,6 @@ #include #include -#define NUM_PROGRAMS_POW_2 10 -#define NUM_PROGRAMS (1LU << NUM_PROGRAMS_POW_2) -#define SIMULATION_SIZE (SIZEOF_PROGRAM * NUM_PROGRAMS) - -#define THREAD_POOL 8 - struct ThreadState { u64 p1, p2;