diff options
Diffstat (limited to 'tableau.c')
-rw-r--r-- | tableau.c | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/tableau.c b/tableau.c new file mode 100644 index 0000000..9160a8c --- /dev/null +++ b/tableau.c @@ -0,0 +1,301 @@ +/* + * Spider-Arachnid: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#include "tableau.h" +#include "deck.h" +#include "heap.h" +#include "history.h" + + +/** --- class Tableau ------------------------------------------------------ **/ + +/** Constructor */ +Tableau::Tableau(Deck& deck, int pileCount, int finalCount, int deals) : + dealCount(deals), deck(deck), piles(pileCount), finals(finalCount) +{ + cardsToOpen = deck.count() - (deals + 1) * pileCount; + for ( ; cardsToOpen < 0; cardsToOpen += pileCount) + --deals; + + pack = new Pack(deck); + for (unsigned int p = 0; p < piles.size(); ++p) + piles[p] = new Pile(deck); + for (unsigned int f = 0; f < finals.size(); ++f) + finals[f] = new FinalHeap(deck); + + history = new History(); + + // choice of piles for extra deal with remaining cards + Piles extra(cardsToOpen % pileCount); + if (!extra.empty()) + { + int extraMax = extra.size() - 1; + int pilesMax = piles.size() - 1; + for (int e = 0; e <= extraMax / 2; ++e) + { + int p = (e * pilesMax) / extraMax; + extra[e] = piles[p]; + extra[extraMax - e] = piles[pilesMax - p]; + } + } + + // deal cards to open + pack->initialDeal(piles, cardsToOpen / pileCount, extra); + + // deal one open row + pack->deal(piles); + + selected = 0; +} + +/** Destructor */ +Tableau::~Tableau() +{ + delete pack; + for (unsigned int p = 0; p < piles.size(); ++p) + delete piles[p]; + for (unsigned int f = 0; f < finals.size(); ++f) + delete finals[f]; + delete history; +} + +/** Current count of deals */ +int Tableau::deals() +{ + return dealCount - pack->count() / piles.size(); +} + +/** Current count of points */ +int Tableau::points() +{ + int openCard = 10; + int openPile = 15; + int matchingCard = 2; + int readyFinal = 50; + int bonusFinal = 2; + int bonusfreeFinals = 3; + + int points = openCard * cardsToOpen; + for (unsigned int p = 0; p < piles.size(); ++p) + { + if (piles[p]->count() > piles[p]->open()) + points -= openCard * (piles[p]->count() - piles[p]->open()); + else + points += openPile; + points += matchingCard * piles[p]->getMatching(); + } + int emptyFinals = 0; + int bonusFinals = 0; + for (unsigned int f = 0; f < finals.size(); ++f) + if (finals[f]->empty()) + ++emptyFinals; + else if (finals[f]->getBonus()) + ++bonusFinals; + points += readyFinal * (finals.size() - emptyFinals); + if (emptyFinals == 0 && bonusFinals > bonusfreeFinals) + points += bonusFinal * (bonusFinals - bonusfreeFinals); + return points; +} + +/** Is no pile empty? */ +bool Tableau::noPileEmpty() +{ + for (unsigned int p = 0; p < piles.size(); p++) + if (piles[p]->empty()) + return false; + return true; +} + +/** Matches all cards in all piles? */ +bool Tableau::allCardsMatches() +{ + for (unsigned int p = 0; p < piles.size(); ++p) + if (piles[p]->count() > piles[p]->open() || + piles[p]->count() > piles[p]->getMatching() * + deck.cardsInSuit / (deck.cardsInSuit - 1)) + return false; + return true; +} + +/** Is the game over? */ +bool Tableau::gameOver() +{ + for (unsigned int p = 0; p < piles.size(); p++) + if (!piles[p]->empty()) + return false; + return true; +} + +/** Select p-th pile by selecting up to max matching cards on its end */ +void Tableau::select(int p, int max) +{ + if (!piles[p]->empty()) + { + unselect(); + selected = piles[p]; + selected->select(max); + changed = true; + } +} + +/** Unselect the selected pile */ +void Tableau::unselect() +{ + if (selected) + { + selected->unselect(); + selected = 0; + } +} + +/** Move cards from selected pile to p-th pile */ +void Tableau::move(int p) +{ + selected->adaptSelectionTo(piles[p]); + int count = selected->selected(); + if (count > 0) + { + bool turn = (count == selected->open() && count < selected->count()); + history->add(new NormalMove(selected, piles[p], count, turn)); + history->current()->execute(); + } + unselect(); + changed = true; +} + +/** Search move from p-th pile to the next left pile, return destination */ +int Tableau::autoMoveLeft(int p) +{ + int i = -1; + if (!piles[p]->empty()) + { + if (selected != piles[p]) + select(p); + for (i = p - 1; i >= 0; --i) + if (piles[i]->empty() || selected->selectionMatchesTo(piles[i])) + break; + if (i >= 0) + move(i); + changed = true; + } + return i; +} + +/** Search move from p-th pile to the next right pile, return destination */ +int Tableau::autoMoveRight(int p) +{ + int i = -1; + if (!piles[p]->empty()) + { + if (selected != piles[p]) + select(p); + for (i = p + 1; i < (int)piles.size(); ++i) + if (piles[i]->empty() || selected->selectionMatchesTo(piles[i])) + break; + if (i < (int)piles.size()) + move(i); + else + i = -1; + changed = true; + } + return i; +} + +/** Search best move from p-th pile, return destination */ +int Tableau::autoMove(int p) +{ + int i = -1; + if (!piles[p]->empty()) + { + if (selected != piles[p]) + select(p); + if (allCardsMatches() && selected->selected() == deck.cardsInSuit) + remove(); + else + { + i = p; + while ((i = (i + 1) % piles.size()) != p) + if (selected->selectionMatchesTo(piles[i], true)) + break; + if (i == p) + while ((i = (i + 1) % piles.size()) != p) + if (selected->selectionMatchesTo(piles[i], false)) + break; + if (i == p) + while ((i = (i + 1) % piles.size()) != p) + if (piles[i]->empty()) + break; + if (i != p) + move(i); + else + i = -1; + } + } + return i; +} + +/** Deal one row */ +void Tableau::deal() +{ + if (!pack->empty() && noPileEmpty()) + { + history->add(new DealMove(pack, piles)); + history->current()->execute(); + + unselect(); + changed = true; + } +} + +/** Remove one suit of cards from selected pile to the final heaps */ +void Tableau::remove() +{ + int count = selected->selected(); + if (count == deck.cardsInSuit) + { + unsigned int f; + for (f = 0; f < finals.size(); ++f) + if (finals[f]->empty()) + break; + if (f < finals.size()) + { + bool turn = (count == selected->open() && count < selected->count()); + bool bonus = allCardsMatches(); + history->add(new FinalMove(selected, finals[f], count, turn, bonus)); + history->current()->execute(); + } + unselect(); + changed = true; + } +} + +/** Go one move backward in the history */ +void Tableau::backward() +{ + if (history->movesExecuted()) + { + history->current()->takeBack(); + history->backward(); + + unselect(); + changed = true; + } +} + +/** Go one move forward in the history */ +void Tableau::forward() +{ + if (history->movesToExecute()) + { + history->forward(); + history->current()->execute(); + + unselect(); + changed = true; + } +} |