Rework various gamestate methods
This commit is contained in:
parent
4ea9a04836
commit
4dbcd700c0
301
gamestate.cpp
301
gamestate.cpp
|
@ -5,15 +5,8 @@
|
||||||
GameState::GameState(QObject *parent)
|
GameState::GameState(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
{
|
{
|
||||||
// Initialize the foundation piles (4 suits)
|
m_foundation.resize(4);
|
||||||
for (int i = 0; i < 4; ++i) {
|
m_columns.resize(7);
|
||||||
m_foundation.append(QList<PlayingCard*>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the columns (7 piles)
|
|
||||||
for (int i = 0; i < 7; ++i) {
|
|
||||||
m_columns.append(QList<ColumnSlot*>());
|
|
||||||
}
|
|
||||||
|
|
||||||
dealCards();
|
dealCards();
|
||||||
}
|
}
|
||||||
|
@ -46,6 +39,7 @@ void GameState::dealCards()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the remaining cards as the draw pile
|
// Use the remaining cards as the draw pile
|
||||||
|
assert(index == 28);
|
||||||
m_drawPile = deck.mid(index);
|
m_drawPile = deck.mid(index);
|
||||||
|
|
||||||
// Reset the foundation & throwaway pile
|
// Reset the foundation & throwaway pile
|
||||||
|
@ -86,9 +80,10 @@ void GameState::drawNextCard()
|
||||||
emit throwawayPileChanged();
|
emit throwawayPileChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameState::moveCardToColumn(int columnId)
|
bool GameState::moveThrownCardToColumn(int columnId)
|
||||||
{
|
{
|
||||||
assert(columnId >= 0 && columnId < 7);
|
assert(columnId >= 0 && columnId < 7);
|
||||||
|
auto columnStack = m_columns[columnId];
|
||||||
|
|
||||||
if (m_throwawayPile.isEmpty()) {
|
if (m_throwawayPile.isEmpty()) {
|
||||||
qWarning() << "Attempted to move thrown card to column with empty throwaway pile";
|
qWarning() << "Attempted to move thrown card to column with empty throwaway pile";
|
||||||
|
@ -96,18 +91,18 @@ bool GameState::moveCardToColumn(int columnId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll be moving the last card in the throwaway pile (maybe)
|
// We'll be moving the last card in the throwaway pile (maybe)
|
||||||
PlayingCard *cardToMove = m_throwawayPile.last();
|
PlayingCard* cardToMove = m_throwawayPile.last();
|
||||||
qDebug() << "Attempting to move thrown card " << cardToMove->toString() << " to column " << columnId;
|
qDebug() << "Attempting to move thrown card " << cardToMove->toString() << " to column " << columnId;
|
||||||
|
|
||||||
if (!isMoveToColumnLegal(cardToMove, columnId)) {
|
if (!isColumnMoveValid(*cardToMove, columnId)) {
|
||||||
qDebug() << "> Moving aborted, illegal move";
|
qDebug() << "> Moving aborted, illegal move";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnSlot *col = new ColumnSlot(cardToMove, true);
|
// Success, perform the move
|
||||||
m_columns[columnId].append(col);
|
ColumnSlot* col = new ColumnSlot(cardToMove, true);
|
||||||
|
columnStack.append(col);
|
||||||
m_throwawayPile.removeLast();
|
m_throwawayPile.removeLast();
|
||||||
ensureColumnRevealed(columnId);
|
|
||||||
qDebug() << "> Moving complete";
|
qDebug() << "> Moving complete";
|
||||||
|
|
||||||
emit throwawayPileChanged();
|
emit throwawayPileChanged();
|
||||||
|
@ -115,35 +110,79 @@ bool GameState::moveCardToColumn(int columnId)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameState::moveThrownCardToFoundation(PlayingCard::Suit foundationId)
|
bool GameState::moveThrownCardToFoundation(int foundationId)
|
||||||
{
|
{
|
||||||
|
assert(foundationId >= 0 && foundationId < 4);
|
||||||
|
auto foundationStack = m_foundation[foundationId];
|
||||||
|
|
||||||
if (m_throwawayPile.isEmpty()) {
|
if (m_throwawayPile.isEmpty()) {
|
||||||
qWarning() << "Attempted to move thrown card to foundation with empty throwaway pile";
|
qWarning() << "Attempted to move thrown card to foundation with empty throwaway pile";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll be moving the last card in the foundation pile (maybe)
|
// We'll be moving the last card in the foundation pile (maybe)
|
||||||
PlayingCard *cardToMove = m_throwawayPile.last();
|
PlayingCard* cardToMove = m_throwawayPile.last();
|
||||||
qDebug() << "Attempting to move thrown card " << cardToMove->toString() << " to foundation " << foundationId;
|
qDebug() << "Attempting to move thrown card " << cardToMove->toString() << " to foundation " << foundationId;
|
||||||
|
|
||||||
// Try moving the card into the foundation
|
// Try moving the card into the foundation
|
||||||
if (!tryMoveCardToFoundation(foundationId, cardToMove)) {
|
if (!isFoundationMoveValid(*cardToMove, foundationId)) {
|
||||||
qDebug() << "> Moving aborted, illegal move";
|
qDebug() << "> Moving aborted, illegal move";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We succeeded, the card is now in the appropriate foundation pile,
|
// Succeess, perform the move
|
||||||
// let's remove the card from the throwaway pile.
|
foundationStack.prepend(cardToMove);
|
||||||
m_throwawayPile.removeLast();
|
m_throwawayPile.removeLast();
|
||||||
qDebug() << "> Moving complete";
|
qDebug() << "> Moving complete";
|
||||||
|
|
||||||
emit throwawayPileChanged();
|
emit throwawayPileChanged();
|
||||||
|
emit foundationChanged();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameState::moveColumnCardToFoundation(int columnId, PlayingCard::Suit foundationId)
|
bool GameState::moveColumnCardToColumn(int fromColumnId, int toColumnId, int fromCardIndex)
|
||||||
|
{
|
||||||
|
assert(fromColumnId >= 0 && fromColumnId < 7);
|
||||||
|
assert(toColumnId >= 0 && toColumnId < 7);
|
||||||
|
auto fromColumnStack = m_columns[fromColumnId];
|
||||||
|
auto toColumnStack = m_columns[toColumnId];
|
||||||
|
|
||||||
|
if (fromColumnStack.isEmpty()) {
|
||||||
|
qWarning() << "Attempted to move card(s) to column from an empty column";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnSlot* col = fromColumnStack[fromCardIndex];
|
||||||
|
if (!col->isRevealed()) {
|
||||||
|
qWarning() << "Attempted to card(s) to column from unrevealed column slot";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayingCard* cardToMove = col->card();
|
||||||
|
qDebug() << "Attempting to move card " << cardToMove->toString() << " from column " << fromColumnId << " to column " << toColumnId;
|
||||||
|
|
||||||
|
// Try moving the card
|
||||||
|
if (!isColumnMoveValid(*cardToMove, toColumnId)) {
|
||||||
|
qDebug() << "> Moving aborted, illegal move";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success, move the card
|
||||||
|
toColumnStack.append(col);
|
||||||
|
fromColumnStack.removeLast();
|
||||||
|
ensureColumnRevealed(fromColumnId);
|
||||||
|
qDebug() << "> Moving complete";
|
||||||
|
|
||||||
|
emit columnsChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameState::moveColumnCardToFoundation(int columnId, int foundationId)
|
||||||
{
|
{
|
||||||
assert(columnId >= 0 && columnId < 7);
|
assert(columnId >= 0 && columnId < 7);
|
||||||
|
assert(foundationId >= 0 && foundationId < 4);
|
||||||
|
auto columnStack = m_columns[columnId];
|
||||||
|
auto foundationStack = m_foundation[foundationId];
|
||||||
|
|
||||||
if (m_columns[columnId].isEmpty()) {
|
if (m_columns[columnId].isEmpty()) {
|
||||||
qWarning() << "Attempted to move card to foundation from an empty column";
|
qWarning() << "Attempted to move card to foundation from an empty column";
|
||||||
|
@ -151,83 +190,122 @@ bool GameState::moveColumnCardToFoundation(int columnId, PlayingCard::Suit found
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll be moving the last card in the column (maybe)
|
// We'll be moving the last card in the column (maybe)
|
||||||
PlayingCard *cardToMove = m_columns[columnId].last()->card();
|
ColumnSlot* col = columnStack.last();
|
||||||
|
PlayingCard* cardToMove = col->card();
|
||||||
qDebug() << "Attempting to move card " << cardToMove->toString() << " from column " << columnId << " to foundation " << foundationId;
|
qDebug() << "Attempting to move card " << cardToMove->toString() << " from column " << columnId << " to foundation " << foundationId;
|
||||||
|
|
||||||
// Try moving the card into the foundation
|
// Try moving the card into the foundation
|
||||||
if (!tryMoveCardToFoundation(foundationId, cardToMove)) {
|
if (!isFoundationMoveValid(*cardToMove, foundationId)) {
|
||||||
qDebug() << "> Moving aborted, illegal move";
|
qDebug() << "> Moving aborted, illegal move";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We succeeded, the card is now in the appropriate foundation pile,
|
// Success, move the card
|
||||||
// let's remove the column slot.
|
foundationStack.prepend(cardToMove);
|
||||||
m_columns[columnId].removeLast();
|
columnStack.removeLast();
|
||||||
|
col->deleteLater();
|
||||||
ensureColumnRevealed(columnId);
|
ensureColumnRevealed(columnId);
|
||||||
qDebug() << "> Moving complete";
|
qDebug() << "> Moving complete";
|
||||||
|
|
||||||
emit columnsChanged();
|
emit columnsChanged(); // CRASH (not if I remove the delete col line though)
|
||||||
|
emit foundationChanged();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameState::autoMoveThrownCard()
|
bool GameState::autoMoveThrownCard()
|
||||||
{
|
{
|
||||||
// NOTE: This method is very similar to moveThrownCardToFoundation,
|
|
||||||
// consider reducing the repetitino here somehow.
|
|
||||||
|
|
||||||
if (m_throwawayPile.isEmpty()) {
|
if (m_throwawayPile.isEmpty()) {
|
||||||
// Consider raising an exception here instead
|
|
||||||
qWarning() << "Attempted to move thrown card to foundation with empty throwaway pile";
|
qWarning() << "Attempted to move thrown card to foundation with empty throwaway pile";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll be moving the last card in the foundation pile (maybe)
|
// We'll be moving the last card in the foundation pile (maybe)
|
||||||
PlayingCard *cardToMove = m_throwawayPile.last();
|
PlayingCard* cardToMove = m_throwawayPile.last();
|
||||||
qDebug() << "Attempting auto-move of thrown card " << cardToMove->toString();
|
qDebug() << "Attempting auto-move of thrown card " << cardToMove->toString();
|
||||||
|
|
||||||
// Try moving the card into the foundation
|
// Try moving the card into the foundation
|
||||||
if (!tryAutoMoveCard(cardToMove)) {
|
if (!tryAutoMoveSingleCard(*cardToMove)) {
|
||||||
qDebug() << "> Moving failed, no available move found";
|
qDebug() << "> Moving failed, no available move found";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We succeeded, the card is now in the appropriate foundation pile,
|
// We succeeded, the card was moved, remove it from throwaway pile
|
||||||
// let's remove the card from the throwaway pile.
|
|
||||||
m_throwawayPile.removeLast();
|
m_throwawayPile.removeLast();
|
||||||
qDebug() << "> Moving complete";
|
qDebug() << "> Moving complete";
|
||||||
|
|
||||||
emit throwawayPileChanged();
|
emit throwawayPileChanged();
|
||||||
|
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameState::autoMoveColumnCard(int columnId)
|
bool GameState::autoMoveColumnCard(int columnId, int cardIndex)
|
||||||
{
|
{
|
||||||
// NOTE: This method is very similar to moveColumnCardToFoundation,
|
|
||||||
// consider reducing the repetitino here somehow.
|
|
||||||
|
|
||||||
assert(columnId >= 0 && columnId < 7);
|
assert(columnId >= 0 && columnId < 7);
|
||||||
|
auto columnStack = m_columns[columnId];
|
||||||
|
|
||||||
if (m_columns[columnId].isEmpty()) {
|
if (columnStack.isEmpty()) {
|
||||||
// Consider raising an exception here instead
|
qWarning() << "Attempted to move card(s) to foundation from an empty column";
|
||||||
qWarning() << "Attempted to move card to foundation from an empty column";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll be moving the last card in the column (maybe)
|
ColumnSlot* col = columnStack[cardIndex];
|
||||||
PlayingCard *cardToMove = m_columns[columnId].last()->card();
|
if (!col->isRevealed()) {
|
||||||
qDebug() << "Attempting auto-move of column card " << cardToMove->toString();
|
qWarning() << "Attempted to card(s) to column from unrevealed column slot";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tryAutoMoveCard(cardToMove)) {
|
if (cardIndex == columnStack.size() - 1) {
|
||||||
|
// This is a single card move (last card)
|
||||||
|
PlayingCard* cardToMove = col->card();
|
||||||
|
qDebug() << "Attempting auto-move of column " << columnId << " card " << cardToMove->toString();
|
||||||
|
if (!tryAutoMoveSingleCard(*cardToMove, columnId)) {
|
||||||
|
qDebug() << "> Moving failed, no available move found";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We succeeded, the card was moved, remove it from the original column
|
||||||
|
columnStack.removeLast();
|
||||||
|
col->deleteLater();
|
||||||
|
ensureColumnRevealed(columnId);
|
||||||
|
qDebug() << "> Moving complete";
|
||||||
|
|
||||||
|
emit columnsChanged();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a multiple cards move
|
||||||
|
qDebug() << "Attempting auto-move of column " << columnId << " card range " << cardIndex << " to " << columnStack.size() - 1;
|
||||||
|
QList<PlayingCard*> selectedCards;
|
||||||
|
for (int i = cardIndex; i < m_columns.size(); ++i) {
|
||||||
|
ColumnSlot* col = columnStack[i];
|
||||||
|
selectedCards.append(col->card());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tryAutoMoveMultipleCards(selectedCards, cardIndex)) {
|
||||||
qDebug() << "> Moving failed, no available move found";
|
qDebug() << "> Moving failed, no available move found";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We succeeded, the card is now in the appropriate foundation pile,
|
// We succeeded, the cards were moved,
|
||||||
// let's remove the column slot.
|
// now remove the moved cards from the column
|
||||||
m_columns[columnId].removeLast();
|
while (columnStack.size() > cardIndex) {
|
||||||
ensureColumnRevealed(columnId);
|
ColumnSlot* curSlot = columnStack.takeLast();
|
||||||
qDebug() << "> Moving complete";
|
curSlot->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
emit columnsChanged();
|
emit columnsChanged();
|
||||||
return true;
|
return true;
|
||||||
|
@ -255,26 +333,82 @@ void GameState::onFoundationChanged()
|
||||||
emit gameWonChanged();
|
emit gameWonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameState::tryMoveCardToFoundation(PlayingCard::Suit foundationId, PlayingCard* cardToMove)
|
bool GameState::tryAutoMoveSingleCard(PlayingCard &cardToMove, int skipColumnId)
|
||||||
{
|
{
|
||||||
assert(foundationId >= PlayingCard::Suit::Clubs && foundationId <= PlayingCard::Suit::Spades);
|
// 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 true;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "* Trying to move card " << cardToMove->toString() << " to foundation " << foundationId;
|
// 2. Try moving the card to another column
|
||||||
|
for (int columnId = 0; columnId < m_columns.size(); ++columnId) {
|
||||||
|
if (columnId == skipColumnId)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (cardToMove->suit() != foundationId) {
|
if (isColumnMoveValid(cardToMove, columnId)) {
|
||||||
qDebug() << "* Move attempt failed (wrong suit)";
|
ColumnSlot* col = new ColumnSlot(&cardToMove, true);
|
||||||
|
m_columns[columnId].append(col);
|
||||||
|
qDebug() << "* Auto-moved card " << cardToMove.toString() << " to column " << columnId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No available auto-move
|
||||||
|
qDebug() << "* Auto-move failed, no available moves";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameState::tryAutoMoveMultipleCards(const QList<PlayingCard*>& cards, int skipColumnId)
|
||||||
|
{
|
||||||
|
assert(cards.size() > 1);
|
||||||
|
|
||||||
|
// If we can move the first (selected) card to another column,
|
||||||
|
// we can also move the rest of the cards below to that column,
|
||||||
|
// so we only need to care about the first card.
|
||||||
|
// (Foundation moves are impossible with multiple card movements).
|
||||||
|
|
||||||
|
PlayingCard* firstCard = cards.first();
|
||||||
|
|
||||||
|
for (int columnId = 0; columnId < m_columns.size(); ++columnId) {
|
||||||
|
if (columnId == skipColumnId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (isColumnMoveValid(*firstCard, columnId)) {
|
||||||
|
for (auto card : cards) {
|
||||||
|
ColumnSlot* col = new ColumnSlot(card, true);
|
||||||
|
m_columns[columnId].append(col);
|
||||||
|
qDebug() << "* Auto-moved card " << card->toString() << " to column " << columnId;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "* Auto-move failed, no available moves";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameState::isFoundationMoveValid(const PlayingCard& cardToMove, int foundationId)
|
||||||
|
{
|
||||||
|
assert(foundationId >= 0 && foundationId < 4);
|
||||||
|
const auto foundationSuit = static_cast<PlayingCard::Suit>(foundationId);
|
||||||
|
const auto foundationStack = m_foundation[foundationId];
|
||||||
|
|
||||||
|
// The card must match the suit of the foundation
|
||||||
|
if (cardToMove.suit() != foundationSuit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayingCard::Value requiredValue;
|
PlayingCard::Value requiredValue;
|
||||||
if (m_foundation[foundationId].isEmpty()) {
|
if (foundationStack.isEmpty()) {
|
||||||
// If the pile is empty, only an ace can go in
|
// If the pile is empty, only an ace can go in
|
||||||
requiredValue = PlayingCard::Value::Ace;
|
requiredValue = PlayingCard::Value::Ace;
|
||||||
} else {
|
} else {
|
||||||
// Otherwise it's the next card by value, unless we're already at king
|
// Otherwise it's the next card by value, unless we're already at king
|
||||||
PlayingCard::Value curValue = m_foundation[foundationId].first()->value();
|
PlayingCard::Value curValue = foundationStack.first()->value();
|
||||||
if (curValue == PlayingCard::Value::King) {
|
if (curValue == PlayingCard::Value::King) {
|
||||||
qDebug() << "* Move attempt failed (expected King)";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,59 +417,32 @@ bool GameState::tryMoveCardToFoundation(PlayingCard::Suit foundationId, PlayingC
|
||||||
requiredValue = static_cast<PlayingCard::Value>(static_cast<int>(curValue) + 1);
|
requiredValue = static_cast<PlayingCard::Value>(static_cast<int>(curValue) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cardToMove->value() != requiredValue) {
|
return cardToMove.value() == requiredValue;
|
||||||
qDebug() << "* Move attempt failed (expected value: " << requiredValue << ")";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_foundation[foundationId].push_front(cardToMove);
|
|
||||||
qDebug() << "* Moved card " << cardToMove->toString() << " to foundation " << foundationId;
|
|
||||||
|
|
||||||
emit foundationChanged();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameState::tryAutoMoveCard(PlayingCard *cardToMove)
|
bool GameState::isColumnMoveValid(const PlayingCard& cardToMove, int columnId) {
|
||||||
{
|
|
||||||
// 1. Try moving the card to the foundation
|
|
||||||
for (PlayingCard::Suit suit : {PlayingCard::Suit::Clubs, PlayingCard::Suit::Diamonds, PlayingCard::Suit::Hearts, PlayingCard::Suit::Spades})
|
|
||||||
if (cardToMove->suit() == suit && tryMoveCardToFoundation(suit, cardToMove)) {
|
|
||||||
qDebug() << "* Auto-moved card " << cardToMove->toString() << " to foundation " << suit;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Try moving the card to another column
|
|
||||||
for (int columnId = 0; columnId < m_columns.size(); ++columnId)
|
|
||||||
if (isMoveToColumnLegal(cardToMove, columnId)) {
|
|
||||||
moveCardToColumn(columnId);
|
|
||||||
qDebug() << "* Auto-moved card " << cardToMove->toString() << " to column " << columnId;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No available auto-move
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GameState::isMoveToColumnLegal(PlayingCard *cardToMove, int columnId)
|
|
||||||
{
|
|
||||||
assert(columnId >= 0 && columnId < 7);
|
assert(columnId >= 0 && columnId < 7);
|
||||||
|
const auto columnStack = m_columns[columnId];
|
||||||
|
|
||||||
if (m_columns[columnId].isEmpty()) {
|
if (columnStack.isEmpty()) {
|
||||||
// Column is empty: only a King can be placed in an empty column
|
// Column is empty: only a King can be placed in an empty column
|
||||||
return cardToMove->value() == PlayingCard::Value::King;
|
return cardToMove.value() == PlayingCard::Value::King;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare against the last card in the column
|
// Compare against the last card in the column
|
||||||
PlayingCard* columnCard = m_columns[columnId].last()->card();
|
const PlayingCard& columnCard = *columnStack.last()->card();
|
||||||
|
|
||||||
// The card's value must be one less than the card in the column
|
// The card's value must be one less than the card in the column
|
||||||
if (cardToMove->value() != columnCard->value() - 1)
|
if (cardToMove.value() != columnCard.value() - 1) {
|
||||||
|
qDebug() << "* Move attempt failed (wrong value)";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// The card must be of opposite color
|
// The card must be of opposite color
|
||||||
return PlayingCard::areOppositeColors(*cardToMove, *columnCard);
|
return PlayingCard::areOppositeColors(cardToMove, columnCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GameState::ensureColumnRevealed(int columnId)
|
void GameState::ensureColumnRevealed(int columnId)
|
||||||
{
|
{
|
||||||
assert(columnId >= 0 && columnId < 7);
|
assert(columnId >= 0 && columnId < 7);
|
||||||
|
|
24
gamestate.h
24
gamestate.h
|
@ -28,17 +28,18 @@ public:
|
||||||
bool gameWon() const;
|
bool gameWon() const;
|
||||||
|
|
||||||
// General functions
|
// General functions
|
||||||
void dealCards();
|
Q_INVOKABLE void dealCards();
|
||||||
void drawNextCard();
|
Q_INVOKABLE void drawNextCard();
|
||||||
|
|
||||||
// Manual moves (from X to Y)
|
// Manual moves (from X to Y)
|
||||||
bool moveCardToColumn(int columnId);
|
Q_INVOKABLE bool moveThrownCardToColumn(int columnId);
|
||||||
bool moveThrownCardToFoundation(PlayingCard::Suit foundationId);
|
Q_INVOKABLE bool moveThrownCardToFoundation(int foundationId);
|
||||||
bool moveColumnCardToFoundation(int columnId, PlayingCard::Suit foundationId);
|
Q_INVOKABLE bool moveColumnCardToColumn(int fromColumnId, int toColumnId, int fromCardIndex);
|
||||||
|
Q_INVOKABLE bool moveColumnCardToFoundation(int columnId, int foundationId);
|
||||||
|
|
||||||
// Automatic moves (from X to auto)
|
// Automatic moves (from X to auto)
|
||||||
bool autoMoveThrownCard();
|
Q_INVOKABLE bool autoMoveThrownCard();
|
||||||
bool autoMoveColumnCard(int columnId);
|
Q_INVOKABLE bool autoMoveColumnCard(int columnId, int cardIndex);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void drawPileChanged();
|
void drawPileChanged();
|
||||||
|
@ -57,9 +58,12 @@ private:
|
||||||
QList<QList<PlayingCard*>> m_foundation;
|
QList<QList<PlayingCard*>> m_foundation;
|
||||||
bool m_gameWon;
|
bool m_gameWon;
|
||||||
|
|
||||||
bool tryMoveCardToFoundation(PlayingCard::Suit foundationId, PlayingCard* cardToMove);
|
bool tryAutoMoveSingleCard(PlayingCard& cardToMove, int skipColumnId = -1);
|
||||||
bool tryAutoMoveCard(PlayingCard* cardToMove);
|
bool tryAutoMoveMultipleCards(const QList<PlayingCard*>& cards, int skipColumnId);
|
||||||
bool isMoveToColumnLegal(PlayingCard* cardToMove, int columnId);
|
|
||||||
|
bool isFoundationMoveValid(const PlayingCard& cardToMove, int foundationId);
|
||||||
|
bool isColumnMoveValid(const PlayingCard& cardToMove, int columnId);
|
||||||
|
|
||||||
void ensureColumnRevealed(int columnId);
|
void ensureColumnRevealed(int columnId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue