commit 467873771997901cad4cf011466908ccc724392e
parent ccc7e867e0523ef2355c781804884635f60b6633
Author: Robert Russell <robertrussell.72001@gmail.com>
Date: Thu, 11 Apr 2024 20:53:17 -0700
Try toppling to 8 neighbours
Diffstat:
6 files changed, 156 insertions(+), 14 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,3 +1,5 @@
-spstabilize
+spgen
+spstabilize4
+spstabilize8
sp2ff
ff2sp
diff --git a/Makefile b/Makefile
@@ -3,10 +3,16 @@
CC = gcc
CFLAGS = -march=native -O3 -Wall
-all: spstabilize sp2ff ff2sp
+all: spgen spstabilize4 spstabilize8 sp2ff ff2sp
-spstabilize: spstabilize.c common.c common.h
- $(CC) -o $@ $(CFLAGS) spstabilize.c common.c -lrcx
+spgen: spgen.c common.c common.h
+ $(CC) -o $@ $(CFLAGS) spgen.c common.c -lrcx
+
+spstabilize4: spstabilize4.c common.c common.h
+ $(CC) -o $@ $(CFLAGS) spstabilize4.c common.c -lrcx
+
+spstabilize8: spstabilize8.c common.c common.h
+ $(CC) -o $@ $(CFLAGS) spstabilize8.c common.c -lrcx
sp2ff: sp2ff.c common.c common.h
$(CC) -o $@ $(CFLAGS) sp2ff.c common.c -lrcx
@@ -16,4 +22,4 @@ ff2sp: ff2sp.c common.c common.h
.PHONY: clean
clean:
- rm -f spstabilize sp2ff ff2sp
+ rm -f spgen spstabilize4 spstabilize8 sp2ff ff2sp
diff --git a/sp2ff.c b/sp2ff.c
@@ -5,7 +5,7 @@
#include "common.h"
#define USAGE \
- "usage: %s [COLOR0 COLOR1 COLOR2 COLOR3]\n" \
+ "usage: %s [COLOR0 COLOR1 COLOR2 COLOR3 [COLOR4 COLOR5 COLOR6 COLOR7]]\n" \
"where COLORi is a 24 or 48 (32 or 64) bit RGB (RGBA) hex value\n"
Rgba
@@ -46,7 +46,7 @@ parse_rgba(char *s) {
}
Image
-draw(Sandpile sp, Rgba (*palette)[4]) {
+draw(Sandpile sp, Rgba (*palette)[8]) {
usize w = sp.w;
usize h = sp.h;
@@ -54,7 +54,7 @@ draw(Sandpile sp, Rgba (*palette)[4]) {
for (usize y = 0; y < h; y++) {
for (usize x = 0; x < w; x++) {
u32 s = sp.sand[(y + 1) * (w + 2) + (x + 1)];
- pixels[y * w + x] = (*palette)[MIN(s, 3)];
+ pixels[y * w + x] = (*palette)[MIN(s, 7)];
}
}
@@ -65,15 +65,26 @@ int
main(int argc, char **argv) {
CHECK_FOR_HELP_OPTION(USAGE, argc, argv);
- Rgba palette[4];
+ Rgba palette[8];
if (argc == 1) { // Default palette
- palette[0] = (Rgba){ 0x2222, 0x2727, 0x2525, 0xffff }; // "eerie black"
- palette[1] = (Rgba){ 0x8989, 0x9898, 0x7878, 0xffff }; // "moss green"
- palette[2] = (Rgba){ 0xe4e4, 0xe6e6, 0xc3c3, 0xffff }; // "beige"
- palette[3] = (Rgba){ 0xf7f7, 0xf7f7, 0xf2f2, 0xffff }; // "baby powder"
- } else if (argc == 5) { // Custom palette
+ #define RGB(r, g, b) (Rgba){ 0x##r##r, 0x##g##g, 0x##b##b, 0xffff }
+ palette[0] = RGB(BE, 80, 1D);
+ palette[1] = RGB(BE, 1D, A3);
+ palette[2] = RGB(78, 4E, 71);
+ palette[3] = RGB(4F, 65, 79);
+ palette[4] = RGB(38, A2, 18);
+ palette[5] = RGB(1D, 73, BE);
+ palette[6] = RGB(40, 6A, 33);
+ palette[7] = RGB(79, 69, 4F);
+ #undef RGB
+ } else if (argc == 5) { // Custom 4 color palette
for (usize i = 0; i < 4; i++)
palette[i] = parse_rgba(argv[i+1]);
+ for (usize i = 4; i < 8; i++)
+ palette[i] = palette[3];
+ } else if (argc == 9) { // Custom 8 color palette
+ for (usize i = 0; i < 8; i++)
+ palette[i] = parse_rgba(argv[i+1]);
} else {
fprintf(stderr, USAGE, argv[0]);
return 1;
diff --git a/spgen.c b/spgen.c
@@ -0,0 +1,18 @@
+#include <rcx/all.h>
+#include <stdio.h>
+
+#include "common.h"
+
+int
+main(void) {
+ usize w = 101;
+ usize h = 101;
+ u32 *sand = r_eallocz((w + 2) * (h + 2) * sizeof(u32));
+ Sandpile sp = { .w = w, .h = h, .sand = sand };
+
+ usize x = 50;
+ usize y = 50;
+ sand[(y + 1) * (w + 2) + (x + 1)] = 10000;
+
+ sp_fwrite(stdout, sp);
+}
diff --git a/spstabilize.c b/spstabilize4.c
diff --git a/spstabilize8.c b/spstabilize8.c
@@ -0,0 +1,105 @@
+#include <rcx/all.h>
+#include <rcx/simd.h>
+#include <stdio.h>
+
+#include "common.h"
+
+#ifndef R_HAVE_AVX2
+#error "AVX2 support required"
+#endif
+
+#define USAGE "usage: %s\n"
+
+Sandpile
+stabilize(Sandpile sp) {
+ usize w = sp.w;
+ usize h = sp.h;
+
+ u32 *sand[2];
+ sand[0] = sp.sand;
+ sand[1] = r_eallocz((w + 2) * (h + 2) * sizeof(u32));
+
+ isize nxv = (isize)w / 8; // Number of x vectors that fit in w
+ v8u32 v7 = v8u32_fill(7);
+ for (usize i = 0;; i = !i) {
+ usize unstable = 0;
+
+ for (isize y = 1; y <= h; y++) {
+ isize j = y * ((isize)w + 2) + 1;
+
+ for (isize xv = 0; xv < nxv; xv++, j += 8) {
+ v8u32 a = v8u32_loadu((v8u32a1 *)&sand[i][j]);
+ a = v8u32_and(a, v7);
+
+ #define ADD(dx, dy) \
+ do { \
+ isize dj = (dy) * ((isize)w + 2) + (dx); \
+ v8u32 b = v8u32_loadu((v8u32a1 *)&sand[i][j + dj]); \
+ b = v8u32_sri(b, 3); \
+ a = v8u32_add(a, b); \
+ } while (0)
+ ADD(+1, +0);
+ ADD(+1, +1);
+ ADD(+0, +1);
+ ADD(-1, +1);
+ ADD(-1, +0);
+ ADD(-1, -1);
+ ADD(+0, -1);
+ ADD(+1, -1);
+ #undef ADD
+
+ v8u32 g = v8u32_cmpgt(a, v7);
+ unstable += !v8u32_testz(g, g);
+
+ v8u32_storeu((v8u32a1 *)&sand[!i][j], a);
+ }
+
+ // TODO: Try dealing with tail with masked vector instead? Note
+ // that this would require a minimum width/height of 3.
+ for (isize x = 8*nxv; x < (isize)w; x++, j++) {
+ u32 a = sand[i][j];
+ a = a & 3;
+
+ #define ADD(dx, dy) \
+ do { \
+ isize dj = (dy) * ((isize)w + 2) + (dx); \
+ u32 b = sand[i][j + dj]; \
+ b = b >> 2; \
+ a = a + b; \
+ } while (0)
+ ADD(+1, +0);
+ ADD(+1, +1);
+ ADD(+0, +1);
+ ADD(-1, +1);
+ ADD(-1, +0);
+ ADD(-1, -1);
+ ADD(+0, -1);
+ ADD(+1, -1);
+ #undef ADD
+
+ unstable += a > 3;
+
+ sand[!i][j] = a;
+ }
+ }
+
+ if (!unstable) {
+ free(sand[i]);
+ return (Sandpile){.w = w, .h = h, .sand = sand[!i]};
+ }
+ }
+}
+
+int
+main(int argc, char **argv) {
+ CHECK_FOR_HELP_OPTION(USAGE, argc, argv);
+
+ if (argc != 1) {
+ fprintf(stderr, USAGE, argv[0]);
+ return 1;
+ }
+
+ Sandpile sp = sp_fread(stdin);
+ sp = stabilize(sp);
+ sp_fwrite(stdout, sp);
+}