// Game-like particle system: 32 particles, i16 position + velocity in a
// 320x200 box, bounce on walls.  Mimics the inner loop of an action
// game's sprite update (position += velocity + wall collision).
//
// Each particle is (px, py, vx, vy).  Initial positions deterministic
// pseudo-random (so the bench is reproducible).
//
// particleStep() runs one tick.  Returns a checksum of all px values
// so the result isn't dead-code-eliminated.

#define N_PARTICLES 32
#define W           320
#define H           200

static short px[N_PARTICLES];
static short py[N_PARTICLES];
static short vx[N_PARTICLES];
static short vy[N_PARTICLES];
// volatile to defeat GlobalOpt's narrowing to i1 (causes a backend
// i32-load-from-i1 isel gap — see memory: feedback_i1_load_custom.md).
static volatile short initialized = 0;


static void particleInit(void) {
    // Deterministic pseudo-random init: linear congruential.
    unsigned short seed = 12345;
    for (short i = 0; i < N_PARTICLES; i++) {
        seed = (unsigned short)(seed * 25173 + 13849);
        px[i] = (short)(seed % W);
        seed = (unsigned short)(seed * 25173 + 13849);
        py[i] = (short)(seed % H);
        seed = (unsigned short)(seed * 25173 + 13849);
        vx[i] = (short)((seed % 7) - 3);   // -3..+3
        seed = (unsigned short)(seed * 25173 + 13849);
        vy[i] = (short)((seed % 7) - 3);
        if (vx[i] == 0) {
            vx[i] = 1;
        }
        if (vy[i] == 0) {
            vy[i] = 1;
        }
    }
    initialized = 1;
}


unsigned long particleStep(void) {
    if (!initialized) {
        particleInit();
    }
    unsigned long sum = 0;
    for (short i = 0; i < N_PARTICLES; i++) {
        short nx = (short)(px[i] + vx[i]);
        short ny = (short)(py[i] + vy[i]);
        if (nx < 0 || nx >= W) {
            vx[i] = (short)(-vx[i]);
            nx = px[i];
        }
        if (ny < 0 || ny >= H) {
            vy[i] = (short)(-vy[i]);
            ny = py[i];
        }
        px[i] = nx;
        py[i] = ny;
        sum += (unsigned long)(unsigned short)nx;
    }
    return sum;
}
