فهرست منبع

navigation added
added clipping for cards to avoid overdraw
added draw_box to renderbuffer
updated janky main image

Tibor Tálosi 2 سال پیش
والد
کامیت
aa62580529
14فایلهای تغییر یافته به همراه291 افزوده شده و 192 حذف شده
  1. 24 18
      Deck.cpp
  2. 2 2
      Deck.h
  3. 83 23
      Game.cpp
  4. 5 1
      Game.h
  5. 27 17
      TableauColumn.cpp
  6. 4 0
      TableauColumn.h
  7. 71 71
      assets.h
  8. BIN
      assets/main_image.png
  9. 9 18
      solitaire.cpp
  10. 21 26
      utils/Card.cpp
  11. 2 2
      utils/Card.h
  12. 8 0
      utils/List.h
  13. 32 12
      utils/RenderBuffer.cpp
  14. 3 2
      utils/RenderBuffer.h

+ 24 - 18
Deck.cpp

@@ -10,11 +10,13 @@ void Deck::Generate() {
     waste_pile.empty();
     waste_pile.empty();
     stock_pile.empty();
     stock_pile.empty();
     //generate and shuffle deck
     //generate and shuffle deck
-    uint8_t cards[52];
-    for (int i = 0; i < 52; i++) cards[i] = i;
+    int cards_count = 52 * deck_count;
+    uint8_t cards[cards_count];
+    for (int i = 0; i < cards_count; i++) cards[i] = i % 52;
     srand(DWT->CYCCNT);
     srand(DWT->CYCCNT);
-    for (int i = 0; i < 52; i++) {
-        int r = i + (rand() % (52 - i));
+
+    for (int i = 0; i < cards_count; i++) {
+        int r = i + (rand() % (cards_count - i));
         uint8_t card = cards[i];
         uint8_t card = cards[i];
         cards[i] = cards[r];
         cards[i] = cards[r];
         cards[r] = card;
         cards[r] = card;
@@ -31,13 +33,12 @@ void Deck::Generate() {
 void Deck::Cycle() {
 void Deck::Cycle() {
     if (stock_pile.count > 0) {
     if (stock_pile.count > 0) {
         auto *c = stock_pile.pop();
         auto *c = stock_pile.pop();
-        c->exposed= true;
+        c->exposed = true;
         waste_pile.add(c);
         waste_pile.add(c);
-    }
-    else {
+    } else {
         while (waste_pile.count > 0) {
         while (waste_pile.count > 0) {
             auto *c = waste_pile.pop();
             auto *c = waste_pile.pop();
-            c->exposed= false;
+            c->exposed = false;
             stock_pile.add(c);
             stock_pile.add(c);
         }
         }
     }
     }
@@ -55,22 +56,27 @@ Card *Deck::Extract() {
     return stock_pile.pop();
     return stock_pile.pop();
 }
 }
 
 
-void Deck::Render(RenderBuffer *buffer) {
-    if (stock_pile.count == 0)
+void Deck::Render(RenderBuffer *buffer, bool stockpileSelect, bool wasteSelect) {
+    if (stock_pile.count == 0) {
         Card::RenderEmptyCard(1, 1, buffer);
         Card::RenderEmptyCard(1, 1, buffer);
-    else {
-        if(stock_pile.count>1) {
+        if (stockpileSelect) {
+            buffer->draw_rbox(2, 2, 17, 23, Flip);
+        }
+    } else {
+        if (stock_pile.count > 1) {
             buffer->draw_rbox_frame(1, 1, 17, 23, Black);
             buffer->draw_rbox_frame(1, 1, 17, 23, Black);
-            stock_pile.last()->Render(0, 0, false, buffer);
-        }else{
-            stock_pile.last()->Render(1, 1, false, buffer);
+            stock_pile.last()->Render(0, 0, stockpileSelect, buffer, 22);
+        } else {
+            stock_pile.last()->Render(1, 1, stockpileSelect, buffer, 22);
         }
         }
     }
     }
 
 
     if (waste_pile.count == 0) {
     if (waste_pile.count == 0) {
-        FURI_LOG_D("DECK", "Rendering empty card");
         Card::RenderEmptyCard(19, 1, buffer);
         Card::RenderEmptyCard(19, 1, buffer);
+        if (wasteSelect) {
+            buffer->draw_rbox(20, 2, 35, 23, Flip);
+        }
+    } else {
+        waste_pile.last()->Render(19, 1, wasteSelect, buffer, 22);
     }
     }
-    else
-        waste_pile.last()->Render(19, 1, false, buffer);
 }
 }

+ 2 - 2
Deck.h

@@ -10,9 +10,9 @@ class Deck {
 public:
 public:
     explicit Deck(uint8_t count);
     explicit Deck(uint8_t count);
     void Generate();
     void Generate();
-    void Render(RenderBuffer *buffer);
+    void Render(RenderBuffer *buffer, bool stockpileSelect, bool wasteSelect);
     void Cycle();
     void Cycle();
     Card* GetLastWaste();
     Card* GetLastWaste();
-    Card* Extract();
     void AddToWaste(Card* c);
     void AddToWaste(Card* c);
+    Card* Extract();
 };
 };

+ 83 - 23
Game.cpp

@@ -1,39 +1,51 @@
 #include "Game.h"
 #include "Game.h"
+#include "assets.h"
+
+static Sprite logo = Sprite(sprite_logo, BlackOnly);
+static Sprite main_image = Sprite(sprite_main_image, BlackOnly);
+static Sprite start = Sprite(sprite_start, BlackOnly);
 
 
 Game::~Game() {
 Game::~Game() {
     delete deck;
     delete deck;
+    for (int i = 0; i < 4; i++)
+        delete piles[i];
+    delete buffer;
 }
 }
 
 
 void Game::Render(Canvas *const canvas) {
 void Game::Render(Canvas *const canvas) {
     if (!buffer) return;
     if (!buffer) return;
     if (had_change) {
     if (had_change) {
-        deck->Render(buffer);
-        for (int i = 0; i < 7; i++) {
-            FURI_LOG_D("Game", "%i", i);
-            tableau[i].Render(i * 18 + 1, 25, false, 0, buffer);
-        }
-        for (int i = 0; i < 4; i++) {
-            if (piles[i])
-                piles[i]->Render(i * 18 + 55, 1, false, buffer);
-            else
-                Card::RenderEmptyCard(i * 18 + 55, 1, buffer);
-        }
+        if (state == GameStateStart) {
+            buffer->clear();
+            buffer->draw(&logo, (Vector) {60, 30}, 0);
+            buffer->draw(&main_image, (Vector) {110, 25}, 0);
+            buffer->draw(&start, (Vector) {64, 55}, 0);
 
 
+        } else if (state == GameStatePlay) {
+            buffer->clear();
+            if (deck)
+                deck->Render(buffer, current_row == 0 && current_column == 0, current_row == 0 && current_column == 1);
+            for (int i = 0; i < 7; i++) {
+                bool selected = current_row == 1 && current_column == i;
+                tableau[i].Render(i * 18 + 1, 25, selected, selected ? column_selection : 0, buffer);
+            }
+            for (int i = 0; i < 4; i++) {
+                bool pileSelected = current_row == 0 && (current_column - 3) == i;
+                if (piles[i]) {
+                    piles[i]->Render(i * 18 + 55, 1, pileSelected, buffer, 22);
+                } else {
+                    Card::RenderEmptyCard(i * 18 + 55, 1, buffer);
+                    if (pileSelected) {
+                        buffer->draw_rbox(i * 18 + 56, 2, i * 18 + 71, 23, Flip);
+                    }
+                }
+            }
+        }
     }
     }
     had_change = false;
     had_change = false;
     buffer->render(canvas);
     buffer->render(canvas);
 }
 }
 
 
-void Game::Press(InputKey key) {
-    if (key == InputKeyOk && state == GameStateStart) {
-        Reset();
-        NewRound();
-        return;
-    }
-    had_change = true;
-
-}
-
 Game::Game() {
 Game::Game() {
     deck = new Deck(1);
     deck = new Deck(1);
     buffer = new RenderBuffer(128, 64);
     buffer = new RenderBuffer(128, 64);
@@ -52,8 +64,6 @@ void Game::Reset() {
     column_selection = -1;
     column_selection = -1;
 
 
     deck->Generate();
     deck->Generate();
-    deck->Cycle();
-
     //Reset foundations
     //Reset foundations
     for (int i = 0; i < 4; i++) {
     for (int i = 0; i < 4; i++) {
         if (piles[i]) delete piles[i];
         if (piles[i]) delete piles[i];
@@ -78,3 +88,53 @@ void Game::LongPress(InputKey key) {
 void Game::Update(NotificationApp *app) {
 void Game::Update(NotificationApp *app) {
     UNUSED(app);
     UNUSED(app);
 }
 }
+
+void Game::Press(InputKey key) {
+    if (key == InputKeyOk && state == GameStateStart) {
+        Reset();
+        NewRound();
+        had_change = true;
+        return;
+    }
+
+    if (key == InputKeyBack && state == GameStatePlay) {
+        state = GameStateStart;
+        had_change = true;
+        return;
+    }
+
+    if(key == InputKeyOk && current_column == 0 && current_row == 0){
+        deck->Cycle();
+        had_change = true;
+    }
+
+    if (key == InputKeyLeft && current_column > 0) {
+        current_column--;
+        had_change = true;
+    } else if (key == InputKeyRight && current_column < 6) {
+        current_column++;
+        if (current_row == 0 && current_column == 2) current_column++;
+        had_change = true;
+    }
+
+    if (key == InputKeyUp && current_row == 1) {
+        uint8_t count = tableau[current_column].Count() - 1;
+        uint8_t first_non_flipped = tableau[current_column].FirstNonFlipped();
+        if (count > first_non_flipped && (column_selection + 1) > count) {
+            column_selection++;
+        } else
+            current_row--;
+
+        had_change = true;
+    } else if (key == InputKeyDown && current_row == 0) {
+        current_row++;
+        column_selection = 0;
+        had_change = true;
+    }
+
+    //disable empty space selection
+    if (current_row == 0 && current_column == 2) {
+        current_column--;
+        had_change = true;
+    }
+}

+ 5 - 1
Game.h

@@ -19,11 +19,15 @@ class Game {
     Card *piles[4];
     Card *piles[4];
     TableauColumn tableau[7];
     TableauColumn tableau[7];
 
 
-    List<Card> hand;
+    TableauColumn hand;
 
 
     PlayState state = GameStateStart;
     PlayState state = GameStateStart;
     uint8_t current_row;
     uint8_t current_row;
     uint8_t current_column;
     uint8_t current_column;
+
+    uint8_t picked_from_row;
+    uint8_t picked_from_column;
+
     int8_t column_selection;
     int8_t column_selection;
     RenderBuffer *buffer;
     RenderBuffer *buffer;
     uint32_t round_start;
     uint32_t round_start;

+ 27 - 17
TableauColumn.cpp

@@ -19,7 +19,6 @@ void TableauColumn::AddRange(List<Card> *hand) {
 
 
 void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selection_from_end, RenderBuffer *buffer) {
 void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selection_from_end, RenderBuffer *buffer) {
     // If the hand is empty
     // If the hand is empty
-    FURI_LOG_D("Tableau", "%i %i, count %li", x, y, cards->count);
     if (cards->count == 0) {
     if (cards->count == 0) {
         Card::RenderEmptyCard(x, y, buffer);
         Card::RenderEmptyCard(x, y, buffer);
         if (selected)
         if (selected)
@@ -27,6 +26,7 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
         return;
         return;
     }
     }
     uint8_t selection = cards->count - selection_from_end;
     uint8_t selection = cards->count - selection_from_end;
+    if (selected) selection--;
 
 
     uint8_t loop_end = cards->count;
     uint8_t loop_end = cards->count;
     uint8_t loop_start = max(loop_end - 4, 0);
     uint8_t loop_start = max(loop_end - 4, 0);
@@ -38,34 +38,34 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
     if (first_non_flipped <= loop_start && selection != first_non_flipped) {
     if (first_non_flipped <= loop_start && selection != first_non_flipped) {
         // Draw a card back if it is not the first card
         // Draw a card back if it is not the first card
         if (first_non_flipped > 0) {
         if (first_non_flipped > 0) {
-            Card::RenderBack(x,y+position, selection == first_non_flipped, buffer);
+            Card::RenderBack(x, y + position, selection == first_non_flipped, buffer, 4);
             // Increment loop start index and position
             // Increment loop start index and position
             position += 4;
             position += 4;
             loop_start++;
             loop_start++;
-            had_top=true;
+            had_top = true;
         }
         }
         // Draw the front side of the first non-flipped card
         // Draw the front side of the first non-flipped card
-        (*cards)[first_non_flipped]->Render(x, y + position, selection == first_non_flipped, buffer);
+        (*cards)[first_non_flipped]->Render(x, y + position, selection == first_non_flipped, buffer, cards->count == 1 ? 22 : 8);
         position += 8;
         position += 8;
         loop_start++; // Increment loop start index
         loop_start++; // Increment loop start index
     }
     }
 
 
     // Draw the selected card with adjusted visibility
     // Draw the selected card with adjusted visibility
     if (loop_start > selection) {
     if (loop_start > selection) {
-        if(!had_top && first_non_flipped>0){
-            Card::RenderBack(x,y+position, selection == first_non_flipped, buffer);
-            position+=2;
+        if (!had_top && first_non_flipped > 0) {
+            Card::RenderBack(x, y + position, selection == first_non_flipped, buffer,4);
+            position += 2;
             loop_start++;
             loop_start++;
         }
         }
         // Draw the front side of the selected card
         // Draw the front side of the selected card
-        (*cards)[selection]->Render(x, y + position, true, buffer);
+        (*cards)[selection]->Render(x, y + position, true, buffer, 8);
         position += 8;
         position += 8;
         loop_start++; // Increment loop start index
         loop_start++; // Increment loop start index
     }
     }
 
 
     //Draw the rest
     //Draw the rest
     for (uint8_t i = loop_start; i < loop_end; i++, position += 4) {
     for (uint8_t i = loop_start; i < loop_end; i++, position += 4) {
-        (*cards)[i]->Render(x, y + position, i == selection, buffer);
+        (*cards)[i]->Render(x, y + position, i == selection, buffer, (i+1)==loop_end ? 22 : 4);
 
 
         if (i == selection || i == first_non_flipped) position += 4;
         if (i == selection || i == first_non_flipped) position += 4;
     }
     }
@@ -74,14 +74,6 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
 int8_t TableauColumn::FirstNonFlipped() {
 int8_t TableauColumn::FirstNonFlipped() {
     int8_t index = -1;
     int8_t index = -1;
     if (cards->count > 0) {
     if (cards->count > 0) {
-/*        ListItem<Card> *c = cards->start;
-        while (c){
-            index++;
-            if (c->data->exposed) {
-                break;
-            }
-            c=c->next;
-        }*/
         for (auto *card: *cards) {
         for (auto *card: *cards) {
             index++;
             index++;
             if (card && card->exposed) {
             if (card && card->exposed) {
@@ -99,3 +91,21 @@ TableauColumn::TableauColumn() {
 TableauColumn::~TableauColumn() {
 TableauColumn::~TableauColumn() {
     delete cards;
     delete cards;
 }
 }
+
+void TableauColumn::AddTo(TableauColumn *other) {
+    for (auto *item: *(other->cards)) {
+        cards->add(item);
+    }
+}
+
+Card *TableauColumn::TopCard() {
+    return (*cards)[0];
+}
+
+uint8_t TableauColumn::Count() {
+    return cards->count;
+}
+
+List<Card>* TableauColumn::ExtractEnd(uint8_t count) {
+    return cards->splice(cards->count - count, count);
+}

+ 4 - 0
TableauColumn.h

@@ -13,7 +13,11 @@ public:
     void Reset();
     void Reset();
     void AddCard(Card *c);
     void AddCard(Card *c);
     void AddRange(List<Card> *hand);
     void AddRange(List<Card> *hand);
+    void AddTo(TableauColumn *other);
+    List<Card>* ExtractEnd(uint8_t count);
     void Render(uint8_t x, uint8_t y, bool selected, uint8_t selection, RenderBuffer *buffer);
     void Render(uint8_t x, uint8_t y, bool selected, uint8_t selection, RenderBuffer *buffer);
+    Card* TopCard();
 
 
     int8_t FirstNonFlipped();
     int8_t FirstNonFlipped();
+    uint8_t Count();
 };
 };

+ 71 - 71
assets.h

@@ -7,7 +7,7 @@
 ████████████   
 ████████████   
          ███   
          ███   
 */
 */
-const SpriteData *sprite_4 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_4 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0xc, 0xa, 0x9, 0x1f, 0x0
 		0xc, 0xa, 0x9, 0x1f, 0x0
 }};
 }};
 /*
 /*
@@ -17,7 +17,7 @@ const SpriteData *sprite_4 = new SpriteData {.width=5, .height=5, .data=new uint
    ███         
    ███         
    ███         
    ███         
 */
 */
-const SpriteData *sprite_7 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_7 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1, 0x19, 0x5, 0x3, 0x0
 		0x1, 0x19, 0x5, 0x3, 0x0
 }};
 }};
 /*
 /*
@@ -29,7 +29,7 @@ const SpriteData *sprite_7 = new SpriteData {.width=5, .height=5, .data=new uint
       ███   ███      
       ███   ███      
          ███         
          ███         
 */
 */
-const SpriteData *sprite_hearths = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_hearths = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0xe, 0x11, 0x22, 0x44, 0x22, 0x11, 0xe
 		0xe, 0x11, 0x22, 0x44, 0x22, 0x11, 0xe
 }};
 }};
 /*
 /*
@@ -39,7 +39,7 @@ const SpriteData *sprite_hearths = new SpriteData {.width=7, .height=7, .data=ne
 ███      ███   
 ███      ███   
 ███      ███   
 ███      ███   
 */
 */
-const SpriteData *sprite_A = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_A = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1e, 0x5, 0x5, 0x1e, 0x0
 		0x1e, 0x5, 0x5, 0x1e, 0x0
 }};
 }};
 /*
 /*
@@ -51,7 +51,7 @@ const SpriteData *sprite_A = new SpriteData {.width=5, .height=5, .data=new uint
       ███   ███   ███
       ███   ███   ███
    ███   ███   ███   
    ███   ███   ███   
 */
 */
-const SpriteData *sprite_pattern_small = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_pattern_small = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x0, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x2a
 		0x0, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x2a
 }};
 }};
 /*
 /*
@@ -77,64 +77,64 @@ const SpriteData *sprite_pattern_small = new SpriteData {.width=7, .height=7, .d
       ███            ███   ███      ███      
       ███            ███   ███      ███      
       ███         ███      ███   ███         
       ███         ███      ███   ███         
 */
 */
