tetris ?

Taka nowość z uC RP2040 Dual CORE ARM Cortex M0+ pędzącym 133MHz
ODPOWIEDZ
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1488
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

tetris ?

Post autor: SunRiver »

W sumie do czego innego powstała matryca 8x8 na diodach WS , ale tak dla zabawy ...
oczywiście to tylko animacja , niemniej można rozwinąć łatwo do pełnoprawnej gry ...

Obrazek

filmik :
https://photos.app.goo.gl/4gpnijQ3R8pn35ek7


Przypominam:
Pico Pi RP2040 lub inna na rp2040
Wyjście dla WS2812B -- PIN GP2

Matryca 8x8 w stylu zigzag czyli lewy górny róg wejście D0 , lewy dolny róg wyjście D63
  1.  
  2. ┌────────────────────────────┐
  3. │  0  1  2  3  4  5  6  7    │  <- górny wiersz
  4. 15 14 13 12 11 10  9  8    │
  5. 16 17 18 19 20 21 22 23    │
  6. 31 30 29 28 27 26 25 24    │
  7. 32 33 34 35 36 37 38 39    │
  8. 47 46 45 44 43 42 41 40    │
  9. 48 49 50 51 52 53 54 55    │
  10. 63 62 61 60 59 58 57 56    │  <- dolny wiersz
  11. └────────────────────────────┘
  12.  
