|
@@ -19,10 +19,12 @@ static const NotificationSequence sequence_fail = {
|
|
|
&message_note_a3,
|
|
&message_note_a3,
|
|
|
&message_delay_10,
|
|
&message_delay_10,
|
|
|
&message_vibro_off,
|
|
&message_vibro_off,
|
|
|
- &message_sound_off
|
|
|
|
|
|
|
+ &message_sound_off,
|
|
|
|
|
+ NULL
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
Game::~Game() {
|
|
Game::~Game() {
|
|
|
|
|
+ furi_record_close(RECORD_NOTIFICATION);
|
|
|
delete deck;
|
|
delete deck;
|
|
|
for (int i = 0; i < 4; i++)
|
|
for (int i = 0; i < 4; i++)
|
|
|
delete piles[i];
|
|
delete piles[i];
|
|
@@ -47,6 +49,7 @@ void Game::Render(Canvas *const canvas) {
|
|
|
}
|
|
}
|
|
|
for (int i = 0; i < 4; i++) {
|
|
for (int i = 0; i < 4; i++) {
|
|
|
bool pileSelected = current_row == 0 && (current_column - 3) == i;
|
|
bool pileSelected = current_row == 0 && (current_column - 3) == i;
|
|
|
|
|
+// check_pointer(piles[i]);
|
|
|
if (piles[i]) {
|
|
if (piles[i]) {
|
|
|
piles[i]->Render(i * 18 + 55, 1, pileSelected, buffer, 22);
|
|
piles[i]->Render(i * 18 + 55, 1, pileSelected, buffer, 22);
|
|
|
} else {
|
|
} 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);
|
|
hand.Render(current_column * 18 + 10, current_row * 25 + 15, false, 0, buffer);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
had_change = false;
|
|
had_change = false;
|
|
|
buffer->render(canvas);
|
|
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() {
|
|
Game::Game() {
|
|
|
deck = new Deck(1);
|
|
deck = new Deck(1);
|
|
|
buffer = new RenderBuffer(128, 64);
|
|
buffer = new RenderBuffer(128, 64);
|
|
|
|
|
+
|
|
|
|
|
+ notifications = static_cast<NotificationApp *>(furi_record_open(RECORD_NOTIFICATION));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Game::NewRound() {
|
|
void Game::NewRound() {
|
|
@@ -88,7 +105,6 @@ void Game::Reset() {
|
|
|
//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];
|
|
|
- piles[i] = nullptr;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//Populate columns
|
|
//Populate columns
|
|
@@ -103,7 +119,23 @@ void Game::Reset() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Game::LongPress(InputKey key) {
|
|
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() {
|
|
void Game::Update() {
|
|
@@ -127,19 +159,25 @@ void Game::Press(InputKey key) {
|
|
|
if (key == InputKeyLeft && current_column > 0) {
|
|
if (key == InputKeyLeft && current_column > 0) {
|
|
|
current_column--;
|
|
current_column--;
|
|
|
had_change = true;
|
|
had_change = true;
|
|
|
|
|
+ column_selection = 0;
|
|
|
} else if (key == InputKeyRight && current_column < 6) {
|
|
} else if (key == InputKeyRight && current_column < 6) {
|
|
|
current_column++;
|
|
current_column++;
|
|
|
|
|
+ column_selection = 0;
|
|
|
if (current_row == 0 && current_column == 2) current_column++;
|
|
if (current_row == 0 && current_column == 2) current_column++;
|
|
|
had_change = true;
|
|
had_change = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (key == InputKeyUp && current_row == 1) {
|
|
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();
|
|
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--;
|
|
current_row--;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
had_change = true;
|
|
had_change = true;
|
|
|
} else if (key == InputKeyDown && current_row == 0) {
|
|
} else if (key == InputKeyDown && current_row == 0) {
|
|
@@ -177,7 +215,6 @@ void Game::Press(InputKey key) {
|
|
|
had_change = true;
|
|
had_change = true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- return;
|
|
|
|
|
} else {
|
|
} else {
|
|
|
//Tableau logic
|
|
//Tableau logic
|
|
|
auto *column = &tableau[current_column];
|
|
auto *column = &tableau[current_column];
|
|
@@ -187,8 +224,13 @@ void Game::Press(InputKey key) {
|
|
|
column->Reveal();
|
|
column->Reveal();
|
|
|
had_change = true;
|
|
had_change = true;
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+// hand.AddCard(column->Pop());
|
|
|
//Pick selection
|
|
//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;
|
|
had_change = true;
|
|
|
picked_from_row = current_row;
|
|
picked_from_row = current_row;
|
|
|
picked_from_column = current_column;
|
|
picked_from_column = current_column;
|
|
@@ -196,19 +238,34 @@ void Game::Press(InputKey key) {
|
|
|
} else {
|
|
} else {
|
|
|
ErrorMessage();
|
|
ErrorMessage();
|
|
|
}
|
|
}
|
|
|
- return;
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
//Place logic
|
|
//Place logic
|
|
|
if (key == InputKeyOk) {
|
|
if (key == InputKeyOk) {
|
|
|
|
|
+ //Place back to where it was picked up
|
|
|
if (current_column == picked_from_column && current_row == picked_from_row) {
|
|
if (current_column == picked_from_column && current_row == picked_from_row) {
|
|
|
//add back to tableau
|
|
//add back to tableau
|
|
|
if (picked_from_row == 0) {
|
|
if (picked_from_row == 0) {
|
|
|
|
|
+ FURI_LOG_D("PLACE", "reinsert top");
|
|
|
had_change = true;
|
|
had_change = true;
|
|
|
deck->AddToWaste(hand.Pop());
|
|
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) {
|
|
} 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];
|
|
Card *current = piles[current_column - 3];
|
|
|
if (Card::CanPlace(current, hand.TopCard())) {
|
|
if (Card::CanPlace(current, hand.TopCard())) {
|
|
|
piles[current_column - 3] = hand.Pop();
|
|
piles[current_column - 3] = hand.Pop();
|
|
@@ -216,21 +273,40 @@ void Game::Press(InputKey key) {
|
|
|
} else {
|
|
} else {
|
|
|
ErrorMessage();
|
|
ErrorMessage();
|
|
|
}
|
|
}
|
|
|
|
|
+ //Place to the tableau columns
|
|
|
} else if (current_row == 1) {
|
|
} else if (current_row == 1) {
|
|
|
|
|
+ FURI_LOG_D("PLACE", "place bottom");
|
|
|
auto *column = &tableau[current_column];
|
|
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 {
|
|
} else {
|
|
|
ErrorMessage();
|
|
ErrorMessage();
|
|
|
}
|
|
}
|
|
|
- return;
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ CheckCanAutoSolve();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Game::ErrorMessage() {
|
|
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");
|
|
|
}
|
|
}
|