-const SpriteData *sprite_pattern_big = new SpriteData {.width=15, .height=21, .data=new uint8_t[45] {
+const SpriteData sprite_pattern_big = (SpriteData) {.width=15, .height=21, .data=(uint8_t[]) {
 		0x0, 0x1e, 0x8c, 0x4c, 0x9e, 0x1e, 0x1f, 0x9e, 0xcc, 0x80, 0x88, 0x14, 0x8, 0x80, 0x0, 
 		0x0, 0x1e, 0x8c, 0x4c, 0x9e, 0x1e, 0x1f, 0x9e, 0xcc, 0x80, 0x88, 0x14, 0x8, 0x80, 0x0, 
 		0x0, 0xe0, 0xc0, 0xc1, 0xe0, 0xe0, 0xf3, 0xe7, 0xc7, 0x7, 0x27, 0x53, 0x23, 0x87, 0x0, 
 		0x0, 0xe0, 0xc0, 0xc1, 0xe0, 0xe0, 0xf3, 0xe7, 0xc7, 0x7, 0x27, 0x53, 0x23, 0x87, 0x0, 
 		0x0, 0x1, 0x18, 0x4, 0x1, 0x1, 0x11, 0xd, 0x0, 0x18, 0x0, 0x10, 0xf, 0x0, 0x0
 		0x0, 0x1, 0x18, 0x4, 0x1, 0x1, 0x11, 0xd, 0x0, 0x18, 0x0, 0x10, 0xf, 0x0, 0x0
 }};
 }};
 /*
 /*
-                                                   █████████████████████████████████████████████   
-                                                ███                                             ███
-                                             █████████████████████████████████████████████      ███
-                                          ███                                             ███   ███
-                                       █████████████████████████████████████████████      ███   ███
-                                    ███                                             ███   ███   ███
-                                    █████████████████████████████████████████████   ███   ███   ███
-                                 ███                                             ██████   ███   ███
-                                 █████████████████████████████████████████████   ██████   ███   ███
-                              ███                                             █████████   ███   ███
-                              ███   ███      ███               ███            █████████   ███   ███
-                              █████████████████████████████████████████████   █████████   ███   ███
-   █████████████████████████████████████████████                           ████████████   ███   ███
-███                                             ███         ███            ████████████   ███   ███
-███   ███      ███               ███            ███████████████████████████   █████████   ███   ███
-███   ███   ███   ███         █████████         ███                        ████████████   ███   ███
-███   ███   ███   ███      ███████████████      ███         ███            ████████████   ███   ███
-███   ███   ███   ███   █████████████████████   ████████████████████████   ████████████   ███   ███
-███   ███   ███   ███      ███████████████      ██████                  ███████████████   ███   ███
-███   ███      ███            █████████         ████████████            ███████████████   ███   ███
-███                              ███            ██████      ████████████   ████████████   ███   ███
-███                                             ██████      ███         ███████████████   ██████   
-███                                             ██████      ██████      ███████████████   ███      
-███                                             ██████      ███   ███   ██████████████████         
-███                                             █████████   ███   ███   ███████████████            
-███            ███                              ██████      ███   ███   ████████████               
-███         █████████            ███      ███   ██████      ███   ███   ████████████               
-███      ███████████████      ███   ███   ███   ██████      ███   ███   █████████                  
-███   █████████████████████   ███   ███   ███   ██████      ███   ███   █████████                  
-███      ███████████████      ███   ███   ███   ██████      ███   ███   ██████                     
-███         █████████         ███   ███   ███   ██████      ███   ███   ██████                     
-███            ███               ███      ███   ██████      ███   ███   ██████                     
-███                                             ██████      ███   ███   ██████                     
-   █████████████████████████████████████████████   ██████   ███   ███   ██████                     
-   ███         █████████         ███   ███   ███   ██████   ███   ███   ██████                     
-   ███            ███               ███      ███   ██████   ███   ███   ███                        
-   ███                                             ██████   ███   ███   ███                        
-      █████████████████████████████████████████████   ███   ███   ███   ███                        
-            ███            ███               ███      ███   ███   ███   ███                        
-            ███                                             ███   ███   ███                        
-               █████████████████████████████████████████████      ███   ███                        
+                                          █████████████████████████████████████████████            
+                                       ███                                             ███         
+                                       █████████████████████████████████████████████   ███         
+                                    ███                                             ██████         
+                                    █████████████████████████████████████████████   ██████         
+                                 ███                                             █████████         
+                                 ███   ███      ███               ███            █████████         
+                                 ███   ███   ███   ███         █████████         █████████         
+                                 █████████████████████████████████████████████   █████████         
+                              ███                                             ████████████         
+                              ███   ███      ███               ███            ████████████         
+                              ███   ███   ███   ███         █████████         ████████████         
+            ███████████████████████████████████████████████████████████████   ████████████         
+         ███                                             ███               ███████████████         
+         ███   ███      ███               ███            ██████            ███████████████         
+         ███   ███   ███   ███         █████████         █████████         ███████████████         
+         ███   ███   ███   ███      ███████████████      ███████████████   ███████████████         
+         ███   ███   ███   ███   █████████████████████   ██████         ██████████████████         
+         ███   ███   ███   ███      ███████████████      █████████      ██████████████████         
+         ███   ███      ███            █████████         █████████      ██████████████████         
+         ███                              ███            █████████      ██████████████████         
+         ███                                             ████████████   ███████████████            
+         ███                                             ████████████   ███████████████            
+         ███                                             ███████████████████████████               
+         ███                                             ███████████████████████████               
+         ███            ███                              ████████████████████████                  
+         ███         █████████            ███      ███   ████████████████████████                  
+         ███      ███████████████      ███   ███   ███   ████████████████████████                  
+         ███   █████████████████████   ███   ███   ███   ████████████████████████                  
+         ███      ███████████████      ███   ███   ███   █████████████████████                     
+         ███         █████████         ███   ███   ███   █████████████████████                     
+         ███            ███               ███      ███   █████████████████████                     
+         ███                                             █████████████████████                     
+            █████████████████████████████████████████████   ███████████████                        
+            ███                                             ███████████████                        
+               █████████████████████████████████████████████   ████████████                        
+               ███            ███               ███      ███   ████████████                        
+               ███                                             █████████                           
+                  █████████████████████████████████████████████   ██████                           
                   ███            ███               ███      ███   ██████                           
                   ███            ███               ███      ███   ██████                           
-                  ███                                             ███                              
-                     █████████████████████████████████████████████                                 
+                  ███                                             ██████                           
+                     █████████████████████████████████████████████   ███                           
+                     ███                                             ███                           
+                        █████████████████████████████████████████████                              
 */
 */