Kod tego że tak powiem programu z niedopracowaną Ai , -- niedopracowaną bo jest blond , ale ją ufarbujemy i będzie git :)

  1.  
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "pico/stdlib.h"
  6. #include "hardware/pio.h"
  7. #include "hardware/clocks.h"
  8. #include "ws2812.pio.h"
  9.  
  10. // --- Konfiguracja ---
  11. #define WS2812_PIN 2
  12. #define MATRIX_WIDTH  8
  13. #define MATRIX_HEIGHT 8
  14. #define LED_COUNT (MATRIX_WIDTH * MATRIX_HEIGHT)
  15. #define IS_RGBW false
  16.  
  17. // --- Bufory i plansza ---
  18. uint32_t led_buffer[LED_COUNT];
  19. uint8_t board[MATRIX_HEIGHT][MATRIX_WIDTH]; // 0 = puste, >0 = kolor
  20.  
  21. // --- Klocki Tetris ---
  22. const uint8_t tetrominoes[7][4][4] = {
  23.     // I
  24.     { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  25.     // O
  26.     { { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  27.     // T
  28.     { { 0, 1, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  29.     // S
  30.     { { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  31.     // Z
  32.     { { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  33.     // J
  34.     { { 1, 0, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  35.     // L
  36.     { { 0, 0, 1, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }
  37. };
  38.  
  39. // Kolory Tetrisa
  40. uint32_t tetris_colors[8] = {
  41.     0,
  42.     0x00FFFF,
  43.     // cyan
  44.     0xFFFF00,
  45.     // yellow
  46.     0xA000F0,
  47.     // purple
  48.     0x00FF00,
  49.     // green
  50.     0xFF0000,
  51.     // red
  52.     0x0000FF,
  53.     // blue
  54.     0xFFA000  // orange
  55. };
  56.  
  57. // --- Funkcje pomocnicze ---
  58. static inline uint32_t xy_to_index(uint8_t x, uint8_t y) {
  59.     // Zigzag, górny lewy = 0, dolny lewy = 63
  60.     if (y % 2 == 0) return y * MATRIX_WIDTH + x;
  61.     else return y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x);
  62. }
  63.  
  64. static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
  65.     return ((uint32_t)g << 16) | ((uint32_t)r << 8) | b;
  66. }
  67.  
  68. void show(PIO pio, uint sm) {
  69.     for (int i = 0; i < LED_COUNT; i++)
  70.         pio_sm_put_blocking(pio, sm, led_buffer[i] << 8u);
  71. }
  72.  
  73. void clear_matrix() {
  74.     for (int i = 0; i < LED_COUNT; i++) led_buffer[i] = 0;
  75. }
  76.  
  77. // --- PIO WS2812 ---
  78. static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
  79.     pio_sm_config c = ws2812_program_get_default_config(offset);
  80.     sm_config_set_sideset_pins(&c, pin);
  81.     sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
  82.     sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
  83.  
  84.     int cycles_per_bit = 10;
  85.     float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
  86.     sm_config_set_clkdiv(&c, div);
  87.  
  88.     pio_gpio_init(pio, pin);
  89.     pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
  90.     pio_sm_init(pio, sm, offset, &c);
  91.     pio_sm_set_enabled(pio, sm, true);
  92. }
  93.  
  94. // --- Tetris ---
  95. void rotate(uint8_t dst[4][4], uint8_t src[4][4]) {
  96.     for (int y = 0; y < 4; y++)
  97.         for (int x = 0; x < 4; x++)
  98.             dst[y][x] = src[3 - x][y];
  99. }
  100.  
  101. bool collision(uint8_t piece[4][4], int px, int py) {
  102.     for (int y = 0; y < 4; y++)
  103.         for (int x = 0; x < 4; x++) {
  104.             if (!piece[y][x]) continue;
  105.             int bx = px + x;
  106.             int by = py + y;
  107.             if (bx < 0 || bx >= MATRIX_WIDTH || by >= MATRIX_HEIGHT) return true;
  108.             if (by >= 0 && board[by][bx]) return true;
  109.         }
  110.     return false;
  111. }
  112.  
  113. void merge_piece(uint8_t piece[4][4], int px, int py, uint8_t color) {
  114.     for (int y = 0; y < 4; y++)
  115.         for (int x = 0; x < 4; x++)
  116.             if (piece[y][x] && py + y >= 0)
  117.                 board[py + y][px + x] = color;
  118. }
  119.  
  120. void clear_lines() {
  121.     for (int y = MATRIX_HEIGHT - 1; y >= 0; y--) {
  122.         bool full = true;
  123.         for (int x = 0; x < MATRIX_WIDTH; x++)
  124.             if (!board[y][x]) full = false;
  125.         if (full) {
  126.             for (int yy = y; yy > 0; yy--)
  127.                 for (int x = 0; x < MATRIX_WIDTH; x++)
  128.                     board[yy][x] = board[yy - 1][x];
  129.             for (int x = 0; x < MATRIX_WIDTH; x++) board[0][x] = 0;
  130.             y++;
  131.         }
  132.     }
  133. }
  134.  
  135. void draw_board() {
  136.     clear_matrix();
  137.     for (int y = 0; y < MATRIX_HEIGHT; y++)
  138.         for (int x = 0; x < MATRIX_WIDTH; x++)
  139.             if (board[y][x])
  140.                 led_buffer[xy_to_index(x, y)] = tetris_colors[board[y][x]];
  141. }
  142.  
  143. // --- AI: prosty losowy gracz ---
  144. void ai_place_piece(uint8_t piece[4][4], uint8_t color) {
  145.     int rotation = rand() % 4;
  146.     uint8_t rotated[4][4];
  147.     memcpy(rotated, piece, 16);
  148.     for (int r = 0; r < rotation; r++) {
  149.         uint8_t tmp[4][4];
  150.         rotate(tmp, rotated);
  151.         memcpy(rotated, tmp, 16);
  152.     }
  153.     memcpy(piece, rotated, 16);
  154.  
  155.     int best_x = rand() % (MATRIX_WIDTH - 3);
  156.     int py = -4;
  157.     while (!collision(piece, best_x, py + 1)) py++;
  158.     merge_piece(piece, best_x, py, color);
  159.     clear_lines();
  160. }
  161.  
  162. // --- Main ---
  163. int main() {
  164.     stdio_init_all();
  165.     sleep_ms(100);
  166.  
  167.     PIO pio = pio0;
  168.     uint sm = 0;
  169.     uint offset = pio_add_program(pio, &ws2812_program);
  170.     ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW);
  171.  
  172.     memset(board, 0, sizeof(board));
  173.  
  174.     while (true) {
  175.         // Losowy klocek
  176.         int type = rand() % 7;
  177.         uint8_t piece[4][4];
  178.         memcpy(piece, tetrominoes[type], 16);
  179.  
  180.         // Losowa rotacja
  181.         uint8_t rotated[4][4];
  182.         memcpy(rotated, piece, 16);
  183.         int rotations = rand() % 4;
  184.         for (int r = 0; r < rotations; r++) {
  185.             uint8_t tmp[4][4];
  186.             rotate(tmp, rotated);
  187.             memcpy(rotated, tmp, 16);
  188.         }
  189.         memcpy(piece, rotated, 16);
  190.  
  191.         // Losowa kolumna startowa
  192.         int px = rand() % (MATRIX_WIDTH - 3);
  193.         int py = -4;
  194.         uint8_t color = type + 1;
  195.  
  196.         // Animacja spadania
  197.         while (true) {
  198.             if (!collision(piece, px, py + 1)) {
  199.                 py++;
  200.             }
  201.             else {
  202.                 merge_piece(piece, px, py, color);
  203.                 clear_lines();
  204.                 break;
  205.             }
  206.  
  207.             draw_board();
  208.  
  209.             // Wyświetlenie aktualnego klocka
  210.             for (int y = 0; y < 4; y++)
  211.                 for (int x = 0; x < 4; x++)
  212.                     if (piece[y][x] && py + y >= 0)
  213.                         led_buffer[xy_to_index(px + x, py + y)] = tetris_colors[color];
  214.  
  215.             show(pio, sm);
  216.             sleep_ms(200); // czas spadania pojedynczego kroku
  217.         }
  218.  
  219.         // Krótkie zatrzymanie po umieszczeniu klocka
  220.         draw_board();
  221.         show(pio, sm);
  222.         sleep_ms(300);
  223.     }
  224. }
  225.  
  226.  
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Awatar użytkownika
gufim
Użytkownik
Posty: 170
Rejestracja: 16 paź 2017, 16:58

Re: tetris ?

Post autor: gufim »

Super :)
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1488
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

Re: tetris ?

Post autor: SunRiver »

Dobra .... chciałeś maras to masz ...

Zrobiłem małego pełnoprawnego Tetrisa na matrycy LED 8×8, bo najwyraźniej klasyczny Tetris był za mały na Raspberry Pi Pico 😉

Projekt działa na Raspberry Pi Pico + WS2812, sterowany czterema przyciskami.
Plansza ma 8×8, więc decyzje trzeba podejmować szybciej niż w normalnym Tetrisie 😄

Co potrafi ta wersja:


-- klasyczne klocki Tetrisa
-- sterowanie: lewo / prawo / dół / obrót
-- zrobiłem też animację startową prosto bo tylko 3–2–1 ale ....
-- migające pełne linie (jak w prawdziwym Tetrisie)
-- Game Over, gdy zabraknie miejsca albo klocek nie zmieści się od góry
-- kolorowa animacja Game Over –
-- restart gry po naciśnięciu dowolnego przycisku

Całość napisana w C, bez systemu operacyjnego, tylko Pico SDK i trochę cierpliwości do debouncingu przycisków 😉

Jeśli ktoś też lubi:

LEDy, retro gry,
projekty „trochę bez sensu, ale bardzo fajne”

to będzie mu się to podobać 👍

Filmik .... nie nie grałem , ale wy możecie ... :)



Chętnie posłucham sugestii, co dodać dalej ....

A tu jak zbudować sobie matrixa https://forum.lothar-team.pl/viewtopic.php?p=3394#p3394

Pełny kod źródłowy ....
  1.  
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "pico/stdlib.h"
  6. #include "hardware/pio.h"
  7. #include "hardware/clocks.h"
  8. #include "ws2812.pio.h"
  9.  
  10. // ---------- KONFIGURACJA ----------
  11. #define WS2812_PIN 2
  12. #define MATRIX_WIDTH 8
  13. #define MATRIX_HEIGHT 8
  14. #define LED_COUNT (MATRIX_WIDTH * MATRIX_HEIGHT)
  15. #define IS_RGBW false
  16.  
  17. #define BTN_LEFT   12
  18. #define BTN_RIGHT  13
  19. #define BTN_DOWN   14
  20. #define BTN_ROTATE 15
  21. #define DEBOUNCE_MS 120
  22.  
  23. // ---------- BUFOR ----------
  24. uint32_t led_buffer[LED_COUNT];
  25. uint8_t board[MATRIX_HEIGHT][MATRIX_WIDTH];
  26.  
  27. // ---------- TETROMINO ----------
  28. const uint8_t tetrominoes[7][4][4] = {
  29.     { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  30.     // I
  31.     { { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  32.     // O
  33.     { { 0, 1, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  34.     // T
  35.     { { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  36.     // S
  37.     { { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  38.     // Z
  39.     { { 1, 0, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  40.     // J
  41.     { { 0, 0, 1, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }  // L
  42. };
  43.  
  44. uint32_t tetris_colors[8] = {
  45.     0,
  46.     0x00FFFF,
  47.     0xFFFF00,
  48.     0xA000F0,
  49.     0x00FF00,
  50.     0xFF0000,
  51.     0x0000FF,
  52.     0xFFA000
  53. };
  54.  
  55. // ---------- MAPOWANIE ----------
  56. static inline uint32_t xy_to_index(uint8_t x, uint8_t y) {
  57.     return (y % 2 == 0) ? y * MATRIX_WIDTH + x
  58.                         : y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x);
  59. }
  60.  
  61. void show(PIO pio, uint sm) {
  62.     for (int i = 0; i < LED_COUNT; i++)
  63.         pio_sm_put_blocking(pio, sm, led_buffer[i] << 8u);
  64. }
  65.  
  66. void clear_matrix() {
  67.     memset(led_buffer, 0, sizeof(led_buffer));
  68. }
  69.  
  70. void draw_board() {
  71.     clear_matrix();
  72.     for (int y = 0; y < MATRIX_HEIGHT; y++)
  73.         for (int x = 0; x < MATRIX_WIDTH; x++)
  74.             if (board[y][x])
  75.                 led_buffer[xy_to_index(x, y)] = tetris_colors[board[y][x]];
  76. }
  77.  
  78. // ---------- PIO ----------
  79. static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin) {
  80.     pio_sm_config c = ws2812_program_get_default_config(offset);
  81.     sm_config_set_sideset_pins(&c, pin);
  82.     sm_config_set_out_shift(&c, false, true, 24);
  83.     sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
  84.  
  85.     float div = clock_get_hz(clk_sys) / (800000 * 10);
  86.     sm_config_set_clkdiv(&c, div);
  87.  
  88.     pio_gpio_init(pio, pin);
  89.     pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
  90.     pio_sm_init(pio, sm, offset, &c);
  91.     pio_sm_set_enabled(pio, sm, true);
  92. }
  93.  
  94. // ---------- LOGIKA ----------
  95. void rotate(uint8_t d[4][4], uint8_t s[4][4]) {
  96.     for (int y = 0; y < 4; y++)
  97.         for (int x = 0; x < 4; x++)
  98.             d[y][x] = s[3 - x][y];
  99. }
  100.  
  101. bool collision(uint8_t p[4][4], int px, int py) {
  102.     for (int y = 0; y < 4; y++)
  103.         for (int x = 0; x < 4; x++) {
  104.             if (!p[y][x]) continue;
  105.             int bx = px + x, by = py + y;
  106.             if (bx < 0 || bx >= MATRIX_WIDTH || by >= MATRIX_HEIGHT) return true;
  107.             if (by >= 0 && board[by][bx]) return true;
  108.         }
  109.     return false;
  110. }
  111.  
  112. void merge_piece(uint8_t p[4][4], int px, int py, uint8_t c) {
  113.     for (int y = 0; y < 4; y++)
  114.         for (int x = 0; x < 4; x++)
  115.             if (p[y][x] && py + y >= 0)
  116.                 board[py + y][px + x] = c;
  117. }
  118.  
  119. // ---------- LINIE ----------
  120. void blink_line(int y, PIO pio, uint sm) {
  121.     for (int i = 0; i < 3; i++) {
  122.         for (int x = 0; x < MATRIX_WIDTH; x++)
  123.             led_buffer[xy_to_index(x, y)] = 0;
  124.         show(pio, sm);
  125.         sleep_ms(120);
  126.         for (int x = 0; x < MATRIX_WIDTH; x++)
  127.             led_buffer[xy_to_index(x, y)] = 0xFFFFFF;
  128.         show(pio, sm);
  129.         sleep_ms(120);
  130.     }
  131. }
  132.  
  133. void clear_lines(PIO pio, uint sm) {
  134.     for (int y = MATRIX_HEIGHT - 1; y >= 0; y--) {
  135.         bool full = true;
  136.         for (int x = 0; x < MATRIX_WIDTH; x++)
  137.             if (!board[y][x]) full = false;
  138.         if (full) {
  139.             draw_board();
  140.             blink_line(y, pio, sm);
  141.             for (int yy = y; yy > 0; yy--)
  142.                 memcpy(board[yy], board[yy - 1], MATRIX_WIDTH);
  143.             memset(board[0], 0, MATRIX_WIDTH);
  144.             y++;
  145.         }
  146.     }
  147. }
  148.  
  149. // ---------- PRZYCISKI ----------
  150. bool button_pressed(uint pin) {
  151.     static absolute_time_t last[32];
  152.     absolute_time_t now = get_absolute_time();
  153.     if (!gpio_get(pin) &&
  154.         absolute_time_diff_us(last[pin], now) > DEBOUNCE_MS * 1000) {
  155.         last[pin] = now;
  156.         return true;
  157.     }
  158.     return false;
  159. }
  160.  
  161. // ---------- START 3-2-1 ----------
  162. const uint8_t digits[3][5][5] = {
  163.     { { 1, 1, 1, 1, 0 }, { 0, 0, 0, 1, 0 }, { 0, 1, 1, 1, 0 }, { 0, 0, 0, 1, 0 }, { 1, 1, 1, 1, 0 } },
  164.     { { 1, 1, 1, 1, 0 }, { 0, 0, 0, 1, 0 }, { 1, 1, 1, 1, 0 }, { 1, 0, 0, 0, 0 }, { 1, 1, 1, 1, 0 } },
  165.     { { 0, 0, 1, 0, 0 }, { 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0, 1, 1, 1, 0 } }
  166. };
  167.  
  168. void start_animation(PIO pio, uint sm) {
  169.     for (int d = 0; d < 3; d++) {
  170.         clear_matrix();
  171.         for (int y = 0; y < 5; y++)
  172.             for (int x = 0; x < 5; x++)
  173.                 if (digits[d][y][x])
  174.                     led_buffer[xy_to_index(x + 1, y + 1)] = 0xFFFFFF;
  175.         show(pio, sm);
  176.         sleep_ms(600);
  177.         clear_matrix();
  178.         show(pio, sm);
  179.         sleep_ms(150);
  180.     }
  181. }
  182.  
  183. // ---------- GAME OVER – WĄŻ ----------
  184. void game_over_snake(PIO pio, uint sm) {
  185.     clear_matrix();
  186.  
  187.     int left = 0;
  188.     int right = MATRIX_WIDTH - 1;
  189.     int top = 0;
  190.     int bottom = MATRIX_HEIGHT - 1;
  191.  
  192.     int color_idx = 1;
  193.  
  194.     while (left <= right && top <= bottom) {
  195.  
  196.         // górny wiersz →
  197.         for (int x = left; x <= right; x++) {
  198.             led_buffer[xy_to_index(x, top)] = tetris_colors[color_idx];
  199.             show(pio, sm);
  200.             sleep_ms(35);
  201.             color_idx = (color_idx % 7) + 1;
  202.         }
  203.         top++;
  204.  
  205.         // prawa kolumna ↓
  206.         for (int y = top; y <= bottom; y++) {
  207.             led_buffer[xy_to_index(right, y)] = tetris_colors[color_idx];
  208.             show(pio, sm);
  209.             sleep_ms(35);
  210.             color_idx = (color_idx % 7) + 1;
  211.         }
  212.         right--;
  213.  
  214.         // dolny wiersz ←
  215.         if (top <= bottom) {
  216.             for (int x = right; x >= left; x--) {
  217.                 led_buffer[xy_to_index(x, bottom)] = tetris_colors[color_idx];
  218.                 show(pio, sm);
  219.                 sleep_ms(35);
  220.                 color_idx = (color_idx % 7) + 1;
  221.             }
  222.             bottom--;
  223.         }
  224.  
  225.         // lewa kolumna ↑
  226.         if (left <= right) {
  227.             for (int y = bottom; y >= top; y--) {
  228.                 led_buffer[xy_to_index(left, y)] = tetris_colors[color_idx];
  229.                 show(pio, sm);
  230.                 sleep_ms(35);
  231.                 color_idx = (color_idx % 7) + 1;
  232.             }
  233.             left++;
  234.         }
  235.     }
  236.  
  237.     // Miganie środka wszystkimi kolorami
  238.     for (int i = 0; i < 6; i++) {
  239.         for (int y = 0; y < MATRIX_HEIGHT; y++)
  240.             for (int x = 0; x < MATRIX_WIDTH; x++)
  241.                 led_buffer[xy_to_index(x, y)] =
  242.                     tetris_colors[(i + x + y) % 7 + 1];
  243.  
  244.         show(pio, sm);
  245.         sleep_ms(180);
  246.     }
  247.  
  248.     clear_matrix();
  249.     show(pio, sm);
  250. }
  251.  
  252.  
  253. bool piece_locked_above_board(int py) {
  254.     return py < 0;
  255. }
  256.  
  257. bool board_full(void) {
  258.     for (int y = 0; y < MATRIX_HEIGHT; y++)
  259.         for (int x = 0; x < MATRIX_WIDTH; x++)
  260.             if (!board[y][x])
  261.                 return false;
  262.     return true;
  263. }
  264.  
  265. void wait_for_any_button(void) {
  266.     while (true) {
  267.         if (button_pressed(BTN_LEFT) ||
  268.             button_pressed(BTN_RIGHT) ||
  269.             button_pressed(BTN_DOWN) ||
  270.             button_pressed(BTN_ROTATE)) {
  271.             sleep_ms(200); // zabezpieczenie przed odbiciem
  272.             return;
  273.         }
  274.         sleep_ms(10);
  275.     }
  276. }
  277.  
  278. // ---------- MAIN ----------
  279. int main() {
  280.     stdio_init_all();
  281.     sleep_ms(100);
  282.  
  283.     PIO pio = pio0;
  284.     uint sm = 0;
  285.     uint offset = pio_add_program(pio, &ws2812_program);
  286.     ws2812_program_init(pio, sm, offset, WS2812_PIN);
  287.  
  288.     gpio_init(BTN_LEFT); gpio_init(BTN_RIGHT);
  289.     gpio_init(BTN_DOWN); gpio_init(BTN_ROTATE);
  290.     gpio_set_dir(BTN_LEFT, GPIO_IN);
  291.     gpio_set_dir(BTN_RIGHT, GPIO_IN);
  292.     gpio_set_dir(BTN_DOWN, GPIO_IN);
  293.     gpio_set_dir(BTN_ROTATE, GPIO_IN);
  294.     gpio_pull_up(BTN_LEFT);
  295.     gpio_pull_up(BTN_RIGHT);
  296.     gpio_pull_up(BTN_DOWN);
  297.     gpio_pull_up(BTN_ROTATE);
  298.  
  299.     start_animation(pio, sm);
  300.     memset(board, 0, sizeof(board));
  301.  
  302.     while (true) {
  303.         int type = rand() % 7;
  304.         uint8_t piece[4][4];
  305.         memcpy(piece, tetrominoes[type], 16);
  306.  
  307.         int px = rand() % (MATRIX_WIDTH - 3);
  308.         int py = -4;
  309.         uint8_t color = type + 1;
  310.  
  311.         // Game Over – brak miejsca na nowy klocek
  312.         if (collision(piece, px, py + 1) || board_full()) {
  313.             game_over_snake(pio, sm);
  314.             wait_for_any_button();
  315.             memset(board, 0, sizeof(board));
  316.             start_animation(pio, sm);
  317.             continue;
  318.         }
  319.  
  320.         while (true) {
  321.  
  322.             // --- Sterowanie ---
  323.             if (button_pressed(BTN_LEFT) && !collision(piece, px - 1, py))
  324.                 px--;
  325.  
  326.             if (button_pressed(BTN_RIGHT) && !collision(piece, px + 1, py))
  327.                 px++;
  328.  
  329.             if (button_pressed(BTN_DOWN) && !collision(piece, px, py + 1))
  330.                 py++;
  331.  
  332.             if (button_pressed(BTN_ROTATE)) {
  333.                 uint8_t r[4][4];
  334.                 rotate(r, piece);
  335.                 if (!collision(r, px, py))
  336.                     memcpy(piece, r, 16);
  337.             }
  338.  
  339.             // --- Grawitacja ---
  340.             if (!collision(piece, px, py + 1)) {
  341.                 py++;
  342.             }
  343.             else {
  344.                 // Klocek się zablokował
  345.  
  346.                 // GAME OVER – klocek nie zmieścił się w całości
  347.                 if (py < 0) {
  348.                     game_over_snake(pio, sm);
  349.                     wait_for_any_button();
  350.                     memset(board, 0, sizeof(board));
  351.                     start_animation(pio, sm);
  352.                     break;
  353.                 }
  354.  
  355.                 merge_piece(piece, px, py, color);
  356.                 clear_lines(pio, sm);
  357.  
  358.                 // GAME OVER – plansza pełna
  359.                 if (board_full()) {
  360.                     game_over_snake(pio, sm);
  361.                     wait_for_any_button();
  362.                     memset(board, 0, sizeof(board));
  363.                     start_animation(pio, sm);
  364.                 }
  365.                 break;
  366.             }
  367.  
  368.             // --- Rysowanie ---
  369.             draw_board();
  370.             for (int y = 0; y < 4; y++)
  371.                 for (int x = 0; x < 4; x++)
  372.                     if (piece[y][x] && py + y >= 0)
  373.                         led_buffer[xy_to_index(px + x, py + y)] =
  374.                             tetris_colors[color];
  375.  
  376.             show(pio, sm);
  377.             sleep_ms(200);
  378.         }
  379.     }
  380. }
  381.  
W załączniku binarki dla każdego :P
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Awatar użytkownika
gufim
Użytkownik
Posty: 170
Rejestracja: 16 paź 2017, 16:58

Re: tetris ?

Post autor: gufim »

Piękny prezent świąyeczny dziękuje :)
Awatar użytkownika
maras52
Użytkownik
Posty: 72
Rejestracja: 24 mar 2019, 10:22
Lokalizacja: Racibórz
Kontakt:

Re: tetris ?

Post autor: maras52 »

SunRiver pisze: 24 gru 2025, 17:10 Dobra .... chciałeś maras to masz ...
To było na zasadzie "Co ja nie zrobię?! Trzymaj mi piwo" :forest
Zdravim
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1488
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

Re: tetris ?

Post autor: SunRiver »

maras52 pisze: 25 gru 2025, 10:34
SunRiver pisze: 24 gru 2025, 17:10 Dobra .... chciałeś maras to masz ...
To było na zasadzie "Co ja nie zrobię?! Trzymaj mi piwo" :forest

HEHEHE , albo jak wolisz Ho Ho Ho .... a jak ze co ... że niby ja nie dam rady :P
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1488
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

Re: tetris ?

Post autor: SunRiver »

Drobne poprawki w kodzie:

-- dodałem autorepeat dla przycisków L/R
-- animacja startowa
-- ulepszona animacja końcowa

Miłej zabawy ....

Można by jeszcze zrobić :
--> poprawić napis END !
--> dodać funkcję next block jak w prawdziwym tetrisie, obecnie klocek się losuje
--> i wiele innych

Tak czy siak miłej zabawy :)

Skompilowane pliki w załączniku

  1.  
  2. /*
  3.  * Tetris na matrycę LED 8x8 z Raspberry Pi Pico
  4.  * Autor: SunRiver / Lothar Team
  5.  * www:   https://forum.lothar-team.pl
  6.  * Data:  2025-12-28
  7.  * Opis:  Gra Tetris z animacją startową, końcową i efektami LED.
  8.  *        Obsługa przycisków: Lewo, Prawo, Dół, Obrót.
  9.  *        
  10.  *        Wersja: 1.0
  11.  *        
  12.  */
  13.  
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "pico/stdlib.h"
  19. #include "hardware/pio.h"
  20. #include "hardware/clocks.h"
  21. #include "ws2812.pio.h"
  22.  
  23. // ---------- KONFIGURACJA ----------
  24. #define WS2812_PIN 2
  25. #define MATRIX_WIDTH 8
  26. #define MATRIX_HEIGHT 8
  27. #define LED_COUNT (MATRIX_WIDTH * MATRIX_HEIGHT)
  28. #define IS_RGBW false
  29.  
  30. #define BTN_LEFT   12
  31. #define BTN_RIGHT  13
  32. #define BTN_DOWN   14
  33. #define BTN_ROTATE 15
  34. #define DEBOUNCE_MS 120
  35.  
  36. #define REPEAT_DELAY_MS  300   // opóźnienie przed autorepeat
  37. #define REPEAT_RATE_MS    90   // szybkość powtarzania
  38.  
  39. // ---------- BUFOR ----------
  40. uint32_t led_buffer[LED_COUNT];
  41. uint8_t board[MATRIX_HEIGHT][MATRIX_WIDTH];
  42.  
  43. // ---------- TETROMINO ----------
  44. // klocki Tetrisa (7 typów)
  45. const uint8_t tetrominoes[7][4][4] = {
  46.     { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  47.     // I
  48.     { { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  49.     // O
  50.     { { 0, 1, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  51.     // T
  52.     { { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  53.     // S
  54.     { { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  55.     // Z
  56.     { { 1, 0, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
  57.     // J
  58.     { { 0, 0, 1, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }  // L
  59. };
  60.  
  61. // Kolory klocków
  62. uint32_t tetris_colors[8] = {
  63.     0,
  64.     0x00FFFF,
  65.     0xFFFF00,
  66.     0xA000F0,
  67.     0x00FF00,
  68.     0xFF0000,
  69.     0x0000FF,
  70.     0xFFA000
  71. };
  72.  
  73. // -- Przyciski
  74. typedef struct {
  75.     bool held;
  76.     absolute_time_t press_time;
  77.     absolute_time_t last_repeat;
  78. } button_state_t;
  79.  
  80. // Stany przycisków L/R
  81. button_state_t btn_left_state = { 0 };
  82. button_state_t btn_right_state = { 0 };
  83.  
  84. // Sprawdza czy którykolwiek przycisk jest wciśnięty (stan, nie event)
  85. bool any_button_held(void) {
  86.     return !gpio_get(BTN_LEFT)  ||
  87.            !gpio_get(BTN_RIGHT) ||
  88.            !gpio_get(BTN_DOWN)  ||
  89.            !gpio_get(BTN_ROTATE);
  90. }
  91.  
  92. // Sprawdza czy współrzędne (x,y) są na obwodzie matrycy
  93. static inline bool is_border(int x, int y) {
  94.     return x == 0 || x == MATRIX_WIDTH - 1 ||
  95.            y == 0 || y == MATRIX_HEIGHT - 1;
  96. }
  97.  
  98. // ---------- MAPOWANIE ----------
  99. static inline uint32_t xy_to_index(uint8_t x, uint8_t y) {
  100.     return (y % 2 == 0) ? y * MATRIX_WIDTH + x
  101.                         : y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x);
  102. }
  103.  
  104. // ---------- WYŚWIETLANIE ----------
  105. void show(PIO pio, uint sm) {
  106.     for (int i = 0; i < LED_COUNT; i++)
  107.         pio_sm_put_blocking(pio, sm, led_buffer[i] << 8u);
  108. }
  109.  
  110. // Czyści bufor matrycy
  111. void clear_matrix() {
  112.     memset(led_buffer, 0, sizeof(led_buffer));
  113. }
  114. // Rysuje planszę na matrycy
  115. void draw_board() {
  116.     clear_matrix();
  117.     for (int y = 0; y < MATRIX_HEIGHT; y++)
  118.         for (int x = 0; x < MATRIX_WIDTH; x++)
  119.             if (board[y][x])
  120.                 led_buffer[xy_to_index(x, y)] = tetris_colors[board[y][x]];
  121. }
  122.  
  123. // Inicjalizacja PIO dla WS2812
  124. static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin) {
  125.     pio_sm_config c = ws2812_program_get_default_config(offset);
  126.     sm_config_set_sideset_pins(&c, pin);
  127.     sm_config_set_out_shift(&c, false, true, 24);
  128.     sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
  129.  
  130.     float div = clock_get_hz(clk_sys) / (800000 * 10);
  131.     sm_config_set_clkdiv(&c, div);
  132.  
  133.     pio_gpio_init(pio, pin);
  134.     pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
  135.     pio_sm_init(pio, sm, offset, &c);
  136.     pio_sm_set_enabled(pio, sm, true);
  137. }
  138.  
  139. // Autorepeat - dla przycisków L/R
  140. bool button_autorepeat(uint pin, button_state_t *state) {
  141.     absolute_time_t now = get_absolute_time();
  142.     bool pressed = !gpio_get(pin); // pull-up
  143.  
  144.     if (pressed) {
  145.         if (!state->held) {
  146.             // pierwsze naciśnięcie
  147.             state->held = true;
  148.             state->press_time = now;
  149.             state->last_repeat = now;
  150.             return true;
  151.         }
  152.  
  153.         // autorepeat
  154.         if (absolute_time_diff_us(state->press_time, now) >
  155.                 REPEAT_DELAY_MS * 1000 &&
  156.             absolute_time_diff_us(state->last_repeat, now) >
  157.                 REPEAT_RATE_MS * 1000) {
  158.  
  159.             state->last_repeat = now;
  160.             return true;
  161.         }
  162.     }
  163.     else {
  164.         // puszczony
  165.         state->held = false;
  166.     }
  167.  
  168.     return false;
  169. }
  170.  
  171.  
  172. // ---------- LOGIKA ----------
  173. void rotate(uint8_t d[4][4], uint8_t s[4][4]) {
  174.     for (int y = 0; y < 4; y++)
  175.         for (int x = 0; x < 4; x++)
  176.             d[y][x] = s[3 - x][y];
  177. }
  178.  
  179. // Sprawdza kolizję klocka z planszą lub krawędziami
  180. bool collision(uint8_t p[4][4], int px, int py) {
  181.     for (int y = 0; y < 4; y++)
  182.         for (int x = 0; x < 4; x++) {
  183.             if (!p[y][x]) continue;
  184.             int bx = px + x, by = py + y;
  185.             if (bx < 0 || bx >= MATRIX_WIDTH || by >= MATRIX_HEIGHT) return true;
  186.             if (by >= 0 && board[by][bx]) return true;
  187.         }
  188.     return false;
  189. }
  190.  
  191. // Łączy klocek z planszą
  192. void merge_piece(uint8_t p[4][4], int px, int py, uint8_t c) {
  193.     for (int y = 0; y < 4; y++)
  194.         for (int x = 0; x < 4; x++)
  195.             if (p[y][x] && py + y >= 0)
  196.                 board[py + y][px + x] = c;
  197. }
  198.  
  199. // ---------- LINIE ----------
  200. void blink_line(int y, PIO pio, uint sm) {
  201.     for (int i = 0; i < 3; i++) {
  202.         for (int x = 0; x < MATRIX_WIDTH; x++)
  203.             led_buffer[xy_to_index(x, y)] = 0;
  204.         show(pio, sm);
  205.         sleep_ms(120);
  206.         for (int x = 0; x < MATRIX_WIDTH; x++)
  207.             led_buffer[xy_to_index(x, y)] = 0xFFFFFF;
  208.         show(pio, sm);
  209.         sleep_ms(120);
  210.     }
  211. }
  212.  
  213. // Sprawdza i usuwa pełne linie
  214. void clear_lines(PIO pio, uint sm) {
  215.     for (int y = MATRIX_HEIGHT - 1; y >= 0; y--) {
  216.         bool full = true;
  217.         for (int x = 0; x < MATRIX_WIDTH; x++)
  218.             if (!board[y][x]) full = false;
  219.         if (full) {
  220.             draw_board();
  221.             blink_line(y, pio, sm);
  222.             for (int yy = y; yy > 0; yy--)
  223.                 memcpy(board[yy], board[yy - 1], MATRIX_WIDTH);
  224.             memset(board[0], 0, MATRIX_WIDTH);
  225.             y++;
  226.         }
  227.     }
  228. }
  229.  
  230. // ---------- PRZYCISKI ----------
  231. bool button_pressed(uint pin) {
  232.     static absolute_time_t last[32];
  233.     absolute_time_t now = get_absolute_time();
  234.     if (!gpio_get(pin) &&
  235.         absolute_time_diff_us(last[pin], now) > DEBOUNCE_MS * 1000) {
  236.         last[pin] = now;
  237.         return true;
  238.     }
  239.     return false;
  240. }
  241.  
  242. // ---------- START 3-2-1 ----------
  243. const uint8_t digits[3][5][5] = {
  244.     { { 1, 1, 1, 1, 0 }, { 0, 0, 0, 1, 0 }, { 0, 1, 1, 1, 0 }, { 0, 0, 0, 1, 0 }, { 1, 1, 1, 1, 0 } },
  245.     { { 1, 1, 1, 1, 0 }, { 0, 0, 0, 1, 0 }, { 1, 1, 1, 1, 0 }, { 1, 0, 0, 0, 0 }, { 1, 1, 1, 1, 0 } },
  246.     { { 0, 0, 1, 0, 0 }, { 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0, 1, 1, 1, 0 } }
  247. };
  248.  
  249. // ---------- TEXT END ! ----------
  250. const uint8_t font_end[4][7][5] = {
  251.  
  252.     // E
  253. {
  254.     { 1, 1, 1, 1, 1 },
  255.     { 1, 0, 0, 0, 0 },
  256.     { 1, 1, 1, 1, 0 },
  257.     { 1, 0, 0, 0, 0 },
  258.     { 1, 1, 1, 1, 1 },
  259.     { 0, 0, 0, 0, 0 },
  260.     { 0, 0, 0, 0, 0 }
  261. },
  262.  
  263.     // N
  264. {
  265.     { 1, 0, 0, 0, 1 },
  266.     { 1, 1, 0, 0, 1 },
  267.     { 1, 0, 1, 0, 1 },
  268.     { 1, 0, 0, 1, 1 },
  269.     { 1, 0, 0, 0, 1 },
  270.     { 0, 0, 0, 0, 0 },
  271.     { 0, 0, 0, 0, 0 }
  272. },
  273.  
  274.     // D
  275. {
  276.     { 1, 1, 1, 1, 0 },
  277.     { 1, 0, 0, 0, 1 },
  278.     { 1, 0, 0, 0, 1 },
  279.     { 1, 0, 0, 0, 1 },
  280.     { 1, 1, 1, 1, 0 },
  281.     { 0, 0, 0, 0, 0 },
  282.     { 0, 0, 0, 0, 0 }
  283. },
  284.  
  285.     // !
  286. {
  287.     { 0, 1, 0, 0, 0 },
  288.     { 0, 1, 0, 0, 0 },
  289.     { 0, 1, 0, 0, 0 },
  290.     { 0, 0, 0, 0, 0 },
  291.     { 0, 1, 0, 0, 0 },
  292.     { 0, 0, 0, 0, 0 },
  293.     { 0, 0, 0, 0, 0 }
  294. }
  295. };
  296.  
  297. // ---------- ANIMACJE ----------
  298. void draw_letter_flash(PIO pio, uint sm, uint8_t letter[7][5], int flashes, int on_ms, int off_ms) {
  299.     for (int f = 0; f < flashes; f++) {
  300.         // włącz literę
  301.         clear_matrix();
  302.         for (int y = 0; y < MATRIX_HEIGHT; y++)
  303.             for (int x = 0; x < MATRIX_WIDTH; x++)
  304.                 if (is_border(x, y))
  305.                     led_buffer[xy_to_index(x, y)] = tetris_colors[(x + y) % 7 + 1];
  306.  
  307.         for (int y = 0; y < 7; y++) {
  308.             for (int x = 0; x < 5; x++) {
  309.                 if (letter[y][x]) {
  310.                     int px = x * 4 / 5 + 2;
  311.                     int py = y * 5 / 7 + 1;
  312.                     led_buffer[xy_to_index(px, py)] = 0xFFFFFF;
  313.                 }
  314.             }
  315.         }
  316.         show(pio, sm);
  317.         sleep_ms(on_ms);
  318.  
  319.         // wyłącz literę (tylko środek)
  320.         clear_matrix();
  321.         for (int y = 0; y < MATRIX_HEIGHT; y++)
  322.             for (int x = 0; x < MATRIX_WIDTH; x++)
  323.                 if (is_border(x, y))
  324.                     led_buffer[xy_to_index(x, y)] = tetris_colors[(x + y) % 7 + 1];
  325.  
  326.         show(pio, sm);
  327.         sleep_ms(off_ms);
  328.     }
  329. }
  330.  
  331. // Rysuje napis "END !" w centrum matrycy
  332. void draw_word_center(PIO pio, uint sm, int word_index) {
  333.     clear_matrix();
  334.  
  335.     for (int y = 0; y < MATRIX_HEIGHT; y++) {
  336.         for (int x = 0; x < MATRIX_WIDTH; x++) {
  337.  
  338.             if (is_border(x, y)) {
  339.                 int c = (x + y) % 7 + 1;
  340.                 led_buffer[xy_to_index(x, y)] =
  341.                     tetris_colors[c];
  342.             }
  343.         }
  344.     }
  345.  
  346.     // GAME / OVER (2x2 litery)
  347.     int base_x = 1;
  348.     int base_y = 1;
  349.  
  350.     for (int i = 0; i < 4; i++) {
  351.         for (int y = 0; y < 5; y++) {
  352.             for (int x = 0; x < 5; x++) {
  353.                 if (font_end[word_index * 4 + i][y][x]) {
  354.                     led_buffer[
  355.                         xy_to_index(base_x + (i % 2) * 3 + x / 2,
  356.                         base_y + (i / 2) * 3 + y / 2)
  357.         ] = 0xFFFFFF;
  358.                 }
  359.             }
  360.         }
  361.     }
  362.  
  363.     show(pio, sm);
  364. }
  365.  
  366. // Animacja startowa 3-2-1
  367. void start_animation(PIO pio, uint sm) {
  368.     for (int d = 0; d < 3; d++) {
  369.         clear_matrix();
  370.         for (int y = 0; y < 5; y++)
  371.             for (int x = 0; x < 5; x++)
  372.                 if (digits[d][y][x])
  373.                     led_buffer[xy_to_index(x + 1, y + 1)] = 0xFFFFFF;
  374.         show(pio, sm);
  375.         sleep_ms(600);
  376.         clear_matrix();
  377.         show(pio, sm);
  378.         sleep_ms(150);
  379.     }
  380. }
  381.  
  382. // Wygaszanie środka matrycy, pozostawiając obwód
  383. void fade_center_keep_border(PIO pio, uint sm) {
  384.     for (int step = 255; step >= 0; step -= 15) {
  385.  
  386.         for (int y = 0; y < MATRIX_HEIGHT; y++) {
  387.             for (int x = 0; x < MATRIX_WIDTH; x++) {
  388.  
  389.                 if (is_border(x, y)) {
  390.                     // obwód – losowy kolor
  391.                     int c = (x + y + step) % 7 + 1;
  392.                     led_buffer[xy_to_index(x, y)] =
  393.                         tetris_colors[c];
  394.                 }
  395.                 else {
  396.                     // środek – wygaszanie
  397.                     uint8_t v = step;
  398.                     led_buffer[xy_to_index(x, y)] =
  399.                         (v << 16) | (v << 8) | v;
  400.                 }
  401.             }
  402.         }
  403.  
  404.         show(pio, sm);
  405.         sleep_ms(60);
  406.     }
  407. }
  408. // Rysuje literę w centrum matrycy z obwodem
  409. void draw_letter_center(PIO pio, uint sm, uint8_t letter[7][5]) {
  410.     clear_matrix();
  411.  
  412.     // rysowanie border
  413.     for (int y = 0; y < MATRIX_HEIGHT; y++) {
  414.         for (int x = 0; x < MATRIX_WIDTH; x++) {
  415.             if (is_border(x, y)) {
  416.                 int c = (x + y) % 7 + 1;
  417.                 led_buffer[xy_to_index(x, y)] = tetris_colors[c];
  418.             }
  419.         }
  420.     }
  421.  
  422.     // rysowanie litery w centrum (skalowanie 5x7 → 4x5)
  423.     for (int y = 0; y < 7; y++) {
  424.         for (int x = 0; x < 5; x++) {
  425.             if (letter[y][x]) {
  426.                 int px = x * 4 / 5 + 2; // dopasowanie do środka 8x8
  427.                 int py = y * 5 / 7 + 1;
  428.                 led_buffer[xy_to_index(px, py)] = 0xFFFFFF;
  429.             }
  430.         }
  431.     }
  432.  
  433.     show(pio, sm);
  434. }
  435.  
  436. // Pętla animacji napisu "END ! z Flashem"
  437. void game_over_text_loop_flash(PIO pio, uint sm) {
  438.     for (int i = 0; i < 4; i++) {
  439.         // E, N, D, !
  440.         draw_letter_flash(pio, sm, font_end[i], 2, 300, 150);
  441.         // 2 razy flash, 300ms włączona, 150ms wyłączona
  442.     }
  443. }
  444.  
  445. // Pętla animacji napisu "END !" bez flasha
  446. void game_over_text_loop(PIO pio, uint sm) {
  447.     for (int i = 0; i < 4; i++) {
  448.         // E, N, D, !
  449.         draw_letter_center(pio, sm, font_end[i]);
  450.         sleep_ms(600);
  451.         clear_matrix();
  452.         show(pio, sm);
  453.         sleep_ms(150);
  454.     }
  455. }
  456.  
  457.  
  458. // ---------- GAME OVER – WĄŻ ----------
  459. void game_over_snake(PIO pio, uint sm) {
  460.     clear_matrix();
  461.  
  462.     int left = 0;
  463.     int right = MATRIX_WIDTH - 1;
  464.     int top = 0;
  465.     int bottom = MATRIX_HEIGHT - 1;
  466.  
  467.     int color_idx = 1;
  468.  
  469.     while (left <= right && top <= bottom) {
  470.  
  471.         // górny wiersz →
  472.         for (int x = left; x <= right; x++) {
  473.             led_buffer[xy_to_index(x, top)] = tetris_colors[color_idx];
  474.             show(pio, sm);
  475.             sleep_ms(35);
  476.             color_idx = (color_idx % 7) + 1;
  477.         }
  478.         top++;
  479.  
  480.         // prawa kolumna ↓
  481.         for (int y = top; y <= bottom; y++) {
  482.             led_buffer[xy_to_index(right, y)] = tetris_colors[color_idx];
  483.             show(pio, sm);
  484.             sleep_ms(35);
  485.             color_idx = (color_idx % 7) + 1;
  486.         }
  487.         right--;
  488.  
  489.         // dolny wiersz ←
  490.         if (top <= bottom) {
  491.             for (int x = right; x >= left; x--) {
  492.                 led_buffer[xy_to_index(x, bottom)] = tetris_colors[color_idx];
  493.                 show(pio, sm);
  494.                 sleep_ms(35);
  495.                 color_idx = (color_idx % 7) + 1;
  496.             }
  497.             bottom--;
  498.         }
  499.  
  500.         // lewa kolumna ↑
  501.         if (left <= right) {
  502.             for (int y = bottom; y >= top; y--) {
  503.                 led_buffer[xy_to_index(left, y)] = tetris_colors[color_idx];
  504.                 show(pio, sm);
  505.                 sleep_ms(35);
  506.                 color_idx = (color_idx % 7) + 1;
  507.             }
  508.             left++;
  509.         }
  510.     }
  511.  
  512.     // Miganie środka wszystkimi kolorami
  513.     for (int i = 0; i < 6; i++) {
  514.         for (int y = 0; y < MATRIX_HEIGHT; y++)
  515.             for (int x = 0; x < MATRIX_WIDTH; x++)
  516.                 led_buffer[xy_to_index(x, y)] =
  517.                     tetris_colors[(i + x + y) % 7 + 1];
  518.  
  519.         show(pio, sm);
  520.         sleep_ms(180);
  521.     }
  522.  
  523.     fade_center_keep_border(pio, sm);
  524.     game_over_text_loop_flash(pio, sm);
  525.     clear_matrix();
  526.     show(pio, sm);
  527. }
  528.  
  529.  
  530.  
  531. // rysowanie pojedyńczego klocka
  532. void draw_piece(uint8_t p[4][4], int px, int py, uint8_t color) {
  533.     clear_matrix();
  534.  
  535.     for (int y = 0; y < 4; y++)
  536.         for (int x = 0; x < 4; x++)
  537.             if (p[y][x] && py + y >= 0)
  538.                 led_buffer[xy_to_index(px + x, py + y)] =
  539.                     tetris_colors[color];
  540. }
  541.  
  542. // animowanie klocka
  543. void rotating_piece_animation(PIO pio, uint sm, int type) {
  544.     uint8_t piece[4][4];
  545.     uint8_t rotated[4][4];
  546.  
  547.     memcpy(piece, tetrominoes[type], sizeof(piece));
  548.  
  549.     int px = 2; // środek 8x8
  550.     int py = 2;
  551.     uint8_t color = type + 1;
  552.  
  553.     for (int r = 0; r < 4; r++) {
  554.         draw_piece(piece, px, py, color);
  555.         show(pio, sm);
  556.  
  557.         for (int i = 0; i < 6; i++) {
  558.             sleep_ms(60);
  559.  
  560.            
  561.            
  562.         }
  563.  
  564.         rotate(rotated, piece);
  565.         memcpy(piece, rotated, sizeof(piece));
  566.     }
  567. }
  568.  
  569. //Pętla animacji startowej (attract mode)
  570. void start_attract_mode(PIO pio, uint sm) {
  571.     while (true) {
  572.         int type = rand() % 7;
  573.         rotating_piece_animation(pio, sm, type);
  574.  
  575.         // SPRAWDZENIE STANU
  576.         if (any_button_held()) {
  577.             // czekamy aż użytkownik puści przycisk
  578.             while (any_button_held())
  579.                 sleep_ms(10);
  580.  
  581.             sleep_ms(150); // stabilizacja
  582.             return;
  583.         }
  584.  
  585.         clear_matrix();
  586.         show(pio, sm);
  587.         sleep_ms(120);
  588.     }
  589. }
  590.  
  591. // Sprawdza czy klocek zablokował się powyżej planszy
  592. bool piece_locked_above_board(int py) {
  593.     return py < 0;
  594. }
  595.  
  596. // Sprawdza czy plansza jest pełna
  597. bool board_full(void) {
  598.     for (int y = 0; y < MATRIX_HEIGHT; y++)
  599.         for (int x = 0; x < MATRIX_WIDTH; x++)
  600.             if (!board[y][x])
  601.                 return false;
  602.     return true;
  603. }
  604.  
  605. // Czeka na wciśnięcie dowolnego przycisku
  606. void wait_for_any_button(void) {
  607.     while (true) {
  608.         if (button_pressed(BTN_LEFT) ||
  609.             button_pressed(BTN_RIGHT) ||
  610.             button_pressed(BTN_DOWN) ||
  611.             button_pressed(BTN_ROTATE)) {
  612.             sleep_ms(200); // zabezpieczenie przed odbiciem
  613.             return;
  614.         }
  615.         sleep_ms(10);
  616.     }
  617. }
  618.  
  619. // ---------- MAIN ----------
  620.  
  621. int main() {
  622.     stdio_init_all();
  623.     sleep_ms(100);
  624.  
  625.     PIO pio = pio0;
  626.     uint sm = 0;
  627.     uint offset = pio_add_program(pio, &ws2812_program);
  628.     ws2812_program_init(pio, sm, offset, WS2812_PIN);
  629.  
  630.     gpio_init(BTN_LEFT); gpio_init(BTN_RIGHT);
  631.     gpio_init(BTN_DOWN); gpio_init(BTN_ROTATE);
  632.     gpio_set_dir(BTN_LEFT, GPIO_IN);
  633.     gpio_set_dir(BTN_RIGHT, GPIO_IN);
  634.     gpio_set_dir(BTN_DOWN, GPIO_IN);
  635.     gpio_set_dir(BTN_ROTATE, GPIO_IN);
  636.     gpio_pull_up(BTN_LEFT);
  637.     gpio_pull_up(BTN_RIGHT);
  638.     gpio_pull_up(BTN_DOWN);
  639.     gpio_pull_up(BTN_ROTATE);
  640.    
  641.     start_attract_mode(pio, sm); // animacja klocków
  642.     start_animation(pio, sm);    // 3-2-1 po przycisku
  643.     memset(board, 0, sizeof(board));
  644.  
  645.     while (true) {
  646.         int type = rand() % 7;
  647.         uint8_t piece[4][4];
  648.         memcpy(piece, tetrominoes[type], 16);
  649.  
  650.         int px = rand() % (MATRIX_WIDTH - 3);
  651.         int py = -4;
  652.         uint8_t color = type + 1;
  653.  
  654.         // Game Over – brak miejsca na nowy klocek
  655.         if (collision(piece, px, py + 1) || board_full()) {
  656.             game_over_snake(pio, sm);
  657.             wait_for_any_button();
  658.             memset(board, 0, sizeof(board));
  659.             start_animation(pio, sm);
  660.             continue;
  661.         }
  662.  
  663.         while (true) {
  664.  
  665.             // --- Sterowanie ---
  666.             if (button_autorepeat(BTN_LEFT, &btn_left_state) &&
  667.     !collision(piece, px - 1, py))
  668.                 px--;
  669.  
  670.             if (button_autorepeat(BTN_RIGHT, &btn_right_state) &&
  671.                 !collision(piece, px + 1, py))
  672.                 px++;
  673.             if (button_pressed(BTN_DOWN) && !collision(piece, px, py + 1))
  674.                 py++;
  675.  
  676.             if (button_pressed(BTN_ROTATE)) {
  677.                 uint8_t r[4][4];
  678.                 rotate(r, piece);
  679.                 if (!collision(r, px, py))
  680.                     memcpy(piece, r, 16);
  681.             }
  682.  
  683.             // --- Grawitacja ---
  684.             if (!collision(piece, px, py + 1)) {
  685.                 py++;
  686.             }
  687.             else {
  688.                 // Klocek się zablokował
  689.                 // GAME OVER – klocek nie zmieścił się w całości
  690.                 if (py < 0) {
  691.                     game_over_snake(pio, sm);
  692.                     wait_for_any_button();
  693.                     memset(board, 0, sizeof(board));
  694.                     start_attract_mode(pio, sm);
  695.                    
  696.                     wait_for_any_button();
  697.                     start_animation(pio, sm);
  698.                     break;
  699.                 }
  700.  
  701.                 merge_piece(piece, px, py, color);
  702.                 clear_lines(pio, sm);
  703.  
  704.                 // GAME OVER – plansza pełna
  705.                 if (board_full()) {
  706.                     game_over_snake(pio, sm);
  707.                     wait_for_any_button();
  708.                     memset(board, 0, sizeof(board));
  709.                     start_attract_mode(pio, sm);
  710.                     wait_for_any_button();
  711.                     start_animation(pio, sm);
  712.                 }
  713.                 break;
  714.             }
  715.  
  716.             // --- Rysowanie ---
  717.             draw_board();
  718.             for (int y = 0; y < 4; y++)
  719.                 for (int x = 0; x < 4; x++)
  720.                     if (piece[y][x] && py + y >= 0)
  721.                         led_buffer[xy_to_index(px + x, py + y)] =
  722.                             tetris_colors[color];
  723.  
  724.             show(pio, sm);
  725.             sleep_ms(200);
  726.         }
  727.     }
  728. }
  729.  
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
ODPOWIEDZ

Wróć do „Raspberry Pi Pico”