Stopped adding a grain of sand per step. Collapsing should work properly for any amount of sand grains, regardless of whether it's 4 or 4000. Previous code fixed it at 4 always, and how it distributed was so as well. Now we distribute as much sand as we can. This comes from the idea that, instead of incrementing while rendering, let's just set some n pixels in the centre and see how the model distributes them.
127 lines
3.3 KiB
C
127 lines
3.3 KiB
C
/* main.c
|
|
* Created: 2023-08-25
|
|
* Author: Aryadev Chavali
|
|
* Description: Entry point of program
|
|
*/
|
|
#include <malloc.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
|
|
#include <raylib.h>
|
|
#include <raymath.h>
|
|
|
|
#include "./lib.h"
|
|
|
|
void step(state_t *state)
|
|
{
|
|
for (size_t i = 0; i < state->dwidth; ++i)
|
|
for (size_t j = 0; j < state->dwidth; ++j)
|
|
if (state->data[(i * state->dwidth) + j] >= 4)
|
|
{
|
|
uint64_t *references[] = {
|
|
(j == 0) ? NULL : &state->data[((i)*state->dwidth) + j - 1],
|
|
(i == state->dwidth - 1)
|
|
? NULL
|
|
: &state->data[((i + 1) * state->dwidth) + j],
|
|
(j == state->dwidth - 1)
|
|
? NULL
|
|
: &state->data[(i * state->dwidth) + j + 1],
|
|
(i == 0) ? NULL : &state->data[((i - 1) * state->dwidth) + j]};
|
|
for (size_t k = 0; k < 4; ++k)
|
|
if (references[k])
|
|
*references[k] += state->data[(i * state->dwidth) + j] / 4;
|
|
state->data[(i * state->dwidth) + j] %= 4;
|
|
}
|
|
}
|
|
|
|
void *compute_thread(void *input)
|
|
{
|
|
state_t *state = input;
|
|
while (state->thread_alive)
|
|
step(state);
|
|
return NULL;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
state_t state = {NULL, 512, 512, 0, true};
|
|
state.data = calloc(state.dwidth * state.dwidth, sizeof(*state.data));
|
|
state.multiplier = state.window_len / state.dwidth;
|
|
|
|
const float zoom = 0.125f;
|
|
Camera2D camera = {0};
|
|
camera.zoom = 1.0f;
|
|
|
|
pthread_t step_thread;
|
|
pthread_create(&step_thread, NULL, &compute_thread, &state);
|
|
|
|
InitWindow(state.window_len, state.window_len, "Abelian sand pile");
|
|
SetTargetFPS(60);
|
|
|
|
while (!WindowShouldClose())
|
|
{
|
|
if (IsKeyPressed(KEY_UP) || IsKeyDown(KEY_UP))
|
|
{
|
|
Vector2 centre = {state.window_len / 2, state.window_len / 2};
|
|
Vector2 world_pos = GetScreenToWorld2D(centre, camera);
|
|
camera.offset = centre;
|
|
camera.target = world_pos;
|
|
camera.zoom += zoom;
|
|
if (camera.zoom < zoom)
|
|
camera.zoom = zoom;
|
|
}
|
|
if (IsKeyPressed(KEY_DOWN) || IsKeyDown(KEY_DOWN))
|
|
{
|
|
Vector2 centre = {state.window_len / 2, state.window_len / 2};
|
|
Vector2 world_pos = GetScreenToWorld2D(centre, camera);
|
|
camera.offset = centre;
|
|
camera.target = world_pos;
|
|
camera.zoom -= zoom;
|
|
if (camera.zoom < zoom)
|
|
camera.zoom = zoom;
|
|
}
|
|
|
|
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
|
|
{
|
|
Vector2 delta = Vector2Scale(GetMouseDelta(), -1.0f / camera.zoom);
|
|
camera.target = Vector2Add(camera.target, delta);
|
|
}
|
|
|
|
BeginDrawing();
|
|
ClearBackground(BLACK);
|
|
BeginMode2D(camera);
|
|
for (size_t i = 0; i < state.dwidth; ++i)
|
|
for (size_t j = 0; j < state.dwidth; ++j)
|
|
{
|
|
Color c = {0};
|
|
uint64_t sandpile = state.data[(i * state.dwidth) + j];
|
|
if (sandpile == 0)
|
|
c = BLACK;
|
|
else if (sandpile == 1)
|
|
c = GREEN;
|
|
else if (sandpile == 2)
|
|
c = PURPLE;
|
|
else if (sandpile == 3)
|
|
c = YELLOW;
|
|
|
|
DrawRectangle(i * state.multiplier, j * state.multiplier,
|
|
state.multiplier, state.multiplier, c);
|
|
}
|
|
EndMode2D();
|
|
EndDrawing();
|
|
}
|
|
|
|
if (state.thread_alive)
|
|
{
|
|
state.thread_alive = false;
|
|
pthread_join(step_thread, NULL);
|
|
}
|
|
|
|
CloseWindow();
|
|
free(state.data);
|
|
return 0;
|
|
}
|