summaryrefslogtreecommitdiff
path: root/main.c
blob: a4a36b0dc787265f027a22de3f58a8889fc7faaa (plain)
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;
}