Compare commits
10 Commits
64f8df2592
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a635d19cfa | ||
|
|
0965b02fed | ||
|
|
65bb0e0f66 | ||
|
|
2d11304ab4 | ||
|
|
026aa887f9 | ||
|
|
1bc283b195 | ||
|
|
0a5d5fc87c | ||
|
|
21c03264e6 | ||
|
|
58970e8a68 | ||
|
|
f155f0e088 |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Aryadev Chavali
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -Wextra -pedantic -ggdb -fsanitize=address
|
CFLAGS=-Wall -Wextra -pedantic -ggdb -fsanitize=address
|
||||||
LIBS=-lm -lraylib
|
LIBS=-lm -lraylib
|
||||||
OBJECTS=main.o
|
OBJECTS=files.o main.o
|
||||||
OUT=sandpile.out
|
OUT=sandpile.out
|
||||||
ARGS=
|
ARGS=
|
||||||
|
|
||||||
|
|||||||
50
files.c
Normal file
50
files.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* file-handler.c
|
||||||
|
* Created: 2023-08-25
|
||||||
|
* Author: Aryadev Chavali
|
||||||
|
* Description: Implementations of writing and loading state->from files
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stb/stb_image_write.h>
|
||||||
|
|
||||||
|
#include "./lib.h"
|
||||||
|
|
||||||
|
#define CHUNK_SIZE 1024
|
||||||
|
|
||||||
|
bool write_to_png(state_t *state, const char *filepath)
|
||||||
|
{
|
||||||
|
unsigned char *image_data =
|
||||||
|
calloc(3 * state->dwidth * state->dwidth, sizeof(*image_data));
|
||||||
|
|
||||||
|
size_t image_ptr = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->dwidth; ++i)
|
||||||
|
for (size_t j = 0; j < state->dwidth; ++j, image_ptr += 3)
|
||||||
|
{
|
||||||
|
unsigned char colour[3] = {0};
|
||||||
|
uint64_t sandpile = state->data[(i * state->dwidth) + j];
|
||||||
|
if (sandpile == 0)
|
||||||
|
colour[0] = colour[1] = colour[2] = 0;
|
||||||
|
else if (sandpile == 1)
|
||||||
|
colour[0] = colour[2] = 255;
|
||||||
|
else if (sandpile == 2)
|
||||||
|
{
|
||||||
|
colour[0] = 255;
|
||||||
|
colour[1] = colour[2] = 20;
|
||||||
|
}
|
||||||
|
else if (sandpile == 3)
|
||||||
|
{
|
||||||
|
colour[2] = 255;
|
||||||
|
colour[0] = colour[1] = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(image_data + image_ptr, colour, sizeof(*colour) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
stbi_write_png(filepath, state->dwidth, state->dwidth, 3, image_data,
|
||||||
|
3 * state->dwidth);
|
||||||
|
free(image_data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
9
lib.h
9
lib.h
@@ -2,21 +2,22 @@
|
|||||||
#define LIB_H
|
#define LIB_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef struct State
|
typedef struct State
|
||||||
{
|
{
|
||||||
// Sandpiles
|
// Sandpiles
|
||||||
unsigned char *data;
|
uint64_t *data;
|
||||||
size_t dwidth;
|
size_t dwidth;
|
||||||
|
|
||||||
size_t window_len;
|
size_t window_len;
|
||||||
int multiplier;
|
double multiplier;
|
||||||
|
|
||||||
bool thread_alive;
|
bool thread_alive;
|
||||||
|
uint64_t payload;
|
||||||
} state_t;
|
} state_t;
|
||||||
|
|
||||||
bool load_from_file(state_t *state, const char *filepath);
|
bool write_to_png(state_t *state, const char *filepath);
|
||||||
bool write_to_file(state_t *state, const char *filepath);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
104
main.c
104
main.c
@@ -15,14 +15,23 @@
|
|||||||
|
|
||||||
#include "./lib.h"
|
#include "./lib.h"
|
||||||
|
|
||||||
void step(state_t *state)
|
struct StepArg
|
||||||
{
|
{
|
||||||
state->data[((state->dwidth / 2) * state->dwidth) + (state->dwidth / 2)]++;
|
state_t *state;
|
||||||
for (size_t i = 0; i < state->dwidth; ++i)
|
size_t x_min, x_max, y_min, y_max;
|
||||||
for (size_t j = 0; j < state->dwidth; ++j)
|
};
|
||||||
|
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
void step(struct StepArg arg)
|
||||||
|
{
|
||||||
|
state_t *state = arg.state;
|
||||||
|
for (size_t i = arg.x_min; i < arg.x_max; ++i)
|
||||||
|
for (size_t j = arg.y_min; j < arg.y_max; ++j)
|
||||||
if (state->data[(i * state->dwidth) + j] >= 4)
|
if (state->data[(i * state->dwidth) + j] >= 4)
|
||||||
{
|
{
|
||||||
unsigned char *references[] = {
|
pthread_mutex_lock(&mutex);
|
||||||
|
uint64_t *references[] = {
|
||||||
(j == 0) ? NULL : &state->data[((i)*state->dwidth) + j - 1],
|
(j == 0) ? NULL : &state->data[((i)*state->dwidth) + j - 1],
|
||||||
(i == state->dwidth - 1)
|
(i == state->dwidth - 1)
|
||||||
? NULL
|
? NULL
|
||||||
@@ -33,36 +42,65 @@ void step(state_t *state)
|
|||||||
(i == 0) ? NULL : &state->data[((i - 1) * state->dwidth) + j]};
|
(i == 0) ? NULL : &state->data[((i - 1) * state->dwidth) + j]};
|
||||||
for (size_t k = 0; k < 4; ++k)
|
for (size_t k = 0; k < 4; ++k)
|
||||||
if (references[k])
|
if (references[k])
|
||||||
*references[k] += 1;
|
*references[k] += state->data[(i * state->dwidth) + j] / 4;
|
||||||
state->data[(i * state->dwidth) + j] = 0;
|
state->data[(i * state->dwidth) + j] %= 4;
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *compute_thread(void *input)
|
void *compute_thread(void *input)
|
||||||
{
|
{
|
||||||
state_t *state = input;
|
struct StepArg *arg = input;
|
||||||
while (state->thread_alive)
|
while (arg->state->thread_alive)
|
||||||
step(state);
|
step(*arg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
bool completed_avalanche(state_t *state)
|
||||||
{
|
{
|
||||||
state_t state = {NULL, 512, 512, 0, true};
|
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)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// Setup "default" state
|
||||||
|
state_t state = {NULL, 512, 512, 0, true, pow(2, 16)};
|
||||||
state.data = calloc(state.dwidth * state.dwidth, sizeof(*state.data));
|
state.data = calloc(state.dwidth * state.dwidth, sizeof(*state.data));
|
||||||
state.multiplier = state.window_len / state.dwidth;
|
state.multiplier = state.window_len / state.dwidth;
|
||||||
|
state.data[(state.dwidth * state.dwidth / 2) + (state.dwidth / 2)] =
|
||||||
|
state.payload;
|
||||||
|
|
||||||
const float zoom = 0.125f;
|
const float zoom = 0.125f;
|
||||||
Camera2D camera = {0};
|
Camera2D camera = {0};
|
||||||
camera.zoom = 1.0f;
|
camera.zoom = 1.0f;
|
||||||
|
|
||||||
pthread_t step_thread;
|
// Initialise mutex for threads to use
|
||||||
pthread_create(&step_thread, NULL, &compute_thread, &state);
|
pthread_mutex_init(&mutex, NULL);
|
||||||
|
// Setup quadrants (for threads)
|
||||||
|
struct StepArg a = {&state, 0, state.dwidth / 2, 0, state.dwidth / 2};
|
||||||
|
struct StepArg b = {&state, 0, state.dwidth / 2, state.dwidth / 2,
|
||||||
|
state.dwidth};
|
||||||
|
struct StepArg c = {&state, state.dwidth / 2, state.dwidth, 0,
|
||||||
|
state.dwidth / 2};
|
||||||
|
struct StepArg d = {&state, state.dwidth / 2, state.dwidth, state.dwidth / 2,
|
||||||
|
state.dwidth};
|
||||||
|
// Setup threads
|
||||||
|
pthread_t thread_a, thread_b, thread_c, thread_d;
|
||||||
|
pthread_create(&thread_a, NULL, &compute_thread, &a);
|
||||||
|
pthread_create(&thread_b, NULL, &compute_thread, &b);
|
||||||
|
pthread_create(&thread_c, NULL, &compute_thread, &c);
|
||||||
|
pthread_create(&thread_d, NULL, &compute_thread, &d);
|
||||||
|
|
||||||
InitWindow(state.window_len, state.window_len, "Abelian sand pile");
|
InitWindow(state.window_len, state.window_len, "Abelian sand pile");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
while (!WindowShouldClose())
|
const int DELTA = 100;
|
||||||
|
bool done = false;
|
||||||
|
for (uint64_t ticks = 0, prev_ticks = 0; !WindowShouldClose(); ++ticks)
|
||||||
{
|
{
|
||||||
if (IsKeyPressed(KEY_UP) || IsKeyDown(KEY_UP))
|
if (IsKeyPressed(KEY_UP) || IsKeyDown(KEY_UP))
|
||||||
{
|
{
|
||||||
@@ -85,6 +123,21 @@ int main(void)
|
|||||||
camera.zoom = zoom;
|
camera.zoom = zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ticks - prev_ticks > DELTA && !done)
|
||||||
|
{
|
||||||
|
printf("Checking if avalanche is complete!\n");
|
||||||
|
if (completed_avalanche(&state))
|
||||||
|
{
|
||||||
|
state.thread_alive = false;
|
||||||
|
pthread_join(thread_a, NULL);
|
||||||
|
pthread_join(thread_b, NULL);
|
||||||
|
pthread_join(thread_c, NULL);
|
||||||
|
pthread_join(thread_d, NULL);
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
prev_ticks = ticks;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
|
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
|
||||||
{
|
{
|
||||||
Vector2 delta = Vector2Scale(GetMouseDelta(), -1.0f / camera.zoom);
|
Vector2 delta = Vector2Scale(GetMouseDelta(), -1.0f / camera.zoom);
|
||||||
@@ -97,16 +150,16 @@ int main(void)
|
|||||||
for (size_t i = 0; i < state.dwidth; ++i)
|
for (size_t i = 0; i < state.dwidth; ++i)
|
||||||
for (size_t j = 0; j < state.dwidth; ++j)
|
for (size_t j = 0; j < state.dwidth; ++j)
|
||||||
{
|
{
|
||||||
Color c = {0};
|
Color c = {0};
|
||||||
unsigned char sandpile = state.data[(i * state.dwidth) + j];
|
uint64_t sandpile = state.data[(i * state.dwidth) + j];
|
||||||
if (sandpile == 0)
|
if (sandpile == 0)
|
||||||
c = BLACK;
|
c = BLACK;
|
||||||
else if (sandpile == 1)
|
else if (sandpile == 1)
|
||||||
c = GREEN;
|
c = MAGENTA;
|
||||||
else if (sandpile == 2)
|
else if (sandpile == 2)
|
||||||
c = PURPLE;
|
c = RED;
|
||||||
else if (sandpile == 3)
|
else if (sandpile == 3)
|
||||||
c = YELLOW;
|
c = BLUE;
|
||||||
|
|
||||||
DrawRectangle(i * state.multiplier, j * state.multiplier,
|
DrawRectangle(i * state.multiplier, j * state.multiplier,
|
||||||
state.multiplier, state.multiplier, c);
|
state.multiplier, state.multiplier, c);
|
||||||
@@ -116,7 +169,16 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.thread_alive)
|
if (state.thread_alive)
|
||||||
pthread_cancel(step_thread);
|
{
|
||||||
|
state.thread_alive = false;
|
||||||
|
pthread_join(thread_a, NULL);
|
||||||
|
pthread_join(thread_b, NULL);
|
||||||
|
pthread_join(thread_c, NULL);
|
||||||
|
pthread_join(thread_d, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
|
write_to_png(&state, "data.png");
|
||||||
|
free(state.data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user