Compare commits
No commits in common. "ef16bf91881f43d9964de2ed27d5fdb045df9b7c" and "6ecfc64a792c42f098a0e59d0c0be4e5c51e46d3" have entirely different histories.
ef16bf9188
...
6ecfc64a79
11
qml/Main.qml
11
qml/Main.qml
|
@ -53,7 +53,7 @@ ApplicationWindow {
|
|||
Timer {
|
||||
id: gameTimer
|
||||
interval: 1000
|
||||
running: GameState.gameWon === false
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: scoreBar.time += 1
|
||||
}
|
||||
|
@ -62,15 +62,12 @@ ApplicationWindow {
|
|||
id: scoreBar
|
||||
|
||||
moves: GameState.moveAmount
|
||||
score: GameState.score
|
||||
time: 0
|
||||
|
||||
height: Math.max(parent.height * 0.08, 50)
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
onRestart: time = 0
|
||||
}
|
||||
|
||||
// Show the foundation piles, throwaway pile & the draw stack on the first row
|
||||
|
@ -126,9 +123,5 @@ ApplicationWindow {
|
|||
cardHeight: app.cardHeight
|
||||
}
|
||||
|
||||
WinOverlay {
|
||||
onRestart: {
|
||||
scoreBar.time = 0
|
||||
}
|
||||
}
|
||||
WinOverlay {}
|
||||
}
|
||||
|
|
|
@ -10,15 +10,10 @@ Rectangle {
|
|||
property int time: 0
|
||||
property int moves: 0
|
||||
|
||||
signal restart
|
||||
|
||||
color: "lightgray"
|
||||
|
||||
RoundButton {
|
||||
onClicked: {
|
||||
GameState.dealCards()
|
||||
scoreBarRoot.restart()
|
||||
}
|
||||
onClicked: GameState.dealCards()
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: parent.width * 0.02
|
||||
|
|
|
@ -10,8 +10,6 @@ Rectangle {
|
|||
visible: GameState.gameWon === true
|
||||
anchors.fill: parent
|
||||
|
||||
signal restart
|
||||
|
||||
Text {
|
||||
id: winText
|
||||
|
||||
|
@ -25,10 +23,7 @@ Rectangle {
|
|||
|
||||
Button {
|
||||
text: "Restart"
|
||||
onClicked: {
|
||||
GameState.dealCards();
|
||||
winOverlay.restart();
|
||||
}
|
||||
onClicked: GameState.dealCards()
|
||||
anchors.top: winText.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ void GameState::dealCards() {
|
|||
emit columnsChanged();
|
||||
emit foundationChanged();
|
||||
emit moveAmountChanged();
|
||||
emit scoreChanged();
|
||||
}
|
||||
|
||||
void GameState::setupWinningDeck() {
|
||||
|
@ -103,7 +102,6 @@ void GameState::setupWinningDeck() {
|
|||
emit columnsChanged();
|
||||
emit foundationChanged();
|
||||
emit moveAmountChanged();
|
||||
emit scoreChanged();
|
||||
}
|
||||
|
||||
bool GameState::drawNextCard() {
|
||||
|
@ -155,7 +153,6 @@ bool GameState::moveThrownCardToColumn(int columnId) {
|
|||
qDebug() << "> Moving complete";
|
||||
|
||||
incrementMoveAmt();
|
||||
increaseScore(5); // Score increase for moving to column
|
||||
emit throwawayPileChanged();
|
||||
emit columnsChanged();
|
||||
return true;
|
||||
|
@ -186,7 +183,6 @@ bool GameState::moveThrownCardToFoundation(int foundationId) {
|
|||
qDebug() << "> Moving complete";
|
||||
|
||||
incrementMoveAmt();
|
||||
increaseScore(10); // Score increase for moving to foundation
|
||||
emit throwawayPileChanged();
|
||||
emit foundationChanged();
|
||||
return true;
|
||||
|
@ -267,7 +263,6 @@ bool GameState::moveColumnCardToFoundation(int columnId, int foundationId) {
|
|||
ensureColumnRevealed(columnId);
|
||||
qDebug() << "> Moving complete";
|
||||
|
||||
increaseScore(10); // Score increase for moving to foundation
|
||||
incrementMoveAmt();
|
||||
emit columnsChanged();
|
||||
emit foundationChanged();
|
||||
|
@ -285,8 +280,7 @@ bool GameState::autoMoveThrownCard() {
|
|||
qDebug() << "Attempting auto-move of thrown card " << cardToMove->toString();
|
||||
|
||||
// Try moving the card into the foundation
|
||||
auto changed = tryAutoMoveSingleCard(*cardToMove);
|
||||
if (!changed.has_value()) {
|
||||
if (!tryAutoMoveSingleCard(*cardToMove)) {
|
||||
qDebug() << "> Moving failed, no available move found";
|
||||
return false;
|
||||
}
|
||||
|
@ -297,17 +291,11 @@ bool GameState::autoMoveThrownCard() {
|
|||
|
||||
emit throwawayPileChanged();
|
||||
|
||||
switch (changed.value().destinationType) {
|
||||
case AutoMoveResult::DestinationType::Foundation:
|
||||
increaseScore(10); // Score increase for moving to foundation
|
||||
emit foundationChanged();
|
||||
break;
|
||||
case AutoMoveResult::DestinationType::Column:
|
||||
increaseScore(5); // Score increase for moving to column
|
||||
emit columnsChanged();
|
||||
break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
// We don't know which pile the card was moved to, to be safe, emit
|
||||
// a change from both
|
||||
// NOTE: consider returning what changed from tryAutoMoveSingleCard
|
||||
emit columnsChanged();
|
||||
emit foundationChanged();
|
||||
incrementMoveAmt();
|
||||
|
||||
return true;
|
||||
|
@ -332,8 +320,7 @@ bool GameState::autoMoveColumnCard(int columnId, int cardIndex) {
|
|||
// This is a single card move (last card)
|
||||
PlayingCard* cardToMove = col->card();
|
||||
qDebug() << "Attempting auto-move of column " << columnId << " card " << cardToMove->toString();
|
||||
auto changed = tryAutoMoveSingleCard(*cardToMove, columnId);
|
||||
if (!changed.has_value()) {
|
||||
if (!tryAutoMoveSingleCard(*cardToMove, columnId)) {
|
||||
qDebug() << "> Moving failed, no available move found";
|
||||
return false;
|
||||
}
|
||||
|
@ -344,14 +331,12 @@ bool GameState::autoMoveColumnCard(int columnId, int cardIndex) {
|
|||
ensureColumnRevealed(columnId);
|
||||
qDebug() << "> Moving complete";
|
||||
|
||||
// Columns always change, we're moving from them, if the move is to another column
|
||||
// that's all, if it's to a foundation, also emit foundation change
|
||||
emit columnsChanged();
|
||||
if (changed.value().destinationType == AutoMoveResult::DestinationType::Foundation) {
|
||||
increaseScore(10); // Score increase for moving to foundation
|
||||
emit foundationChanged();
|
||||
}
|
||||
|
||||
// we don't know where the card was moved, it could've been the foundation too
|
||||
// to be safe, emit a change signal for it too
|
||||
// NOTE: consider returning what changed from tryAutoMoveSingleCard
|
||||
emit foundationChanged();
|
||||
incrementMoveAmt();
|
||||
|
||||
return true;
|
||||
|
@ -365,7 +350,7 @@ bool GameState::autoMoveColumnCard(int columnId, int cardIndex) {
|
|||
selectedCards.append(curCol->card());
|
||||
}
|
||||
|
||||
if (!tryAutoMoveMultipleCards(selectedCards, columnId).has_value()) {
|
||||
if (!tryAutoMoveMultipleCards(selectedCards, columnId)) {
|
||||
qDebug() << "> Moving failed, no available move found";
|
||||
return false;
|
||||
}
|
||||
|
@ -430,7 +415,6 @@ GameState* GameState::clone(bool enableWinnabilitySim) const {
|
|||
|
||||
newGameState->m_gameWon = m_gameWon;
|
||||
newGameState->m_prelimWin = m_prelimWin;
|
||||
newGameState->m_score = m_score;
|
||||
|
||||
assert(this->generateStateHash() == newGameState->generateStateHash());
|
||||
return newGameState;
|
||||
|
@ -468,7 +452,6 @@ void GameState::cleanupBoard(bool emitChanges) {
|
|||
}
|
||||
|
||||
m_moveAmt = 0;
|
||||
m_score = 0;
|
||||
|
||||
// Note that we don't need to reset gameWon/prelimWin from here, as it's
|
||||
// auto-checked from onFoundationChanged, which the emits trigger. Similarly
|
||||
|
@ -529,13 +512,13 @@ QString GameState::generateStateHash() const {
|
|||
return stateHash;
|
||||
}
|
||||
|
||||
std::optional<GameState::AutoMoveResult> GameState::tryAutoMoveSingleCard(PlayingCard& cardToMove, int skipColumnId) {
|
||||
bool GameState::tryAutoMoveSingleCard(PlayingCard& cardToMove, int skipColumnId) {
|
||||
// 1. Try moving the card to the foundation
|
||||
const int foundationId = static_cast<int>(cardToMove.suit());
|
||||
if (isFoundationMoveValid(cardToMove, foundationId)) {
|
||||
m_foundation[foundationId].prepend(&cardToMove);
|
||||
qDebug() << "* Auto-moved card " << cardToMove.toString() << " to foundation " << foundationId;
|
||||
return AutoMoveResult{AutoMoveResult::DestinationType::Foundation, foundationId};
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. Try moving the card to another column
|
||||
|
@ -547,16 +530,16 @@ std::optional<GameState::AutoMoveResult> GameState::tryAutoMoveSingleCard(Playin
|
|||
ColumnSlot* col = new ColumnSlot(&cardToMove, true, this);
|
||||
m_columns[columnId].append(col);
|
||||
qDebug() << "* Auto-moved card " << cardToMove.toString() << " to column " << columnId;
|
||||
return AutoMoveResult{AutoMoveResult::DestinationType::Column, columnId};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// No available auto-move
|
||||
qDebug() << "* Auto-move failed, no available moves";
|
||||
return std::nullopt;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<GameState::AutoMoveResult> GameState::tryAutoMoveMultipleCards(const QList<PlayingCard*>& cards, int skipColumnId) {
|
||||
bool GameState::tryAutoMoveMultipleCards(const QList<PlayingCard*>& cards, int skipColumnId) {
|
||||
assert(cards.size() > 1);
|
||||
|
||||
// If we can move the first (selected) card to another column,
|
||||
|
@ -576,12 +559,12 @@ std::optional<GameState::AutoMoveResult> GameState::tryAutoMoveMultipleCards(con
|
|||
m_columns[columnId].append(col);
|
||||
qDebug() << "* Auto-moved card " << card->toString() << " to column " << columnId;
|
||||
}
|
||||
return AutoMoveResult{AutoMoveResult::DestinationType::Column, columnId};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "* Auto-move failed, no available moves";
|
||||
return std::nullopt;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GameState::isFoundationMoveValid(const PlayingCard& cardToMove, int foundationId) const {
|
||||
|
@ -651,7 +634,6 @@ void GameState::ensureColumnRevealed(int columnId) {
|
|||
|
||||
// First slot in the column must always be revealed, reveal it
|
||||
col->reveal();
|
||||
increaseScore(5); // Score increase for revealing a card
|
||||
qDebug() << "Revealed card " << col->card()->toString() << " in column " << columnId;
|
||||
}
|
||||
|
||||
|
@ -660,11 +642,6 @@ void GameState::incrementMoveAmt() {
|
|||
emit moveAmountChanged();
|
||||
}
|
||||
|
||||
void GameState::increaseScore(int amount) {
|
||||
m_score += amount;
|
||||
emit scoreChanged();
|
||||
}
|
||||
|
||||
bool GameState::prelimWinCheck() {
|
||||
// Check if the game is preliminarily won:
|
||||
// This occurs when all cards in the tableau are revealed.
|
||||
|
@ -926,10 +903,6 @@ QVariant GameState::isWinnable() const {
|
|||
return map;
|
||||
}
|
||||
|
||||
int GameState::score() const {
|
||||
return m_score;
|
||||
}
|
||||
|
||||
std::pair<std::optional<bool>, int> GameState::checkWinnable() {
|
||||
if (!m_enableWinnabilitySim)
|
||||
return {std::nullopt, 0};
|
||||
|
|
|
@ -27,7 +27,6 @@ class GameState : public QObject {
|
|||
Q_PROPERTY(bool gameWon READ gameWon NOTIFY gameWonChanged)
|
||||
Q_PROPERTY(bool preliminaryWin READ preliminaryWin NOTIFY preliminaryWinChanged)
|
||||
Q_PROPERTY(QVariant isWinnable READ isWinnable NOTIFY isWinnableChanged)
|
||||
Q_PROPERTY(int score READ score NOTIFY scoreChanged)
|
||||
|
||||
public:
|
||||
explicit GameState(QObject* parent = nullptr, bool preDealCards = true, bool enableWinnabilitySim = true);
|
||||
|
@ -42,7 +41,6 @@ class GameState : public QObject {
|
|||
bool preliminaryWin() const;
|
||||
bool gameWon() const;
|
||||
QVariant isWinnable() const;
|
||||
int score() const;
|
||||
|
||||
// General functions
|
||||
Q_INVOKABLE void dealCards();
|
||||
|
@ -68,7 +66,6 @@ class GameState : public QObject {
|
|||
void gameWonChanged();
|
||||
void preliminaryWinChanged();
|
||||
void isWinnableChanged();
|
||||
void scoreChanged();
|
||||
|
||||
private slots:
|
||||
void onFoundationChanged();
|
||||
|
@ -85,30 +82,19 @@ class GameState : public QObject {
|
|||
bool m_prelimWin;
|
||||
std::pair<std::optional<bool>, int> m_isWinnable;
|
||||
bool m_enableWinnabilitySim;
|
||||
int m_score;
|
||||
|
||||
struct AutoMoveResult {
|
||||
enum class DestinationType {
|
||||
Foundation,
|
||||
Column
|
||||
};
|
||||
DestinationType destinationType;
|
||||
int destinationId;
|
||||
};
|
||||
|
||||
GameState* clone(bool enableWinnabilitySim = false) const;
|
||||
void cleanupBoard(bool emitChanges);
|
||||
QString generateStateHash() const;
|
||||
|
||||
std::optional<AutoMoveResult> tryAutoMoveSingleCard(PlayingCard& cardToMove, int skipColumnId = -1);
|
||||
std::optional<AutoMoveResult> tryAutoMoveMultipleCards(const QList<PlayingCard*>& cards, int skipColumnId);
|
||||
bool tryAutoMoveSingleCard(PlayingCard& cardToMove, int skipColumnId = -1);
|
||||
bool tryAutoMoveMultipleCards(const QList<PlayingCard*>& cards, int skipColumnId);
|
||||
|
||||
bool isFoundationMoveValid(const PlayingCard& cardToMove, int foundationId) const;
|
||||
bool isColumnMoveValid(const PlayingCard& cardToMove, int columnId) const;
|
||||
|
||||
void ensureColumnRevealed(int columnId);
|
||||
void incrementMoveAmt();
|
||||
void increaseScore(int amount);
|
||||
|
||||
bool winCheck();
|
||||
bool prelimWinCheck();
|
||||
|
|
Loading…
Reference in a new issue