-const SpriteData *sprite_main_image = new SpriteData {.width=33, .height=44, .data=new uint8_t[198] {
-		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x60, 0x50, 0x58, 0x54, 0x56, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x95, 0xe5, 0x5, 0xf9, 0x1, 0xfe, 
-		0xe0, 0x10, 0xd0, 0x10, 0x90, 0x50, 0x90, 0x10, 0x10, 0x10, 0x9e, 0xd9, 0x9d, 0x19, 0x19, 0x1d, 0xe9, 0x49, 0x49, 0x49, 0x69, 0x4d, 0x49, 0x49, 0x49, 0xb1, 0xfe, 0xff, 0xff, 0x0, 0xff, 0x0, 0xff, 
-		0xff, 0x0, 0xf, 0x0, 0x7, 0x8, 0x7, 0x0, 0x2, 0x7, 0xf, 0x1f, 0xf, 0x7, 0x2, 0x0, 0xff, 0xfe, 0xa, 0xa, 0xf3, 0x52, 0x92, 0x12, 0xec, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0x20, 0x1f, 
-		0xff, 0x0, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x0, 0x78, 0x84, 0x78, 0x0, 0xfc, 0x0, 0xff, 0xff, 0x1, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x1f, 0x7, 0x1, 0x0, 0x0, 0x0, 0x0, 
-		0x1, 0x1e, 0x22, 0x22, 0xe2, 0x26, 0x2e, 0x26, 0x22, 0x62, 0x22, 0x26, 0x2a, 0x26, 0x22, 0x6e, 0x21, 0x1f, 0x7e, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
-		0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x7, 0x9, 0x9, 0x9, 0x9, 0xb, 0x9, 0x9, 0x9, 0x9, 0x9, 0xb, 0x9, 0x9, 0xa, 0x8, 0x7, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+const SpriteData sprite_main_image = (SpriteData) {.width=33, .height=44, .data=(uint8_t[]) {
+		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x18, 0xd6, 0x15, 0x95, 0x55, 0x95, 0x15, 0x15, 0x15, 0x95, 0xd5, 0x95, 0x15, 0x15, 0x15, 0xe5, 0xf9, 0xfe, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0xe0, 0x10, 0xd0, 0x10, 0x90, 0x50, 0x90, 0x1e, 0x11, 0x1d, 0x91, 0xd9, 0x95, 0x19, 0x11, 0x11, 0xf1, 0xd9, 0x9d, 0x19, 0x11, 0x11, 0xe1, 0xfe, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0xff, 0x0, 0xf, 0x0, 0x7, 0x8, 0x7, 0x0, 0x2, 0x7, 0xf, 0x1f, 0xf, 0x7, 0x2, 0x0, 0xff, 0xff, 0xfd, 0xe1, 0x81, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0xff, 0x0, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x0, 0x78, 0x84, 0x78, 0x0, 0xfc, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0x1, 0x6, 0x3a, 0xca, 0x4a, 0x4a, 0x4a, 0x5a, 0xca, 0x4a, 0x4a, 0x4a, 0x4a, 0x5a, 0xca, 0x4a, 0x59, 0xc7, 0x3f, 0xff, 0xff, 0x1f, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x9, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
 }};
 }};
 /*
 /*
    ██████      
    ██████      
@@ -143,7 +143,7 @@ const SpriteData *sprite_main_image = new SpriteData {.width=33, .height=44, .da
 ███   ███      
 ███   ███      
    ███   ███   
    ███   ███   
 */
 */
