Nimbin[12]?Embedded / snake_compiler / snake_SDL/src/snake.c

snake_compiler git · main

Snake compiled to a bare-metal RISC-V microcontroller

riscv embedded bare-metal c snake · first commit 2026-01-18 · last commit 2026-01-18 (8 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/compilerbau/snake_compiler

C 95.2% Markdown 3.3%
git clone https://git.christianimmanuel.de/embedded/snake_compiler.gitwget https://git.christianimmanuel.de/embedded/snake_compiler/archive/snake_compiler.tar.gz
snake_SDL/src/snake.c 4.2 KB · 158 lines raw
#include "snake.h"

#include "matrix.h"


// Initialize snake with starting position
void snake_Init(Snake* snake, int start_x, int start_y) {
    for (int i = 0; i < SNAKE_START_LENGTH; i++) {
        snake->nodes[i].x = start_x - i;
        snake->nodes[i].y = start_y - i;
        snake->nodes[i].color = (i == 0) ? BLACK : SNAKE_COLOR;
    }

    snake->head_index = SNAKE_START_LENGTH - 1;
    snake->tail_index = 0;
    snake->direction  = DIR_RIGHT;
    snake->length     = SNAKE_START_LENGTH;

    printf("START SNAKE: %d %d, length %d\n", start_x, start_y, SNAKE_START_LENGTH);
}

void snake_SetDirection(Snake* snake, Direction new_dir) {
    if ((snake->direction == DIR_UP && new_dir == DIR_DOWN) ||
        (snake->direction == DIR_DOWN && new_dir == DIR_UP) ||
        (snake->direction == DIR_LEFT && new_dir == DIR_RIGHT) ||
        (snake->direction == DIR_RIGHT && new_dir == DIR_LEFT)) {
        return;
    }
    snake->direction = new_dir;
}


static inline unsigned char rise_dt(
        unsigned char v,
        unsigned char target,
        uint64_t diff,
        uint64_t diff_max)
{
    if (v >= target) return v;

    uint32_t delta = (uint32_t)((diff * target) / diff_max);
    if (delta == 0) delta = 1;

    uint32_t nv = v + delta;
    return (nv > target) ? target : (unsigned char)nv;
}

static inline unsigned char fall_dt(
        unsigned char v,
        uint64_t diff,
        uint64_t diff_max)
{
    if (v == 0) return 0;

    uint32_t delta = (uint32_t)((diff * MAX_BRIGHTNESS) / diff_max);
    if (delta == 0) delta = 1;

    return (delta >= v) ? 0 : (unsigned char)(v - delta);
}

bool snake_Move(Snake* snake, bool is_next_step, uint64_t diff_max, uint64_t diff) {
    SnakeTile* head = &snake->nodes[snake->head_index];
    SnakeTile* tail = &snake->nodes[snake->tail_index];

    // FADE
    Color sc = SNAKE_COLOR;

    head->color.r = rise_dt(head->color.r, sc.r, diff, diff_max);
    head->color.g = rise_dt(head->color.g, sc.g, diff, diff_max);
    head->color.b = rise_dt(head->color.b, sc.b, diff, diff_max);

    tail->color.r = fall_dt(tail->color.r, diff, diff_max);
    tail->color.g = fall_dt(tail->color.g, diff, diff_max);
    tail->color.b = fall_dt(tail->color.b, diff, diff_max);

    matrix->pixels[head->y][head->x].color = head->color;
    matrix->pixels[tail->y][tail->x].color = tail->color;

    if (!is_next_step)
        return true;

    // MOVE
    int new_x = head->x;
    int new_y = head->y;

    switch (snake->direction) {
        case DIR_UP:    new_y--; break;
        case DIR_DOWN:  new_y++; break;
        case DIR_LEFT:  new_x--; break;
        case DIR_RIGHT: new_x++; break;
    }

    if (WALL_COLLISION &&
        (new_x >= MATRIX_WIDTH ||
         new_x <  0 ||
         new_y >= MATRIX_HEIGHT ||
         new_y <  0)) {
        printf("Collided with Wall %d %d %d %d!\n", new_x, new_y, MATRIX_WIDTH, MATRIX_HEIGHT);
        return false;
    }

    new_x = (new_x + MATRIX_WIDTH)  % MATRIX_WIDTH;
    new_y = (new_y + MATRIX_HEIGHT) % MATRIX_HEIGHT;

    int next = (snake->head_index + 1) % MAX_SNAKE_LENGTH;
    SnakeTile* head_next = &snake->nodes[next];

    head_next->x = new_x;
    head_next->y = new_y;
    head_next->color = (Color){0, 0, 0};

    snake->head_index = next;

    bool grow = matrix->pixels[new_y][new_x].type == APPLE;

    matrix->pixels[new_y][new_x].type = SNAKE;

    if (!grow) {
        snake->tail_index = (snake->tail_index + 1) % MAX_SNAKE_LENGTH;
    } else {
        spawn_apple();
        snake->length++;
    }

    return !snake_IsColliding(snake);
}

bool snake_IsColliding(Snake* snake) {
    int idx   = snake->tail_index;
    int count = snake->length - 1;

    int hx = snake->nodes[snake->head_index].x;
    int hy = snake->nodes[snake->head_index].y;

    while (count-- > 0) {
        if (snake->nodes[idx].x == hx && snake->nodes[idx].y == hy) return true;
        idx = (idx + 1) % MAX_SNAKE_LENGTH;
    }
    return false;
}





void spawn_apple() {
    int x, y;

    // Find an empty pixel
    do {
        x = random_Int(MATRIX_WIDTH);
        y = random_Int(MATRIX_HEIGHT);
    } while (matrix->pixels[y][x].type != NONE);

    // Set the apple pixel
    matrix->pixels[y][x].type = APPLE;
    matrix->pixels[y][x].color = (Color){0, MAX_BRIGHTNESS, 0};
}