Przeglądaj źródła

logic finally works as should
quick solve detection added
bugfixes

Tibor Tálosi 2 lat temu
rodzic
commit
87a010c2bc
6 zmienionych plików z 154 dodań i 50 usunięć
  1. 6 2
      Deck.cpp
  2. 92 16
      Game.cpp
  3. 3 1
      Game.h
  4. 33 10
      TableauColumn.cpp
  5. 1 0
      TableauColumn.h
  6. 19 21
      utils/List.h

+ 6 - 2
Deck.cpp

@@ -7,8 +7,8 @@ Deck::Deck(uint8_t count) : deck_count(count) {
 }
 
 void Deck::Generate() {
-    waste_pile.empty();
-    stock_pile.empty();
+    waste_pile.clear();
+    stock_pile.clear();
     //generate and shuffle deck
     int cards_count = 52 * deck_count;
     uint8_t cards[cards_count];
@@ -28,16 +28,19 @@ void Deck::Generate() {
         int suit = cards[i] / 13;
         stock_pile.add(new Card(suit, letter));
     }
+    FURI_LOG_D("Deck count", "%li", stock_pile.count);
 }
 
 void Deck::Cycle() {
     if (stock_pile.count > 0) {
         auto *c = stock_pile.pop();
+        check_pointer(c);
         c->exposed = true;
         waste_pile.add(c);
     } else {
         while (waste_pile.count > 0) {
             auto *c = waste_pile.pop();
+            check_pointer(c);
             c->exposed = false;
             stock_pile.add(c);
         }
@@ -49,6 +52,7 @@ Card *Deck::GetLastWaste() {
 }
 
 void Deck::AddToWaste(Card *c) {
+    check_pointer(c);
     waste_pile.add(c);
 }
 

+ 92 - 16
Game.cpp

@@ -19,10 +19,12 @@ static const NotificationSequence sequence_fail = {
         &message_note_a3,
         &message_delay_10,
         &message_vibro_off,
-        &message_sound_off
+        &message_sound_off,
+        NULL
 };
 
 Game::~Game() {
+    furi_record_close(RECORD_NOTIFICATION);
     delete deck;
     for (int i = 0; i < 4; i++)
         delete piles[i];
@@ -47,6 +49,7 @@ void Game::Render(Canvas *const canvas) {
             }
             for (int i = 0; i < 4; i++) {
                 bool pileSelected = current_row == 0 && (current_column - 3) == i;
+//                check_pointer(piles[i]);
                 if (piles[i]) {
                     piles[i]->Render(i * 18 + 55, 1, pileSelected, buffer, 22);
                 } else {
@@ -56,17 +59,31 @@ void Game::Render(Canvas *const canvas) {
                     }
                 }
             }
-            if (hand.Count() > 0)
+            if (hand.Count() > 0) {
                 hand.Render(current_column * 18 + 10, current_row * 25 + 15, false, 0, buffer);
+            }
         }
     }
     had_change = false;
     buffer->render(canvas);
+    if (state == GameStatePlay && can_auto_solve) {
+        canvas_set_font(canvas,FontSecondary);
+
+        canvas_set_color(canvas, ColorBlack);
+        canvas_draw_frame(canvas, 8, 52, 112, 12);
+        canvas_set_color(canvas, ColorWhite);
+        canvas_draw_box(canvas, 9, 53, 110, 10);
+
+        canvas_set_color(canvas, ColorBlack);
+        canvas_draw_str_aligned(canvas, 64, 58, AlignCenter, AlignCenter, "Long press > to auto solve!");
+    }
 }
 
 Game::Game() {
     deck = new Deck(1);
     buffer = new RenderBuffer(128, 64);
+
+    notifications = static_cast<NotificationApp *>(furi_record_open(RECORD_NOTIFICATION));
 }
 
 void Game::NewRound() {
@@ -88,7 +105,6 @@ void Game::Reset() {
     //Reset foundations
     for (int i = 0; i < 4; i++) {
         if (piles[i]) delete piles[i];
-        piles[i] = nullptr;
     }
 
     //Populate columns
@@ -103,7 +119,23 @@ void Game::Reset() {
 }
 
 void Game::LongPress(InputKey key) {
-    UNUSED(key);
+    if (key == InputKeyOk) {
+        if (hand.Count() == 1) {
+            for (uint8_t i = 0; i < 4; i++) {
+                Card *current = piles[i];
+                if (Card::CanPlace(current, hand.TopCard())) {
+                    check_pointer(piles[i]);
+                    piles[i] = hand.Pop();
+                    had_change = true;
+                    return;
+                }
+            }
+        }
+    } else if (key == InputKeyUp) {
+        current_row = 0;
+        had_change = true;
+        if (current_column == 2) current_column--;
+    }
 }
 
 void Game::Update() {
@@ -127,19 +159,25 @@ void Game::Press(InputKey key) {
     if (key == InputKeyLeft && current_column > 0) {
         current_column--;
         had_change = true;
+        column_selection = 0;
     } else if (key == InputKeyRight && current_column < 6) {
         current_column++;
+        column_selection = 0;
         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 count = tableau[current_column].Count();
         uint8_t first_non_flipped = tableau[current_column].FirstNonFlipped();
-        if (count > first_non_flipped && (column_selection) < count) {
-            column_selection++;
-        } else
+        if (hand.Count() == 0) {
+            if ((count - column_selection - 1) > first_non_flipped && (column_selection) < count) {
+                column_selection++;
+            } else
+                current_row--;
+        } else {
             current_row--;
+        }
 
         had_change = true;
     } else if (key == InputKeyDown && current_row == 0) {
@@ -177,7 +215,6 @@ void Game::Press(InputKey key) {
                         had_change = true;
                     }
                 }
-                return;
             } else {
                 //Tableau logic
                 auto *column = &tableau[current_column];
@@ -187,8 +224,13 @@ void Game::Press(InputKey key) {
                         column->Reveal();
                         had_change = true;
                     } else {
+//                        hand.AddCard(column->Pop());
                         //Pick selection
-                        hand.AddCard(column->Pop());
+                        auto *data = column->splice(column_selection);
+                        hand.AddRange(data);
+                        data->soft_clear();
+                        delete data;
+                        column_selection = 0;
                         had_change = true;
                         picked_from_row = current_row;
                         picked_from_column = current_column;
@@ -196,19 +238,34 @@ void Game::Press(InputKey key) {
                 } else {
                     ErrorMessage();
                 }
-                return;
             }
         }
     } else {
         //Place logic
         if (key == InputKeyOk) {
+            //Place back to where it was picked up
             if (current_column == picked_from_column && current_row == picked_from_row) {
                 //add back to tableau
                 if (picked_from_row == 0) {
+                    FURI_LOG_D("PLACE", "reinsert top");
                     had_change = true;
                     deck->AddToWaste(hand.Pop());
+                } else {
+                    FURI_LOG_D("PLACE", "reinsert tableau %i %i", hand.Count(), current_column);
+                    auto *column = &tableau[current_column];
+                    if (column) {
+                        FURI_LOG_D("PLACE", "BEFORE MERGE %i", hand.Count());
+                        column->Merge(&hand);
+                        had_change = true;
+                        FURI_LOG_D("PLACE", "AFTER MERGE");
+                    } else {
+                        FURI_LOG_E("PLACE", "TABLEAU ERROR");
+                    }
                 }
+                //Place to the top piles
             } else if (hand.Count() == 1 && current_row == 0 && current_column > 1) {
+                FURI_LOG_D("PLACE", "place top");
+                check_pointer(piles[current_column - 3]);
                 Card *current = piles[current_column - 3];
                 if (Card::CanPlace(current, hand.TopCard())) {
                     piles[current_column - 3] = hand.Pop();
@@ -216,21 +273,40 @@ void Game::Press(InputKey key) {
                 } else {
                     ErrorMessage();
                 }
+                //Place to the tableau columns
             } else if (current_row == 1) {
+                FURI_LOG_D("PLACE", "place bottom");
                 auto *column = &tableau[current_column];
-                if ((current_row == picked_from_row && current_column == picked_from_column) ||
-                    column->CanPlace(&hand)) {
-                    column->Merge(&hand);
-                    had_change = true;
+                if (column) {
+                    if ((current_row == picked_from_row && current_column == picked_from_column) ||
+                        column->CanPlace(&hand)) {
+                        FURI_LOG_D("PLACE", "canplace");
+                        column->Merge(&hand);
+                        had_change = true;
+                    }
+                } else {
+                    FURI_LOG_E("PLACE", "TABLEAU ERROR in bottom place");
                 }
             } else {
                 ErrorMessage();
             }
-            return;
         }
     }
+
+    CheckCanAutoSolve();
 }
 
 void Game::ErrorMessage() {
+    notification_message(notifications, &sequence_fail);
+}
 
+void Game::CheckCanAutoSolve() {
+    uint8_t ok = 0;
+    for (uint8_t i = 0; i < 7; i++) {
+        if (tableau[i].Count() == 0 || tableau[i].TopCard()->exposed)
+            ok++;
+    }
+    can_auto_solve = ok == 7;
+    if (can_auto_solve)
+        FURI_LOG_D("Solve", "can auto solve");
 }

+ 3 - 1
Game.h

@@ -10,7 +10,7 @@
 #include "TableauColumn.h"
 
 typedef enum {
-    GameStateGameOver, GameStateStart, GameStatePlay, GameStateAnimate
+    GameStateGameOver, GameStateStart, GameStatePlay, GameStateAnimate, GameStateSolve
 } PlayState;
 
 class Game {
@@ -27,6 +27,7 @@ class Game {
 
     uint8_t picked_from_row;
     uint8_t picked_from_column;
+    NotificationApp* notifications;
 
     int8_t column_selection;
     RenderBuffer *buffer;
@@ -45,6 +46,7 @@ public:
     void Press(InputKey key);
     void Update();
     void ErrorMessage();
+    void CheckCanAutoSolve();
 
     ~Game();
 };

+ 33 - 10
TableauColumn.cpp

@@ -4,15 +4,18 @@
 #define max(a, b) a>b?a:b
 
 void TableauColumn::Reset() {
-    cards->empty();
+    cards->clear();
 }
 
 void TableauColumn::AddCard(Card *c) {
+    check_pointer(c);
     cards->add(c);
 }
 
 void TableauColumn::AddRange(List<Card> *hand) {
+    check_pointer(hand);
     for (auto *item: *hand) {
+        check_pointer(item);
         cards->add(item);
     }
 }
@@ -33,19 +36,21 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
     uint8_t position = 0;
     uint8_t first_non_flipped = FirstNonFlipped();
     bool had_top = false;
+    check_pointer(cards);
 
     // Draw the first flipped and non-flipped card with adjusted visibility
     if (first_non_flipped <= loop_start && selection != first_non_flipped) {
         // Draw a card back if it is not the first card
         if (first_non_flipped > 0) {
-            Card::RenderBack(x, y + position, selection == first_non_flipped, buffer, 5);
+            Card::RenderBack(x, y + position, false, buffer, 5);
             // Increment loop start index and position
             position += 4;
             loop_start++;
             had_top = true;
         }
         // Draw the front side of the first non-flipped card
-        (*cards)[first_non_flipped]->Render(x, y + position, selection == first_non_flipped, buffer,
+        check_pointer((*cards)[first_non_flipped]);
+        (*cards)[first_non_flipped]->Render(x, y + position, false, buffer,
                                             cards->count == 1 ? 22 : 9);
         position += 8;
         loop_start++; // Increment loop start index
@@ -54,10 +59,11 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
     // Draw the selected card with adjusted visibility
     if (loop_start > selection) {
         if (!had_top && first_non_flipped > 0) {
-            Card::RenderBack(x, y + position, selection == first_non_flipped, buffer, 5);
-            position += 2;
+            Card::RenderBack(x, y + position, false, buffer, 5);
+            position += 4;
             loop_start++;
         }
+        check_pointer((*cards)[selection]);
         // Draw the front side of the selected card
         (*cards)[selection]->Render(x, y + position, true, buffer, 9);
         position += 8;
@@ -68,11 +74,12 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
     for (uint8_t i = loop_start; i < loop_end; i++, position += 4) {
         int height = 5;
         if((i + 1) == loop_end) height = 22;
-        else if(i == first_non_flipped) height = 9;
-
-        (*cards)[i]->Render(x, y + position, i == selection, buffer, height);
-
-        if (i == selection || i == first_non_flipped) position += 4;
+        else if(i == selection || i == first_non_flipped) height = 9;
+        check_pointer((*cards)[i]);
+        if((*cards)[i]) {
+            (*cards)[i]->Render(x, y + position, i == selection, buffer, height);
+            if (i == selection || i == first_non_flipped) position += 4;
+        }
     }
 }
 
@@ -98,9 +105,20 @@ TableauColumn::~TableauColumn() {
 }
 
 void TableauColumn::Merge(TableauColumn *other) {
+    Card *prev = nullptr;
     for (auto *item: *(other->cards)) {
+        if(prev == item) {
+            FURI_LOG_E("PLACE", "Possible circular dependency!");
+            break;
+        }
+        FURI_LOG_D("PLACE", "ADDING %i %i", item->suit, item->value);
+        if(!item){
+            FURI_LOG_E("PLACE", "nullptr in merge!");
+            break;
+        }
         cards->add(item);
     }
+    FURI_LOG_D("PLACE", "clear");
     other->cards->soft_clear();
 }
 
@@ -146,3 +164,8 @@ bool TableauColumn::CanPlace(TableauColumn *other) {
 
     return (current_suit + 1) % 2 == other_suit && (last->value + 1) % 13 == (top->value + 2) % 13;
 }
+
+List<Card> *TableauColumn::splice(uint32_t selection) {
+    FURI_LOG_D("TBLC", "%li,  %li", cards->count-selection, selection);
+    return cards->splice(cards->count-selection-1, selection+1);
+}

+ 1 - 0
TableauColumn.h

@@ -24,4 +24,5 @@ public:
     Card* Pop();
     void Reveal();
     bool CanPlace(TableauColumn *other);
+    List<Card> *splice(uint32_t selection);
 };

+ 19 - 21
utils/List.h

@@ -56,8 +56,7 @@ struct List {
 
     ~List() {
         FURI_LOG_D("App", "List emptied");
-
-        empty();
+        clear();
     }
 
     void soft_clear() {
@@ -87,15 +86,8 @@ struct List {
         count = 0;
     }
 
-    void empty() {
-        clear();
-        if (start) {
-            check_pointer(start);
-            delete start;
-        }
-    }
-
     void add(T *data) {
+        check_pointer(data);
         count++;
         if (count > 1) {
             ListItem<T> *c = start;
@@ -181,25 +173,30 @@ struct List {
         if (index < count) {
             uint32_t m = (index + amount) > count ? count - index : amount;
             uint32_t curr_id = 0;
-            auto s = start;
+            auto currentItem = start;
+            ListItem<T> *prevItem = nullptr;
             while (curr_id < index) {
-                s = s->next;
-                if (!s) return removedElements;
+                prevItem = currentItem;
+                currentItem = currentItem->next;
+                if (!currentItem) return removedElements;
                 curr_id++;
             }
 
-            ListItem<T> *t;
+            ListItem<T> *temp;
             for (uint32_t i = 0; i < m; i++) {
-                t = s->next;
-                if (s->data) {
-                    removedElements->add(s->data);
+                temp = currentItem->next;
+                if (currentItem->data) {
+                    removedElements->add(currentItem->data);
                 }
-                delete s;
-                s = t->next;
+                delete currentItem;
+                currentItem = temp;
                 count--;
             }
-            if (index == 0) {
-                start = s;
+
+            if (prevItem) {
+                prevItem->next = currentItem;
+            } else {
+                start = currentItem; // Update start if removing from the beginning.
             }
         }
 
@@ -240,6 +237,7 @@ struct List {
 
     T *pop() {
         if (!start) {
+            FURI_LOG_E("LIST", "No start for pop");
             // List is empty, nothing to remove
             return nullptr;
         }