-const SpriteData *sprite_Q = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_Q = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0xe, 0x11, 0x9, 0x16, 0x0
 		0xe, 0x11, 0x9, 0x16, 0x0
 }};
 }};
 /*
 /*
@@ -153,7 +153,7 @@ const SpriteData *sprite_Q = new SpriteData {.width=5, .height=5, .data=new uint
    ███         
    ███         
 ████████████   
 ████████████   
 */
 */
-const SpriteData *sprite_2 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_2 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x12, 0x19, 0x15, 0x12, 0x0
 		0x12, 0x19, 0x15, 0x12, 0x0
 }};
 }};
 /*
 /*
@@ -163,7 +163,7 @@ const SpriteData *sprite_2 = new SpriteData {.width=5, .height=5, .data=new uint
          ███   
          ███   
 █████████      
 █████████      
 */
 */
-const SpriteData *sprite_3 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_3 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x11, 0x15, 0x15, 0xa, 0x0
 		0x11, 0x15, 0x15, 0xa, 0x0
 }};
 }};
 /*
 /*
@@ -173,7 +173,7 @@ const SpriteData *sprite_3 = new SpriteData {.width=5, .height=5, .data=new uint
 ███   ███   ███
 ███   ███   ███
 ███      ███   
 ███      ███   
 */
 */
