From 8f795618c8f2b795d8b4f647d3e228cf02744240 Mon Sep 17 00:00:00 2001 From: doofenshirmtz Date: Fri, 1 May 2026 22:15:06 +0530 Subject: [PATCH 1/2] puffer aim trainer hehe --- config/whackamole.ini | 13 +++ ocean/whackamole/binding.c | 22 ++++ ocean/whackamole/pufferfish.png | Bin 0 -> 39651 bytes ocean/whackamole/whackamole.c | 50 ++++++++ ocean/whackamole/whackamole.h | 197 ++++++++++++++++++++++++++++++++ 5 files changed, 282 insertions(+) create mode 100644 config/whackamole.ini create mode 100644 ocean/whackamole/binding.c create mode 100644 ocean/whackamole/pufferfish.png create mode 100644 ocean/whackamole/whackamole.c create mode 100644 ocean/whackamole/whackamole.h diff --git a/config/whackamole.ini b/config/whackamole.ini new file mode 100644 index 000000000..db7b5e10b --- /dev/null +++ b/config/whackamole.ini @@ -0,0 +1,13 @@ +[base] +env_name = whackamole + +[env] +num_envs = 4096 + +[policy] +hidden_size = 256 +num_layers = 2 + +[train] +learning_rate = 0.001 +total_timesteps = 500_000_000 diff --git a/ocean/whackamole/binding.c b/ocean/whackamole/binding.c new file mode 100644 index 000000000..6a7c77a87 --- /dev/null +++ b/ocean/whackamole/binding.c @@ -0,0 +1,22 @@ +#include "whackamole.h" + +#define OBS_SIZE TOTAL_CELLS +#define NUM_ATNS 1 +#define ACT_SIZES {TOTAL_CELLS} +#define OBS_TENSOR_T FloatTensor + +#define Env Whackamole +#include "vecenv.h" + +void my_init(Env* env, Dict* kwargs) { + env->num_agents = 1; + env->hits = 0; + env->tick = 0; +} + +void my_log(Log* log, Dict* out) { + dict_set(out, "perf", log->perf); + dict_set(out, "score", log->score); + dict_set(out, "episode_return", log->episode_return); + dict_set(out, "episode_length", log->episode_length); +} \ No newline at end of file diff --git a/ocean/whackamole/pufferfish.png b/ocean/whackamole/pufferfish.png new file mode 100644 index 0000000000000000000000000000000000000000..c9dfc57858b595fb43e6647b632d1850ea56eb4b GIT binary patch literal 39651 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 0 && r < GRID_SIZE && c >= 0 && c < GRID_SIZE) { + env.actions[0] = (float)(r * GRID_SIZE + c); + } + } + if (IsKeyPressed(KEY_R)) c_reset(&env); + } else { + if (frame % 10 == 0) { + env.actions[0] = (float)(rand_r(&env.rng) % TOTAL_CELLS); + } else { + env.actions[0] = NOOP; + } + } + + c_step(&env); + c_render(&env); + } + + free(env.observations); + free(env.actions); + free(env.rewards); + free(env.terminals); + c_close(&env); + + return 0; +} \ No newline at end of file diff --git a/ocean/whackamole/whackamole.h b/ocean/whackamole/whackamole.h new file mode 100644 index 000000000..7912bce19 --- /dev/null +++ b/ocean/whackamole/whackamole.h @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include "raylib.h" + +#define GRID_SIZE 5 +#define TOTAL_CELLS (GRID_SIZE * GRID_SIZE) +#define CELL_SIZE 128 +#define NOOP -1.0f +#define ATTEMPTS_PER_EPISODE 3 + +typedef struct { + float perf; + float score; + float episode_return; + float episode_length; + float n; +} Log; + +typedef struct { + Texture2D puffer; + int flash_timer; + Color flash_color; + int last_action_r; + int last_action_c; + bool show_flash; +} Client; + +typedef struct { + Log log; + float* observations; + float* actions; + float* rewards; + float* terminals; + int num_agents; + unsigned int rng; + int mole_r; + int mole_c; + int hits; + int tick; + Client* client; +} Whackamole; + +void add_log(Whackamole* env) { + env->log.perf += (env->rewards[0] > 0) ? 1.0f : 0.0f; + env->log.score += env->rewards[0]; + env->log.episode_length += env->tick; + env->log.episode_return += env->rewards[0]; + env->log.n += 1.0f; +} + +void c_reset(Whackamole* env) { + memset(env->observations, 0, sizeof(float) * TOTAL_CELLS); + + int mole_idx = rand_r(&env->rng) % TOTAL_CELLS; + env->observations[mole_idx] = 1.0f; + env->mole_r = mole_idx / GRID_SIZE; + env->mole_c = mole_idx % GRID_SIZE; + + env->tick = 0; + env->rewards[0] = 0.0f; + env->terminals[0] = 0.0f; + + if (env->client != NULL) { + env->client->show_flash = false; + env->client->flash_timer = 0; + } +} + +void c_step(Whackamole* env) { + env->tick += 1; + + int action = (int)env->actions[0]; + int mole_idx = env->mole_r * GRID_SIZE + env->mole_c; + + if (env->client != NULL) { + env->client->show_flash = false; + } + + if (action == (int)NOOP || action < 0 || action >= TOTAL_CELLS) { + env->rewards[0] = 0.0f; + } else if (action == mole_idx) { + env->rewards[0] = 1.0f; + env->hits += 1; + // Flash GREEN for hit + if (env->client != NULL) { + env->client->flash_color = (Color){0, 255, 0, 180}; + env->client->flash_timer = 15; + env->client->show_flash = true; + env->client->last_action_r = action / GRID_SIZE; + env->client->last_action_c = action % GRID_SIZE; + } + } else { + int action_r = action / GRID_SIZE; + int action_c = action % GRID_SIZE; + int dist = abs(action_r - env->mole_r) + abs(action_c - env->mole_c); + env->rewards[0] = fmaxf(0.0f, 1.0f - dist * 0.25f); + // Flash RED for miss + if (env->client != NULL) { + env->client->flash_color = (Color){255, 0, 0, 180}; + env->client->flash_timer = 15; + env->client->show_flash = true; + env->client->last_action_r = action_r; + env->client->last_action_c = action_c; + } + } + + if (env->tick >= ATTEMPTS_PER_EPISODE) { + env->terminals[0] = 1.0f; + add_log(env); + c_reset(env); + } else { + env->terminals[0] = 0.0f; + // Move puffre for next attempt + int new_idx = rand_r(&env->rng) % TOTAL_CELLS; + env->observations[mole_idx] = 0.0f; + env->observations[new_idx] = 1.0f; + env->mole_r = new_idx / GRID_SIZE; + env->mole_c = new_idx % GRID_SIZE; + } +} + +void c_render(Whackamole* env) { + if (!IsWindowReady()) { + InitWindow(CELL_SIZE * GRID_SIZE, CELL_SIZE * GRID_SIZE, "PufferLib WhacKe-a-PUFFER"); + SetTargetFPS(60); + env->client = (Client*)calloc(1, sizeof(Client)); + env->client->puffer = LoadTexture("pufferfish.png"); + if (env->client->puffer.id == 0) { + env->client->puffer = LoadTexture("ocean/whackamole/pufferfish.png"); + } + env->client->show_flash = false; + env->client->flash_timer = 0; + } + + if (IsKeyDown(KEY_ESCAPE)) { + exit(0); + } + + BeginDrawing(); + ClearBackground((Color){34, 139, 34, 255}); + + for (int r = 0; r < GRID_SIZE; r++) { + for (int c = 0; c < GRID_SIZE; c++) { + int cx = c * CELL_SIZE + CELL_SIZE / 2; + int cy = r * CELL_SIZE + CELL_SIZE / 2; + DrawCircle(cx, cy, CELL_SIZE / 3, DARKGRAY); + } + } + + for (int i = 1; i < GRID_SIZE; i++) { + int pos = i * CELL_SIZE; + DrawLine(pos, 0, pos, CELL_SIZE * GRID_SIZE, BLACK); + DrawLine(0, pos, CELL_SIZE * GRID_SIZE, pos, BLACK); + } + + if (env->client->show_flash && env->client->flash_timer > 0) { + int fx = env->client->last_action_c * CELL_SIZE; + int fy = env->client->last_action_r * CELL_SIZE; + DrawRectangle(fx, fy, CELL_SIZE, CELL_SIZE, env->client->flash_color); + env->client->flash_timer--; + if (env->client->flash_timer <= 0) { + env->client->show_flash = false; + } + } + + int x = env->mole_c * CELL_SIZE; + int y = env->mole_r * CELL_SIZE; + + if (env->client->puffer.id > 0) { + float scale = (float)CELL_SIZE / env->client->puffer.width; + DrawTextureEx(env->client->puffer, (Vector2){x, y}, 0.0f, scale, WHITE); + } else { + DrawCircle(x + CELL_SIZE/2, y + CELL_SIZE/2, CELL_SIZE/3, RED); + DrawCircle(x + CELL_SIZE/2, y + CELL_SIZE/2, CELL_SIZE/4, YELLOW); + } + + DrawText(TextFormat("Hits: %i", env->hits), 10, 10, 24, WHITE); + DrawText(TextFormat("Return: %.1f", env->log.episode_return), 10, 40, 20, WHITE); + DrawText(TextFormat("Attempt: %i/%i", env->tick + 1, ATTEMPTS_PER_EPISODE), 10, 70, 20, WHITE); + + EndDrawing(); +} + +void c_close(Whackamole* env) { + if (env->client != NULL) { + if (env->client->puffer.id > 0) { + UnloadTexture(env->client->puffer); + } + free(env->client); + env->client = NULL; + } + if (IsWindowReady()) { + CloseWindow(); + } +} \ No newline at end of file From 1227d747531e91bd0d984053d6819abca64d5aab Mon Sep 17 00:00:00 2001 From: Sagnik P <100442225+doofenshirmtz@users.noreply.github.com> Date: Fri, 1 May 2026 22:59:20 +0530 Subject: [PATCH 2/2] Update whackamole.ini --- config/whackamole.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/whackamole.ini b/config/whackamole.ini index db7b5e10b..af4b6c0a0 100644 --- a/config/whackamole.ini +++ b/config/whackamole.ini @@ -5,8 +5,8 @@ env_name = whackamole num_envs = 4096 [policy] -hidden_size = 256 -num_layers = 2 +hidden_size = 64 +num_layers = 1 [train] learning_rate = 0.001