Guest User

Picoris

a guest
Jan 27th, 2021
2,066
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <string.h>
  2. #include <math.h>
  3. #include <vector>
  4. #include <cstdlib>
  5.  
  6. #include "pico_display.hpp"
  7. #include "pico/multicore.h"
  8.  
  9. using namespace pimoroni;
  10.  
  11. #define u8 uint8_t
  12. #define u16 uint16_t
  13. #define u32 uint32_t
  14. #define i8 int8_t
  15. #define i16 int16_t
  16. #define i32 int32_t
  17.  
  18. const u8 TETROMINOES[7][4][16] = {
  19.     { // LONG PIECE
  20.         {
  21.             0, 0, 0, 0,
  22.             1, 1, 1, 1,
  23.             0, 0, 0, 0,
  24.             0, 0, 0, 0
  25.         },
  26.         {
  27.             0, 0, 1, 0,
  28.             0, 0, 1, 0,
  29.             0, 0, 1, 0,
  30.             0, 0, 1, 0
  31.         },
  32.         {
  33.             0, 0, 0, 0,
  34.             0, 0, 0, 0,
  35.             1, 1, 1, 1,
  36.             0, 0, 0, 0
  37.         },
  38.         {
  39.             0, 1, 0, 0,
  40.             0, 1, 0, 0,
  41.             0, 1, 0, 0,
  42.             0, 1, 0, 0
  43.         }
  44.     },
  45.     { // BACKWARD L
  46.         {
  47.             1, 0, 0, 0,
  48.             1, 1, 1, 0,
  49.             0, 0, 0, 0,
  50.             0, 0, 0, 0
  51.         },
  52.         {
  53.             0, 1, 1, 0,
  54.             0, 1, 0, 0,
  55.             0, 1, 0, 0,
  56.             0, 0, 0, 0
  57.         },
  58.         {
  59.             0, 0, 0, 0,
  60.             1, 1, 1, 0,
  61.             0, 0, 1, 0,
  62.             0, 0, 0, 0
  63.         },
  64.         {
  65.             0, 1, 0, 0,
  66.             0, 1, 0, 0,
  67.             1, 1, 0, 0,
  68.             0, 0, 0, 0
  69.         }
  70.     },
  71.     { // L
  72.         {
  73.             0, 0, 1, 0,
  74.             1, 1, 1, 0,
  75.             0, 0, 0, 0,
  76.             0, 0, 0, 0
  77.         },
  78.         {
  79.             0, 1, 0, 0,
  80.             0, 1, 0, 0,
  81.             0, 1, 1, 0,
  82.             0, 0, 0, 0
  83.         },
  84.         {
  85.             0, 0, 0, 0,
  86.             1, 1, 1, 0,
  87.             1, 0, 0, 0,
  88.             0, 0, 0, 0
  89.         },
  90.         {
  91.             1, 1, 0, 0,
  92.             0, 1, 0, 0,
  93.             0, 1, 0, 0,
  94.             0, 0, 0, 0
  95.         }
  96.     },
  97.     { // SQUARE
  98.         {
  99.             0, 1, 1, 0,
  100.             0, 1, 1, 0,
  101.             0, 0, 0, 0,
  102.             0, 0, 0, 0
  103.         },
  104.         {
  105.             0, 1, 1, 0,
  106.             0, 1, 1, 0,
  107.             0, 0, 0, 0,
  108.             0, 0, 0, 0
  109.         },
  110.         {
  111.             0, 1, 1, 0,
  112.             0, 1, 1, 0,
  113.             0, 0, 0, 0,
  114.             0, 0, 0, 0
  115.         },
  116.         {
  117.             0, 1, 1, 0,
  118.             0, 1, 1, 0,
  119.             0, 0, 0, 0,
  120.             0, 0, 0, 0
  121.         }
  122.     },
  123.     { // S
  124.         {
  125.             0, 1, 1, 0,
  126.             1, 1, 0, 0,
  127.             0, 0, 0, 0,
  128.             0, 0, 0, 0
  129.         },
  130.         {
  131.             0, 1, 0, 0,
  132.             0, 1, 1, 0,
  133.             0, 0, 1, 0,
  134.             0, 0, 0, 0
  135.         },
  136.         {
  137.             0, 0, 0, 0,
  138.             0, 1, 1, 0,
  139.             1, 1, 0, 0,
  140.             0, 0, 0, 0
  141.         },
  142.         {
  143.             1, 0, 0, 0,
  144.             1, 1, 0, 0,
  145.             0, 1, 0, 0,
  146.             0, 0, 0, 0
  147.         }
  148.     },
  149.     { // T
  150.         {
  151.             0, 1, 0, 0,
  152.             1, 1, 1, 0,
  153.             0, 0, 0, 0,
  154.             0, 0, 0, 0
  155.         },
  156.         {
  157.             0, 1, 0, 0,
  158.             0, 1, 1, 0,
  159.             0, 1, 0, 0,
  160.             0, 0, 0, 0
  161.         },
  162.         {
  163.             0, 0, 0, 0,
  164.             1, 1, 1, 0,
  165.             0, 1, 0, 0,
  166.             0, 0, 0, 0
  167.         },
  168.         {
  169.             0, 1, 0, 0,
  170.             1, 1, 0, 0,
  171.             0, 1, 0, 0,
  172.             0, 0, 0, 0
  173.         }
  174.     },
  175.     { // BACKWARD S
  176.         {
  177.             1, 1, 0, 0,
  178.             0, 1, 1, 0,
  179.             0, 0, 0, 0,
  180.             0, 0, 0, 0
  181.         },
  182.         {
  183.             0, 0, 1, 0,
  184.             0, 1, 1, 0,
  185.             0, 1, 0, 0,
  186.             0, 0, 0, 0
  187.         },
  188.         {
  189.             0, 0, 0, 0,
  190.             1, 1, 0, 0,
  191.             0, 1, 1, 0,
  192.             0, 0, 0, 0
  193.         },
  194.         {
  195.             0, 1, 0, 0,
  196.             1, 1, 0, 0,
  197.             1, 0, 0, 0,
  198.             0, 0, 0, 0
  199.         }
  200.     }
  201. };
  202.  
  203. const u16 SCREEN_WIDTH = PicoDisplay::WIDTH / 2;
  204. const u16 SCREEN_HEIGHT = PicoDisplay::HEIGHT / 2;
  205.  
  206. uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT];
  207. PicoDisplay pico_display(buffer);
  208.  
  209. const u8 BUTTON_X = 0;
  210. const u8 BUTTON_Y = 1;
  211. const u8 BUTTON_A = 2;
  212. const u8 BUTTON_B = 3;
  213.  
  214. const u8 pico_button_map[] = {
  215.     pico_display.X,
  216.     pico_display.Y,
  217.     pico_display.A,
  218.     pico_display.B
  219. };
  220.  
  221. u8 buttons[4];
  222. u8 buttons_pressed[4];
  223. u8 buttons_released[4];
  224.  
  225. bool check_button(u8 button) {
  226.     return buttons[button];
  227. }
  228.  
  229. bool check_button_pressed(u8 button) {
  230.     return buttons_pressed[button];
  231. }
  232.  
  233. bool check_button_released(u8 button) {
  234.     return buttons_released[button];
  235. }
  236.  
  237. u16 color(u8 r, u8 g, u8 b) {
  238.     return pico_display.create_pen(r, g, b);
  239. }
  240.  
  241. void pixel(u16 x, u16 y, u16 color) {
  242.     x *= 2;
  243.     y *= 2;
  244.     pico_display.frame_buffer[x + y * 240] = color;
  245.     pico_display.frame_buffer[x + 1 + y * 240] = color;
  246.     y++;
  247.     pico_display.frame_buffer[x + y * 240] = color;
  248.     pico_display.frame_buffer[x + 1 + y * 240] = color;
  249. }
  250.  
  251. void rectangle(u16 x, u16 y, u16 width, u16 height, u16 color) {
  252.     for(u16 i = x; i < x + width; i++) {
  253.         for(u16 t = y; t < y + height; t++) {
  254.             pixel(i, t, color);
  255.         }
  256.     }
  257. }
  258.  
  259. const u16 background = color(64, 51, 83);
  260. const u16 field_background = color(36, 34, 52);
  261. const u16 block_colors[] = {
  262.     color(180, 32, 42),
  263.     color(250, 106, 10),
  264.     color(255, 213, 65),
  265.     color(89, 193, 53),
  266.     color(40, 92, 196),
  267.     color(188, 74, 155),
  268.     color(32, 214, 199)
  269. };
  270.  
  271. u8 piece_index = 0;
  272. u8 piece_angle = 0;
  273. u8 piece_x = 0;
  274. u8 piece_y = 0;
  275. u8 piece_dropping = false;
  276. u8 field[10][20];
  277.  
  278. inline void next_piece() {
  279.     piece_index = (piece_index + 1) % 7;
  280.     piece_angle = 0;
  281.     piece_x = 3;
  282.     piece_y = 0;
  283. }
  284.  
  285. inline void init() {
  286.     for(u8 i = 0; i < 10; ++i) {
  287.         for(u8 t = 0; t < 20; ++t) {
  288.             field[i][t] = 0;
  289.         }
  290.     }
  291.     next_piece();
  292. }
  293.  
  294. inline bool piece_position_allowed() {
  295.     const u8* piece = TETROMINOES[piece_index][piece_angle];
  296.     for(u8 i = 0; i < 4; ++i) {
  297.         for(u8 t = 0; t < 4; ++t) {
  298.             u8 block = piece[i + t * 4];
  299.             if(block) {
  300.                 u8 x = piece_x + i;
  301.                 u8 y = piece_y + t;
  302.                 if(x >= 10 || y >= 20 || field[x][y]) {
  303.                     return false;
  304.                 }
  305.             }
  306.         }
  307.     }
  308.     return true;
  309. }
  310.  
  311. inline void place_piece() {
  312.     piece_dropping = false;
  313.     const u8* piece = TETROMINOES[piece_index][piece_angle];
  314.     for(u8 i = 0; i < 4; ++i) {
  315.         for(u8 t = 0; t < 4; ++t) {
  316.             u8 block = piece[i + t * 4];
  317.             if(block) {
  318.                 u8 x = piece_x + i;
  319.                 u8 y = piece_y + t;
  320.                 field[x][y] = piece_index + 1;
  321.             }
  322.         }
  323.     }
  324.    
  325.     for(u8 t = 1; t < 20; ++t) {
  326.         bool line_filled = true;
  327.         for(u8 i = 0; i < 10; ++i) {
  328.             if(field[i][t] == 0) {
  329.                 line_filled = false;
  330.                 break;
  331.             }
  332.         }
  333.         if(line_filled) {
  334.             for(u8 j = t - 1; j > 0; --j) {
  335.                 for(u8 i = 0; i < 10; ++i) {
  336.                     field[i][j + 1] = field[i][j];
  337.                 }
  338.             }
  339.             for(u8 i = 0; i < 10; ++i) {
  340.                 field[i][0] = 0;
  341.             }
  342.             --t;
  343.         }
  344.     }
  345. }
  346.  
  347. inline void tick(bool update_board) {
  348.     pico_display.set_pen(64, 51, 83);
  349.     pico_display.clear();
  350.  
  351.     // Turn the piece
  352.     if(check_button_pressed(BUTTON_A)) {
  353.         piece_angle++;
  354.         if(!piece_position_allowed()) {
  355.             piece_angle--;
  356.         }
  357.         piece_angle = piece_angle % 4;
  358.     }
  359.  
  360.     if(check_button_pressed(BUTTON_B)) {
  361.         piece_dropping = true;
  362.     }
  363.     if(check_button(BUTTON_B) && piece_dropping) {
  364.         update_board = true;
  365.        
  366.     }
  367.  
  368.     if(check_button_pressed(BUTTON_Y)) {
  369.         piece_x++;
  370.         if(!piece_position_allowed()) {
  371.             piece_x--;
  372.         }
  373.     }
  374.     if(check_button_pressed(BUTTON_X)) {
  375.         piece_x--;
  376.         if(!piece_position_allowed()) {
  377.             piece_x++;
  378.         }
  379.     }
  380.  
  381.     if(update_board) {
  382.         piece_y++;
  383.         if(!piece_position_allowed()) {
  384.             piece_y--;
  385.             place_piece();
  386.             next_piece();
  387.         }
  388.     }
  389.  
  390.     u16 offset_x = 9;
  391.     u16 offset_y = 8;
  392.  
  393.     // Draw the field
  394.     rectangle(offset_x, offset_y, 100, 50, field_background);
  395.     for(u8 i = 0; i < 10; ++i) {
  396.         for(u8 t = 0; t < 20; ++t) {
  397.             u8 tile = field[i][t];
  398.             if(field[i][t] > 0) {
  399.                 rectangle(offset_x + t * 5, offset_y + i * 5, 5, 5, block_colors[tile - 1]);
  400.             }
  401.         }
  402.     }
  403.  
  404.     // Draw the active piece
  405.     const u8* piece = TETROMINOES[piece_index][piece_angle];
  406.     for(u8 i = 0; i < 4; ++i) {
  407.         for(u8 t = 0; t < 4; ++t) {
  408.             u8 block = piece[i + t * 4];
  409.             if(block) {
  410.                 u8 x = piece_x + i;
  411.                 u8 y = piece_y + t;
  412.                 if(x < 10 && y < 20) {
  413.                     rectangle(offset_x + (y) * 5, offset_y + (x) * 5, 5, 5, block_colors[piece_index]);
  414.                 }
  415.             }
  416.         }
  417.     }
  418. }
  419.  
  420. void input_init() {
  421.     for(u8 i = 0; i < 4; ++i) {
  422.         buttons[i] = false;
  423.         buttons_pressed[i] = false;
  424.         buttons_released[i] = false;
  425.     }
  426. }
  427.  
  428. const u8 button_gpio_map[] = { 12, 13, 14, 15 };
  429. #define EVENT_QUEUE_SIZE 128
  430. u16 event_queue[EVENT_QUEUE_SIZE];
  431. u16 event_queue_head = 0;
  432. u16 event_queue_tail = 0;
  433.  
  434.  
  435. bool event_queue_has_next() {
  436.     return event_queue_head != event_queue_tail;
  437. }
  438.  
  439. bool event_queue_full() {
  440.     return (event_queue_head + 1) % EVENT_QUEUE_SIZE == event_queue_tail;
  441. }
  442.  
  443. void event_queue_append(u16 value) {
  444.     if(!event_queue_full()) {
  445.         event_queue[event_queue_tail] = value;
  446.         event_queue_tail = (event_queue_tail + 1) % EVENT_QUEUE_SIZE;
  447.     }
  448. }
  449.  
  450. u16 event_queue_next() {
  451.     if(event_queue_has_next()) {
  452.         event_queue_tail = (event_queue_tail - 1) % EVENT_QUEUE_SIZE;
  453.         return event_queue[event_queue_tail];
  454.     }
  455.     return 0;
  456. }
  457.  
  458. void gpio_callback(unsigned int gpio, u32 events) {
  459.     if(events & (GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL)) {
  460.         u8 button;
  461.         if(gpio == 12) {
  462.             button = BUTTON_A;
  463.         } else if(gpio == 13) {
  464.             button = BUTTON_B;
  465.         } else if(gpio == 14) {
  466.             button = BUTTON_X;
  467.         } else if(gpio == 15) {
  468.             button = BUTTON_Y;
  469.         }
  470.         u8 pressed = GPIO_IRQ_EDGE_RISE & events;
  471.  
  472.         event_queue_append(button + pressed * 4);
  473.     }
  474. }
  475.  
  476. void input_start_frame() {
  477.     for(u8 i = 0; i < 4; ++i) {
  478.         buttons_pressed[i] = false;
  479.         buttons_released[i] = false;
  480.     }
  481.  
  482.     while(event_queue_has_next()) {
  483.         u32 event = event_queue_next();
  484.         u8 button = event % 4;
  485.         u8 pressed = event < 4;
  486.  
  487.         buttons[button] = pressed;
  488.         if(pressed) {
  489.             buttons_pressed[button] = true;
  490.         } else {
  491.             buttons_released[button] = true;
  492.         }
  493.     }
  494. }
  495.  
  496. int main() {
  497.     pico_display.init();
  498.     pico_display.set_backlight(255);
  499.  
  500.     gpio_set_irq_enabled_with_callback(12, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
  501.     gpio_set_irq_enabled_with_callback(13, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
  502.     gpio_set_irq_enabled_with_callback(14, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
  503.     gpio_set_irq_enabled_with_callback(15, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
  504.  
  505.     u8 tick_counter = 0;
  506.     u8 tick_interval = 30;
  507.  
  508.     init();
  509.     input_init();
  510.  
  511.     while(true) {
  512.         input_start_frame();
  513.         tick_counter++;
  514.         if(tick_counter > tick_interval) {
  515.             tick(true);
  516.             tick_counter = 0;
  517.         } else {
  518.             tick(false);
  519.         }
  520.         pico_display.update();
  521.     }
  522.  
  523.     return 0;
  524. }
  525.  
RAW Paste Data