-const SpriteData *sprite_10 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_10 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1f, 0x0, 0xe, 0x11, 0xe
 		0x1f, 0x0, 0xe, 0x11, 0xe
 }};
 }};
 /*
 /*
@@ -183,7 +183,7 @@ const SpriteData *sprite_10 = new SpriteData {.width=5, .height=5, .data=new uin
 ███   ███      
 ███   ███      
 ███      ███   
 ███      ███   
 */
 */
-const SpriteData *sprite_K = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_K = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1f, 0x4, 0xa, 0x11, 0x0
 		0x1f, 0x4, 0xa, 0x11, 0x0
 }};
 }};
 /*
 /*
@@ -193,7 +193,7 @@ const SpriteData *sprite_K = new SpriteData {.width=5, .height=5, .data=new uint
          ███   
          ███   
 ████████████   
 ████████████   
 */
 */
-const SpriteData *sprite_5 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_5 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x17, 0x15, 0x15, 0x19, 0x0
 		0x17, 0x15, 0x15, 0x19, 0x0
 }};
 }};
 /*
 /*
@@ -203,7 +203,7 @@ const SpriteData *sprite_5 = new SpriteData {.width=5, .height=5, .data=new uint
 ███      ███   
 ███      ███   
    ██████      
    ██████      
 */
 */
-const SpriteData *sprite_6 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_6 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0xe, 0x15, 0x15, 0x8, 0x0
 		0xe, 0x15, 0x15, 0x8, 0x0
 }};
 }};
 /*
 /*
@@ -213,7 +213,7 @@ const SpriteData *sprite_6 = new SpriteData {.width=5, .height=5, .data=new uint
          ███   
          ███   
    ██████      
    ██████      
 */
 */
-const SpriteData *sprite_9 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_9 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x2, 0x15, 0x15, 0xe, 0x0
 		0x2, 0x15, 0x15, 0xe, 0x0
 }};
 }};
 /*
 /*
@@ -225,7 +225,7 @@ const SpriteData *sprite_9 = new SpriteData {.width=5, .height=5, .data=new uint
       ███   ███      
       ███   ███      
          ███         
          ███         
 */
 */
-const SpriteData *sprite_diamonds = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_diamonds = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x8, 0x14, 0x22, 0x41, 0x22, 0x14, 0x8
 		0x8, 0x14, 0x22, 0x41, 0x22, 0x14, 0x8
 }};
 }};
 /*
 /*
@@ -235,7 +235,7 @@ const SpriteData *sprite_diamonds = new SpriteData {.width=7, .height=7, .data=n
 ███      ███   
 ███      ███   
 ████████████   
 ████████████   
 */
 */
-const SpriteData *sprite_8 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_8 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1f, 0x15, 0x15, 0x1f, 0x0
 		0x1f, 0x15, 0x15, 0x1f, 0x0
 }};
 }};
 /*
 /*
@@ -245,7 +245,7 @@ const SpriteData *sprite_8 = new SpriteData {.width=5, .height=5, .data=new uint
 ███      ███   
 ███      ███   
    ██████      
    ██████      
 */
 */
-const SpriteData *sprite_J = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_J = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x8, 0x10, 0x10, 0xf, 0x0
 		0x8, 0x10, 0x10, 0xf, 0x0
 }};
 }};
 /*
 /*
@@ -257,7 +257,7 @@ const SpriteData *sprite_J = new SpriteData {.width=5, .height=5, .data=new uint
          ███         
          ███         
       █████████      
       █████████      
 */
 */
-const SpriteData *sprite_spades = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_spades = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x18, 0x1c, 0x4e, 0x7f, 0x4e, 0x1c, 0x18
 		0x18, 0x1c, 0x4e, 0x7f, 0x4e, 0x1c, 0x18
 }};
 }};
 /*
 /*
@@ -270,7 +270,7 @@ const SpriteData *sprite_spades = new SpriteData {.width=7, .height=7, .data=new
    ██████████████████         ███            ███   ███      ███      ██████   ███         ███   
    ██████████████████         ███            ███   ███      ███      ██████   ███         ███   
       ████████████               ████████████      ██████   █████████   ███   ███         ██████
       ████████████               ████████████      ██████   █████████   ███   ███         ██████
 */
 */
-const SpriteData *sprite_start = new SpriteData {.width=32, .height=8, .data=new uint8_t[32] {
+const SpriteData sprite_start = (SpriteData) {.width=32, .height=8, .data=(uint8_t[]) {
 		0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x0, 0x0, 0x46, 0x89, 0x89, 0x91, 0x91, 0x62, 0x4, 0xff, 0x84, 0x0, 0xe8, 0x94, 0x94, 0x54, 0xf8, 0x0, 0xfc, 0x8, 0x4, 0x4, 0xff, 0x84
 		0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x0, 0x0, 0x46, 0x89, 0x89, 0x91, 0x91, 0x62, 0x4, 0xff, 0x84, 0x0, 0xe8, 0x94, 0x94, 0x54, 0xf8, 0x0, 0xfc, 0x8, 0x4, 0x4, 0xff, 0x84
 }};
 }};
 /*
 /*
@@ -282,7 +282,7 @@ const SpriteData *sprite_start = new SpriteData {.width=32, .height=8, .data=new
          ███         
          ███         
       █████████      
       █████████      
 */
 */
-const SpriteData *sprite_clubs = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_clubs = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x1c, 0x1c, 0x4b, 0x7f, 0x4b, 0x1c, 0x1c
 		0x1c, 0x1c, 0x4b, 0x7f, 0x4b, 0x1c, 0x1c
 }};
 }};
 /*
 /*
@@ -316,7 +316,7 @@ const SpriteData *sprite_clubs = new SpriteData {.width=7, .height=7, .data=new
                                                                                                       ███                                                                                          ███            
                                                                                                       ███                                                                                          ███            
                                                                                                       ████████████████████████████████████████████████████████████████████████████████████████████████            
                                                                                                       ████████████████████████████████████████████████████████████████████████████████████████████████            
 */
 */
