1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
/* 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)
{
state->data[((state->dwidth / 2) * state->dwidth) + (state->dwidth / 2)]++;
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)
{
unsigned char *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] += 1;
state->data[(i * state->dwidth) + j] = 0;
}
}
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};
unsigned char 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)
pthread_cancel(step_thread);
write_to_file(&state, "data.out");
CloseWindow();
return 0;
}
|