diff --git a/overlay/rootfs/usr/bin/snake b/overlay/rootfs/usr/bin/snake index 8b4621c..5553412 100755 Binary files a/overlay/rootfs/usr/bin/snake and b/overlay/rootfs/usr/bin/snake differ diff --git a/overlay/rootfs/usr/bin/tetris b/overlay/rootfs/usr/bin/tetris index d893b1f..e89787b 100755 Binary files a/overlay/rootfs/usr/bin/tetris and b/overlay/rootfs/usr/bin/tetris differ diff --git a/prebuilt/games/usr/bin/snake b/prebuilt/games/usr/bin/snake index 8b4621c..5553412 100755 Binary files a/prebuilt/games/usr/bin/snake and b/prebuilt/games/usr/bin/snake differ diff --git a/prebuilt/games/usr/bin/tetris b/prebuilt/games/usr/bin/tetris index d893b1f..e89787b 100755 Binary files a/prebuilt/games/usr/bin/tetris and b/prebuilt/games/usr/bin/tetris differ diff --git a/src/games/snake.cpp b/src/games/snake.cpp index 7fc5353..7cc8832 100644 --- a/src/games/snake.cpp +++ b/src/games/snake.cpp @@ -219,7 +219,8 @@ static void render() { // frame the whole window (right/bottom edges too) XSetForeground(dpy, gc, C_DIM); - XDrawRectangle(dpy, back, gc, 0, 0, winW - 1, winH - 1); + XDrawRectangle(dpy, back, gc, 2, 2, winW - 4, winH - 4); + XDrawRectangle(dpy, back, gc, 3, 3, winW - 6, winH - 6); // food if (foodx >= 0) { @@ -363,6 +364,7 @@ int main() { FD_ZERO(&fds); FD_SET(xfd, &fds); int r = select(xfd + 1, &fds, nullptr, nullptr, &tv); + bool dirty = false; if (r > 0) { XEvent e; while (XPending(dpy)) { @@ -371,13 +373,15 @@ int main() { if (!running) break; } if (!running) break; + dirty = true; } if (running && now_ms() >= nextTick) { if (state == PLAYING) step(); if (state == PLAYING) nextTick = now_ms() + speed; else nextTick = now_ms() + 80; // keep loop responsive while paused/over - render(); + dirty = true; } + if (dirty) render(); } XFreeGC(dpy, gc); diff --git a/src/games/tetris.cpp b/src/games/tetris.cpp index cd130a1..4adf8f3 100644 --- a/src/games/tetris.cpp +++ b/src/games/tetris.cpp @@ -92,14 +92,16 @@ static unsigned long C_BG, C_FG, C_HEAD, C_FOOD, C_DIM; // ---- tetromino definitions (state 0 within a 4x4 box) ---- // type 0..6 -> I,O,T,S,Z,J,L -static const int BASE[7][4][2] = { - {{0,1},{1,1},{2,1},{3,1}}, // I - {{1,0},{2,0},{1,1},{2,1}}, // O - {{1,0},{0,1},{1,1},{2,1}}, // T - {{1,0},{2,0},{0,1},{1,1}}, // S - {{0,0},{1,0},{1,1},{2,1}}, // Z - {{0,0},{0,1},{1,1},{2,1}}, // J - {{2,0},{0,1},{1,1},{2,1}}, // L +// 7 tetrominoes, each with 4 explicit rotation states (classic SRS-style). +// type 0..6 -> I,O,T,S,Z,J,L. Coordinates are within a 4x4 box [x,y]. +static const int SHAPES[7][4][4][2] = { + { {{0,1},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{2,2},{2,3}}, {{0,2},{1,2},{2,2},{3,2}}, {{1,0},{1,1},{1,2},{1,3}} }, // I + { {{1,0},{2,0},{1,1},{2,1}}, {{1,0},{2,0},{1,1},{2,1}}, {{1,0},{2,0},{1,1},{2,1}}, {{1,0},{2,0},{1,1},{2,1}} }, // O + { {{1,0},{0,1},{1,1},{2,1}}, {{1,0},{1,1},{2,1},{1,2}}, {{0,1},{1,1},{2,1},{1,2}}, {{1,0},{0,1},{1,1},{1,2}} }, // T + { {{1,0},{2,0},{0,1},{1,1}}, {{1,0},{1,1},{2,1},{2,2}}, {{1,1},{2,1},{0,2},{1,2}}, {{0,0},{0,1},{1,1},{1,2}} }, // S + { {{0,0},{1,0},{1,1},{2,1}}, {{2,0},{1,1},{2,1},{1,2}}, {{0,1},{1,1},{1,2},{2,2}}, {{1,0},{0,1},{1,1},{0,2}} }, // Z + { {{0,0},{0,1},{1,1},{2,1}}, {{1,0},{2,0},{1,1},{1,2}}, {{0,1},{1,1},{2,1},{2,2}}, {{1,0},{1,1},{0,2},{1,2}} }, // J + { {{2,0},{0,1},{1,1},{2,1}}, {{1,0},{1,1},{1,2},{2,2}}, {{0,1},{1,1},{2,1},{0,2}}, {{0,0},{1,0},{1,1},{1,2}} }, // L }; enum State { PLAYING, PAUSED, GAMEOVER }; @@ -112,16 +114,12 @@ static int speed = 1000; // ms per gravity step static unsigned long nextTick = 0; static bool running = true; -static void rotate_cells(const int src[4][2], int dst[4][2], int times) { - for (int i = 0; i < 4; i++) { - int x = src[i][0], y = src[i][1]; - for (int t = 0; t < times; t++) { int nx = 3 - y; int ny = x; x = nx; y = ny; } - dst[i][0] = x; dst[i][1] = y; - } -} - static void piece_cells(int type, int rot, int out[4][2]) { - rotate_cells(BASE[type], out, ((rot % 4) + 4) % 4); + int r = ((rot % 4) + 4) % 4; + for (int i = 0; i < 4; i++) { + out[i][0] = SHAPES[type][r][i][0]; + out[i][1] = SHAPES[type][r][i][1]; + } } static bool collide(int px, int py, int cells[4][2]) { @@ -214,14 +212,18 @@ static void try_move(int dx) { } static void try_rotate() { + int nr = (curRot + 1) % 4; int cells[4][2]; - piece_cells(curType, (curRot + 1) % 4, cells); - // simple wall kick: try shift left/right if blocked - if (!collide(curX, curY, cells)) { curRot = (curRot + 1) % 4; return; } - if (!collide(curX - 1, curY, cells)) { curX--; curRot = (curRot + 1) % 4; return; } - if (!collide(curX + 1, curY, cells)) { curX++; curRot = (curRot + 1) % 4; return; } - if (!collide(curX - 2, curY, cells)) { curX -= 2; curRot = (curRot + 1) % 4; return; } - if (!collide(curX + 2, curY, cells)) { curX += 2; curRot = (curRot + 1) % 4; return; } + piece_cells(curType, nr, cells); + // wall kicks: try in place, then small horizontal shifts + int kicks[5] = {0, -1, 1, -2, 2}; + for (int k = 0; k < 5; k++) { + if (!collide(curX + kicks[k], curY, cells)) { + curX += kicks[k]; + curRot = nr; + return; + } + } } static void reset_game() { @@ -259,7 +261,8 @@ static void render() { // frame the whole window (right/bottom edges too) XSetForeground(dpy, gc, C_DIM); - XDrawRectangle(dpy, back, gc, 0, 0, winW - 1, winH - 1); + XDrawRectangle(dpy, back, gc, 2, 2, winW - 4, winH - 4); + XDrawRectangle(dpy, back, gc, 3, 3, winW - 6, winH - 6); // settled blocks for (int x = 0; x < PCOLS; x++) @@ -445,6 +448,7 @@ int main() { FD_ZERO(&fds); FD_SET(xfd, &fds); int r = select(xfd + 1, &fds, nullptr, nullptr, &tv); + bool dirty = false; if (r > 0) { XEvent e; while (XPending(dpy)) { @@ -453,13 +457,15 @@ int main() { if (!running) break; } if (!running) break; + dirty = true; } if (running && now_ms() >= nextTick) { if (state == PLAYING) step(); if (state == PLAYING) nextTick = now_ms() + speed; else nextTick = now_ms() + 80; - render(); + dirty = true; } + if (dirty) render(); } XFreeGC(dpy, gc);