-const SpriteData *sprite_logo = new SpriteData {.width=70, .height=29, .data=new uint8_t[280] {
+const SpriteData sprite_logo = (SpriteData) {.width=70, .height=29, .data=(uint8_t[]) {
 		0xff, 0x1, 0x1, 0x1, 0xe1, 0xf1, 0x39, 0x19, 0x19, 0x19, 0x39, 0x71, 0x61, 0x1, 0x1, 0x1, 0x81, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0x1, 0xf9, 0xf9, 0x1, 0x1, 0x1, 0xb9, 0xb9, 0x1, 0x1, 0x81, 0xf1, 0xf9, 0x81, 0x81, 0x1, 0x1, 0x81, 0x81, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0xb9, 0xb9, 0x1, 0x1, 0x1, 0x81, 0x81, 0x1, 0x81, 0x81, 0x1, 0x1, 0x1, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0x1, 0x1, 0xff, 
 		0xff, 0x1, 0x1, 0x1, 0xe1, 0xf1, 0x39, 0x19, 0x19, 0x19, 0x39, 0x71, 0x61, 0x1, 0x1, 0x1, 0x81, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0x1, 0xf9, 0xf9, 0x1, 0x1, 0x1, 0xb9, 0xb9, 0x1, 0x1, 0x81, 0xf1, 0xf9, 0x81, 0x81, 0x1, 0x1, 0x81, 0x81, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0xb9, 0xb9, 0x1, 0x1, 0x1, 0x81, 0x81, 0x1, 0x81, 0x81, 0x1, 0x1, 0x1, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0x1, 0x1, 0xff, 
 		0xff, 0x0, 0x0, 0x0, 0x71, 0xf3, 0xc3, 0x86, 0x86, 0x86, 0xcc, 0xfc, 0x78, 0x0, 0x7e, 0xff, 0xc3, 0x81, 0x81, 0xc3, 0xff, 0x7e, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x1, 0xff, 0xff, 0x81, 0x81, 0x0, 0xe2, 0xf3, 0xb1, 0x99, 0x99, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x1, 0x1, 0x1, 0x0, 0x7e, 0xff, 0x99, 0x99, 0x99, 0xdf, 0x5e, 0x0, 0x0, 0x0, 0xff, 
 		0xff, 0x0, 0x0, 0x0, 0x71, 0xf3, 0xc3, 0x86, 0x86, 0x86, 0xcc, 0xfc, 0x78, 0x0, 0x7e, 0xff, 0xc3, 0x81, 0x81, 0xc3, 0xff, 0x7e, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x1, 0xff, 0xff, 0x81, 0x81, 0x0, 0xe2, 0xf3, 0xb1, 0x99, 0x99, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x1, 0x1, 0x1, 0x0, 0x7e, 0xff, 0x99, 0x99, 0x99, 0xdf, 0x5e, 0x0, 0x0, 0x0, 0xff, 
 		0xf, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x8, 0xf8, 0x9, 0xc9, 0x89, 0x8, 0x8, 0x89, 0x9, 0x89, 0x8, 0x9, 0xc9, 0x48, 0x48, 0x89, 0x9, 0x8, 0x88, 0x8, 0x9, 0x9, 0x88, 0x8, 0x88, 0xc8, 0xa8, 0x8, 0x89, 0x9, 0x89, 0x8, 0xf8, 0x8, 0x8, 0x8, 0xf, 
 		0xf, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x8, 0xf8, 0x9, 0xc9, 0x89, 0x8, 0x8, 0x89, 0x9, 0x89, 0x8, 0x9, 0xc9, 0x48, 0x48, 0x89, 0x9, 0x8, 0x88, 0x8, 0x9, 0x9, 0x88, 0x8, 0x88, 0xc8, 0xa8, 0x8, 0x89, 0x9, 0x89, 0x8, 0xf8, 0x8, 0x8, 0x8, 0xf, 

BIN
assets/main_image.png


+ 9 - 18
solitaire.cpp

@@ -29,7 +29,7 @@ static void update_timer_callback(FuriMessageQueue *event_queue) {
 
 
 static void render_callback(Canvas *const canvas, void *ctx) {
 static void render_callback(Canvas *const canvas, void *ctx) {
     Game *g = (Game *) ctx;
     Game *g = (Game *) ctx;
-    auto status = furi_mutex_acquire(mutex, 25);
+    auto status = furi_mutex_acquire(mutex, 150);
     if (g == nullptr || status != FuriStatusOk) return;
     if (g == nullptr || status != FuriStatusOk) return;
     g->Render(canvas);
     g->Render(canvas);
     UNUSED(canvas);
     UNUSED(canvas);
@@ -43,15 +43,13 @@ extern "C"
 #endif
 #endif
 int32_t solitaire_app(void *p) {
 int32_t solitaire_app(void *p) {
     UNUSED(p);
     UNUSED(p);
+    FURI_LOG_D("MEMORY", "Free %i", memmgr_get_free_heap());
     int32_t return_code = 0;
     int32_t return_code = 0;
+    size_t start = memmgr_get_free_heap();
     Game *game = new Game;
     Game *game = new Game;
-    FURI_LOG_D("LOAD", "START");
     FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(AppEvent));
     FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(AppEvent));
-    FURI_LOG_D("LOAD", "QUEUE");
-    FURI_LOG_D("LOAD", "GAME");
     mutex = furi_mutex_alloc(FuriMutexTypeNormal);
     mutex = furi_mutex_alloc(FuriMutexTypeNormal);
     if (mutex) {
     if (mutex) {
-        FURI_LOG_D("LOAD", "ALLOC");
         bool processing = true;
         bool processing = true;
         auto *notification = static_cast<NotificationApp *>(furi_record_open(RECORD_NOTIFICATION));
         auto *notification = static_cast<NotificationApp *>(furi_record_open(RECORD_NOTIFICATION));
 
 
@@ -62,7 +60,7 @@ int32_t solitaire_app(void *p) {
         view_port_input_callback_set(view_port, input_callback, event_queue);
         view_port_input_callback_set(view_port, input_callback, event_queue);
 
 
         FuriTimer *timer = furi_timer_alloc(update_timer_callback, FuriTimerTypePeriodic, event_queue);
         FuriTimer *timer = furi_timer_alloc(update_timer_callback, FuriTimerTypePeriodic, event_queue);
-        furi_timer_start(timer, furi_kernel_get_tick_frequency() / 30);
+        furi_timer_start(timer, furi_kernel_get_tick_frequency() / 20);
 
 
         auto gui = static_cast<Gui *>(furi_record_open("gui"));
         auto gui = static_cast<Gui *>(furi_record_open("gui"));
         gui_add_view_port(gui, view_port, GuiLayerFullscreen);
         gui_add_view_port(gui, view_port, GuiLayerFullscreen);
@@ -72,7 +70,7 @@ int32_t solitaire_app(void *p) {
 //        game->NewRound();
 //        game->NewRound();
 
 
         while (processing) {
         while (processing) {
-            FuriStatus event_status = furi_message_queue_get(event_queue, &event, 150);
+            FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever);
             furi_mutex_acquire(mutex, FuriWaitForever);
             furi_mutex_acquire(mutex, FuriWaitForever);
 
 
             if (event_status == FuriStatusOk) {
             if (event_status == FuriStatusOk) {
@@ -93,17 +91,7 @@ int32_t solitaire_app(void *p) {
                                 break;
                                 break;
                         }
                         }
                     } else if (event.input->type == InputTypePress) {
                     } else if (event.input->type == InputTypePress) {
-                        switch (event.input->key) {
-                            case InputKeyUp:
-                            case InputKeyDown:
-                            case InputKeyRight:
-                            case InputKeyLeft:
-                            case InputKeyOk:
-                                game->Press(event.input->key);
-                                break;
-                            default:
-                                break;
-                        }
+                        game->Press(event.input->key);
                     }
                     }
                 } else if (event.type == EventTypeTick) {
                 } else if (event.type == EventTypeTick) {
                     game->Update(notification);
                     game->Update(notification);
@@ -131,6 +119,9 @@ int32_t solitaire_app(void *p) {
     delete game;
     delete game;
     furi_mutex_free(mutex);
     furi_mutex_free(mutex);
     furi_message_queue_free(event_queue);
     furi_message_queue_free(event_queue);
+    start = memmgr_get_free_heap()-start;
+    if(start!=0)
+        FURI_LOG_E("MEMORY", "Leak detected %i", start);
     return return_code;
     return return_code;
 }
 }
 
 

+ 21 - 26
utils/Card.cpp

@@ -2,11 +2,6 @@
 #include "RenderBuffer.h"
 #include "RenderBuffer.h"
 #include "../assets.h"
 #include "../assets.h"
 
 
-#define CARD_HEIGHT 23
-#define CARD_HALF_HEIGHT 11
-#define CARD_WIDTH 17
-#define CARD_HALF_WIDTH 8
-
 static Sprite letters[] = {
 static Sprite letters[] = {
         Sprite(sprite_2, BlackOnly),
         Sprite(sprite_2, BlackOnly),
         Sprite(sprite_3, BlackOnly),
         Sprite(sprite_3, BlackOnly),
@@ -32,38 +27,38 @@ static Sprite suits[] = {
 
 
 static Sprite backSide = Sprite(sprite_pattern_big, BlackOnly);
 static Sprite backSide = Sprite(sprite_pattern_big, BlackOnly);
 
 
-void Card::Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer) {
-
+void Card::Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit) {
+    uint8_t height = y + fmin(size_limit, 22);
     if (exposed) {
     if (exposed) {
-        buffer->draw_rbox(x, y, x + 16, y + 22, White);
-        buffer->draw_rbox_frame(x, y, x + 16, y + 22, Black);
-//        buffer->draw_line(x+15, y, x+15, y+22, White);
-
-            buffer->draw(&(letters[value]), (Vector) {(float) x + 5, (float) y + 6}, 0);
-           buffer->draw(&(suits[suit]), (Vector) {(float) x + 12, (float) y + 6}, 0);
+        buffer->draw_rbox(x, y, x + 16, height, White);
+        buffer->draw_rbox_frame(x, y, x + 16, height, Black);
+        buffer->draw(&(letters[value]), (Vector) {(float) x + 5, (float) y + 6}, 0);
+        buffer->draw(&(suits[suit]), (Vector) {(float) x + 12, (float) y + 6}, 0);
 
 
-          buffer->draw(&(letters[value]), (Vector) {(float) x + 12, (float) y + 17}, M_PI);
-           buffer->draw(&(suits[suit]), (Vector) {(float) x + 5, (float) y + 17}, M_PI);
+        if (size_limit > 8) {
+            buffer->draw(&(letters[value]), (Vector) {(float) x + 12, (float) y + 17}, M_PI);
+            buffer->draw(&(suits[suit]), (Vector) {(float) x + 5, (float) y + 17}, M_PI);
+        }
         if (selected) {
         if (selected) {
-            buffer->draw_rbox(x, y, x + 17, y + 23, Flip);
+            buffer->draw_box(x + 1, y + 1, x + 16, height, Flip);
         }
         }
     } else {
     } else {
-        RenderBack(x, y, selected, buffer);
-//        buffer->draw(&backSide, (Vector) {(float) x + 8, (float) y + 11}, 0);
+        RenderBack(x, y, selected, buffer, size_limit);
     }
     }
-
 }
 }
 
 
 void Card::RenderEmptyCard(uint8_t x, uint8_t y, RenderBuffer *buffer) {
 void Card::RenderEmptyCard(uint8_t x, uint8_t y, RenderBuffer *buffer) {
-    buffer->draw_rbox(x, y, x + 17, y + 23, Flip);
-    buffer->draw_rbox_frame(x + 2, y + 2, x + 14, y + 20, Flip);
+    buffer->draw_rbox(x, y, x + 17, y + 23, Black);
+    buffer->draw_rbox_frame(x + 2, y + 2, x + 14, y + 20, White);
 }
 }
 
 
-void Card::RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer) {
-    buffer->draw_rbox(x + 1, y + 1, x + 16, y + 22, White);
-    buffer->draw_rbox_frame(x, y, x + 16, y + 22, Black);
-    buffer->draw(&backSide, (Vector) {(float) x + 9, (float) y + 12}, 0);
+void Card::RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit) {
+    uint8_t height = y + fmin(size_limit, 22);
+
+    buffer->draw_box(x + 1, y + 1, x + 16, height, White);
+    buffer->draw_rbox_frame(x, y, x + 16, height, Black);
+    buffer->draw(&backSide, (Vector) {(float) x + 9, (float) y + 12}, 15, fmin(size_limit, 22), 0);
     if (selected) {
     if (selected) {
-        buffer->draw_rbox(x, y, x + 17, y + 23, Flip);
+        buffer->draw_box(x + 1, y + 1, x + 16, height, Flip);
     }
     }
 }
 }

+ 2 - 2
utils/Card.h

@@ -11,7 +11,7 @@ struct Card {
 
 
     Card(uint8_t s, uint8_t v) : suit(s), value(v) {}
     Card(uint8_t s, uint8_t v) : suit(s), value(v) {}
 
 
-    void Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer);
+    void Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit);
     static void RenderEmptyCard(uint8_t x, uint8_t y, RenderBuffer *buffer);
     static void RenderEmptyCard(uint8_t x, uint8_t y, RenderBuffer *buffer);
-    static void RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer);
+    static void RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit);
 };
 };

+ 8 - 0
utils/List.h

@@ -110,6 +110,14 @@ struct List {
         }
         }
     }
     }
 
 
+    void add_front(T *data) {
+        count++;
+        ListItem<T> *c = start;
+        start = new ListItem<T>();
+        start->data = data;
+        start->next = c;
+    }
+
     void remove(T *data) {
     void remove(T *data) {
         if (!start || !data) return;
         if (!start || !data) return;
 
 

+ 32 - 12
utils/RenderBuffer.cpp

@@ -9,17 +9,21 @@ RenderBuffer::RenderBuffer(uint8_t w, uint8_t h) : Buffer(w, h) {
 }
 }
 
 
 void RenderBuffer::reset() {
 void RenderBuffer::reset() {
+    int size = width() * (height() / 8);
+    for (int i = 0; i < size; i++) {
+        data[i] = 0;
+    }
 }
 }
 
 
 void RenderBuffer::render(Canvas *const canvas) {
 void RenderBuffer::render(Canvas *const canvas) {
-    canvas_clear(canvas);
+//    canvas_clear(canvas);
     for (uint8_t x = 0; x < width(); x++) {
     for (uint8_t x = 0; x < width(); x++) {
         for (uint8_t y = 0; y < height(); y++) {
         for (uint8_t y = 0; y < height(); y++) {
             if (test_pixel(x, y))
             if (test_pixel(x, y))
                 canvas_draw_dot(canvas, x, y);
                 canvas_draw_dot(canvas, x, y);
         }
         }
     }
     }
-    canvas_commit(canvas);
+//    canvas_commit(canvas);
 }
 }
 
 
 void RenderBuffer::draw_line(int x0, int y0, int x1, int y1, PixelColor draw_mode) {
 void RenderBuffer::draw_line(int x0, int y0, int x1, int y1, PixelColor draw_mode) {
@@ -70,40 +74,48 @@ void RenderBuffer::draw_circle(int x, int y, int r, PixelColor color) {
 }
 }
 
 
 void RenderBuffer::draw(Sprite *const sprite, Vector position, float rotation) {
 void RenderBuffer::draw(Sprite *const sprite, Vector position, float rotation) {
+    draw(sprite, position, sprite->width(), sprite->height(), rotation);
+}
+
+
+void RenderBuffer::draw(Sprite *const sprite, Vector position, uint8_t x_cap, uint8_t y_cap, float rotation) {
     switch (sprite->draw_mode) {
     switch (sprite->draw_mode) {
         default:
         default:
         case BlackOnly:
         case BlackOnly:
-            draw_sprite(sprite, true, Black, position, rotation);
+            draw_sprite(sprite, true, Black, position, x_cap, y_cap, rotation);
             break;
             break;
         case WhiteOnly:
         case WhiteOnly:
-            draw_sprite(sprite, false, White, position, rotation);
+            draw_sprite(sprite, false, White, position, x_cap, y_cap, rotation);
             break;
             break;
         case WhiteAsBlack:
         case WhiteAsBlack:
-            draw_sprite(sprite, false, Black, position, rotation);
+            draw_sprite(sprite, false, Black, position, x_cap, y_cap, rotation);
             break;
             break;
         case BlackAsWhite:
         case BlackAsWhite:
-            draw_sprite(sprite, true, White, position, rotation);
+            draw_sprite(sprite, true, White, position, x_cap, y_cap, rotation);
             break;
             break;
         case WhiteAsInverted:
         case WhiteAsInverted:
-            draw_sprite(sprite, false, Flip, position, rotation);
+            draw_sprite(sprite, false, Flip, position, x_cap, y_cap, rotation);
             break;
             break;
         case BlackAsInverted:
         case BlackAsInverted:
-            draw_sprite(sprite, true, Flip, position, rotation);
+            draw_sprite(sprite, true, Flip, position, x_cap, y_cap, rotation);
             break;
             break;
     }
     }
 }
 }
 
 
 //TODO: proper scaling
 //TODO: proper scaling
 void
 void
-RenderBuffer::draw_sprite(Sprite *const sprite, bool is_black, PixelColor draw_color, const Vector& position, float rotation) {
+RenderBuffer::draw_sprite(Sprite *const sprite, bool is_black, PixelColor draw_color, const Vector &position,
+                          uint8_t x_cap, uint8_t y_cap, float rotation) {
     Vector anchor = sprite->get_offset();
     Vector anchor = sprite->get_offset();
     float cosTheta = cos(rotation/* + M_PI_2*/);
     float cosTheta = cos(rotation/* + M_PI_2*/);
     float sinTheta = sin(rotation/* + M_PI_2*/);
     float sinTheta = sin(rotation/* + M_PI_2*/);
     float transformedX, transformedY, rotatedX, rotatedY;
     float transformedX, transformedY, rotatedX, rotatedY;
+    int max_w = fmin(sprite->width(), x_cap);
+    int max_h = fmin(sprite->height(), y_cap);
     bool isOn;
     bool isOn;
     int16_t finalX, finalY;
     int16_t finalX, finalY;
-    for (int y = 0; y < sprite->height(); y++) {
-        for (int x = 0; x < sprite->width(); x++) {
+    for (int y = 0; y < max_h; y++) {
+        for (int x = 0; x < max_w; x++) {
             transformedX = (x - anchor.x);
             transformedX = (x - anchor.x);
             transformedY = (y - anchor.y);
             transformedY = (y - anchor.y);
             rotatedX = transformedX * cosTheta - transformedY * sinTheta;
             rotatedX = transformedX * cosTheta - transformedY * sinTheta;
@@ -128,7 +140,7 @@ RenderBuffer::~RenderBuffer() {
 void RenderBuffer::draw_rbox(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode) {
 void RenderBuffer::draw_rbox(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode) {
     for (int16_t x = x0; x < x1; x++) {
     for (int16_t x = x0; x < x1; x++) {
         for (int16_t y = y0; y < y1; y++) {
         for (int16_t y = y0; y < y1; y++) {
-            if (((x == x0 || x == x1-1) && (y == y0 || y == y1-1)) || !test_coordinate(x,y)) continue;
+            if (((x == x0 || x == x1 - 1) && (y == y0 || y == y1 - 1)) || !test_coordinate(x, y)) continue;
             set_pixel(x, y, draw_mode);
             set_pixel(x, y, draw_mode);
         }
         }
     }
     }
@@ -141,3 +153,11 @@ void RenderBuffer::draw_rbox_frame(int16_t x0, int16_t y0, int16_t x1, int16_t y
     draw_line(x0, y0 + 1, x0, y1 - 1, draw_mode);
     draw_line(x0, y0 + 1, x0, y1 - 1, draw_mode);
     draw_line(x1, y0 + 1, x1, y1 - 1, draw_mode);
     draw_line(x1, y0 + 1, x1, y1 - 1, draw_mode);
 }
 }
+
+void RenderBuffer::draw_box(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode) {
+    for (int16_t x = x0; x < x1; x++) {
+        for (int16_t y = y0; y < y1; y++) {
+            set_pixel(x, y, draw_mode);
+        }
+    }
+}

+ 3 - 2
utils/RenderBuffer.h

@@ -7,7 +7,7 @@ struct Vector;
 class Sprite;
 class Sprite;
 class RenderBuffer : public Buffer {
 class RenderBuffer : public Buffer {
     void draw_sprite(Sprite *const sprite, bool is_black,
     void draw_sprite(Sprite *const sprite, bool is_black,
-                     PixelColor draw_color, const Vector& position, float rotation);
+                     PixelColor draw_color, const Vector& position, uint8_t x_cap, uint8_t y_cap, float rotation);
 
 
 public:
 public:
     explicit RenderBuffer(uint8_t w, uint8_t h);
     explicit RenderBuffer(uint8_t w, uint8_t h);
@@ -20,10 +20,11 @@ public:
 
 
     void draw_line(int x0, int y0, int x1, int y1, PixelColor draw_mode);
     void draw_line(int x0, int y0, int x1, int y1, PixelColor draw_mode);
     void draw_rbox(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
     void draw_rbox(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
+    void draw_box(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
     void draw_rbox_frame(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
     void draw_rbox_frame(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
 
 
     void draw_circle(int x, int y, int r, PixelColor draw_mode);
     void draw_circle(int x, int y, int r, PixelColor draw_mode);
 
 
+    void draw(Sprite *const sprite, Vector position, uint8_t x_cap, uint8_t y_cap, float rotation);
     void draw(Sprite *const sprite, Vector position, float rotation);
     void draw(Sprite *const sprite, Vector position, float rotation);
-
 };
 };