diff --git a/CMakeLists.txt b/CMakeLists.txt index 17d830d..47a9e69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ qt_add_qml_module(appSolitare QML_FILES CardModel.qml SOURCES playingcard.h playingcard.cpp SOURCES gamestate.h gamestate.cpp + SOURCES columnslot.h columnslot.cpp ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. diff --git a/columnslot.cpp b/columnslot.cpp new file mode 100644 index 0000000..43d47e2 --- /dev/null +++ b/columnslot.cpp @@ -0,0 +1,21 @@ +#include "columnslot.h" + +ColumnSlot::ColumnSlot(PlayingCard* card, bool revealed, QObject* parent) + : QObject(parent), m_card(card), m_revealed(revealed) +{} + +PlayingCard* ColumnSlot::card() const { + return m_card; +} + +bool ColumnSlot::isRevealed() const { + return m_revealed; +} + +void ColumnSlot::reveal() { + if (m_revealed) + return; + + m_revealed = true; + emit revealedChanged(); +} diff --git a/columnslot.h b/columnslot.h new file mode 100644 index 0000000..3906c26 --- /dev/null +++ b/columnslot.h @@ -0,0 +1,29 @@ +#ifndef COLUMNSLOT_H +#define COLUMNSLOT_H + +#include +#include "playingcard.h" + +class ColumnSlot : public QObject +{ + Q_OBJECT + Q_PROPERTY(PlayingCard* card READ card CONSTANT) + Q_PROPERTY(bool revealed READ isRevealed NOTIFY revealedChanged) + +public: + explicit ColumnSlot(PlayingCard* card, bool revealed, QObject* parent = nullptr); + + PlayingCard* card() const; + + bool isRevealed() const; + void reveal(); + +signals: + void revealedChanged(); + +private: + PlayingCard* m_card; + bool m_revealed; +}; + +#endif // COLUMNSLOT_H diff --git a/gamestate.cpp b/gamestate.cpp index a03b501..4ca29ab 100644 --- a/gamestate.cpp +++ b/gamestate.cpp @@ -1,5 +1,6 @@ #include "gamestate.h" #include +#include GameState::GameState(QObject *parent) : QObject{parent} @@ -11,7 +12,7 @@ GameState::GameState(QObject *parent) // Initialize the columns (7 piles) for (int i = 0; i < 7; ++i) { - m_columns.append(QList()); + m_columns.append(QList()); } } @@ -27,9 +28,17 @@ void GameState::dealCards() // Deal the cards into the columns int index = 0; for (int i = 0; i < 7; i++) { + QList column; + // Deal exactly i+1 cards to the i-th column - m_columns[i] = deck.mid(index, i + 1); - index += i + 1; + for (int j = 0; j <= i; j++) { + bool revealed = (j == i); + ColumnSlot *col = new ColumnSlot(deck[index], revealed); + column.append(col); + index++; + } + + m_columns[i] = column; } // Use the remaining cards as the draw pile @@ -78,7 +87,8 @@ bool GameState::moveCardToColumn(int columnId) if (cardToMove->value() != PlayingCard::Value::King) return false; - m_columns[columnId].append(cardToMove); + ColumnSlot *col = new ColumnSlot(cardToMove, true); + m_columns[columnId].append(col); m_throwawayPile.removeLast(); emit onThrowawayPileChanged(); @@ -87,7 +97,7 @@ bool GameState::moveCardToColumn(int columnId) } // We'll be comparing this card against the last card in the column - PlayingCard* columnCard = m_columns[columnId].last(); + PlayingCard* columnCard = m_columns[columnId].last()->card(); // This card's value must be one less than the card in the column if (cardToMove->value() != columnCard->value() - 1) @@ -97,8 +107,10 @@ bool GameState::moveCardToColumn(int columnId) if (!PlayingCard::areOppositeColors(*cardToMove, *columnCard)) return false; - m_columns[columnId].append(cardToMove); + ColumnSlot *col = new ColumnSlot(cardToMove, true); + m_columns[columnId].append(col); m_throwawayPile.removeLast(); + ensureColumnRevealed(columnId); emit onThrowawayPileChanged(); emit onColumnsChanged(); @@ -137,15 +149,16 @@ bool GameState::moveColumnCardToFoundation(int columnId, PlayingCard::Suit found } // We'll be moving the top card in the column (maybe) - PlayingCard *cardToMove = m_columns[columnId].first(); + PlayingCard *cardToMove = m_columns[columnId].first()->card(); // Try moving the card into the foundation if (!tryMoveCardToFoundation(foundationId, cardToMove)) return false; // We succeeded, the card is now in the appropriate foundation pile, - // let's remove the card from the column. + // let's remove the column slot. m_columns[columnId].removeFirst(); + ensureColumnRevealed(columnId); emit onColumnsChanged(); return true; @@ -183,6 +196,25 @@ bool GameState::tryMoveCardToFoundation(PlayingCard::Suit foundationId, PlayingC return true; } +void GameState::ensureColumnRevealed(int columnId) +{ + assert(columnId >= 0 && columnId < 7); + + // Nothing to reveal + if (m_columns[columnId].isEmpty()) + return; + + // Get the top column slot + ColumnSlot *col = m_columns[columnId].first(); + + // If it's already revealed, there's nothing to do + if (col->isRevealed()) + return; + + // First slot in the column must always be revealed, reveal it + col->reveal(); +} + QList GameState::drawPile() const { return m_drawPile; @@ -193,7 +225,7 @@ QList GameState::throwawayPile() const return m_throwawayPile; } -QList > GameState::columns() const +QList > GameState::columns() const { return m_columns; } diff --git a/gamestate.h b/gamestate.h index 44693d0..f462421 100644 --- a/gamestate.h +++ b/gamestate.h @@ -3,13 +3,14 @@ #include #include "playingcard.h" +#include "columnslot.h" class GameState : public QObject { Q_OBJECT Q_PROPERTY(QList drawPile READ drawPile NOTIFY onDrawPileChanged) Q_PROPERTY(QList throwawayPile READ throwawayPile NOTIFY onThrowawayPileChanged) - Q_PROPERTY(QList> columns READ columns NOTIFY onColumnsChanged) + Q_PROPERTY(QList> columns READ columns NOTIFY onColumnsChanged) Q_PROPERTY(QList> foundation READ foundation NOTIFY onFoundationChanged) public: @@ -17,7 +18,7 @@ public: QList drawPile() const; QList throwawayPile() const; - QList> columns() const; + QList> columns() const; QList> foundation() const; void dealCards(); @@ -35,10 +36,11 @@ signals: private: QList m_drawPile; QList m_throwawayPile; - QList> m_columns; + QList> m_columns; QList> m_foundation; bool tryMoveCardToFoundation(PlayingCard::Suit foundationId, PlayingCard* cardToMove); + void ensureColumnRevealed(int columnId); }; #endif // GAMESTATE_H