/* * Spider-Arachnid: A plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * * $Id: heap.c 2 2005-05-14 22:25:56Z tom $ */ #include "heap.h" #include "deck.h" /** --- base class Heap ---------------------------------------------------- **/ /** Constructor */ Heap::Heap(unsigned int maxCards) { maxCount = maxCards; emptyChanged = true; } /** Destructor */ Heap::~Heap() { } /** Current count of cards */ int Heap::count() const { return allCards.size(); } /** Card in heap */ const Card& Heap::card(int position) const { return allCards[position]; } /** Top card of the heap */ const Card& Heap::top() const { return allCards.back(); } /** Add a new card */ void Heap::add(const Card& card) { if (allCards.size() < maxCount) { if (allCards.empty()) emptyChanged = true; allCards.push_back(card); } } /** Remove the top card */ void Heap::remove() { if (!allCards.empty()) { allCards.pop_back(); if (allCards.empty()) emptyChanged = true; } } /** Move some matching cards to an other heap */ void Heap::moveTo(Heap* other, int countToMove) { for (int i = count() - countToMove; i < count(); ++i) other->add(card(i)); for (int i = 0; i < countToMove; ++i) remove(); } /** Is the heap empty? */ bool Heap::empty() const { return allCards.empty(); } /** Is the heap changed? */ bool Heap::changed() const { return emptyChanged; } /** Reset changed property */ void Heap::resetChanged() { emptyChanged = false; } /** --- class Pack --------------------------------------------------------- **/ /** Constructor */ Pack::Pack(const Deck& deck) : Heap(deck.count()) { for (int pos = 0; pos < deck.count(); ++pos) add(deck.card(pos)); } /** First initial deal of a game */ void Pack::initialDeal(Piles& piles, int rows, Piles& extra) { for (int r = 0; r < rows; ++r) deal(piles); deal(extra); // turn all open cards for (unsigned int p = 0; p < piles.size(); ++p) piles[p]->turn(); } /** Deal one row to the piles */ void Pack::deal(Piles& piles) { for (unsigned int p = 0; p < piles.size(); ++p) { piles[p]->add(top()); remove(); } } /** Cancel the deal */ void Pack::takeBackDeal(Piles& piles) { for (int p = piles.size(); --p >= 0; ) { add(piles[p]->top()); piles[p]->remove(); } } /** --- class Pile --------------------------------------------------------- **/ /** Constructor */ Pile::Pile(const Deck& deck) : Heap(deck.count()) { currentOpen = 0; currentMatching = 0; currentSelected = 0; currentChanged = 0; } /** Add a new card */ void Pile::add(const Card& card) { Heap::add(card); ++currentOpen; if (topCardsMatches()) ++currentMatching; currentSelected = 0; ++currentChanged; } /** Remove top card from pile */ void Pile::remove() { if (currentSelected > 0) --currentSelected; if (topCardsMatches()) --currentMatching; if (currentOpen > 0) --currentOpen; Heap::remove(); if (currentChanged > 0) --currentChanged; if (currentChanged < 1 && !empty()) currentChanged = 1; } /** Turn all open top cards or rather open the top card */ void Pile::turn() { if (currentOpen < 1 && !empty()) currentOpen = 1; else currentOpen = 0; currentMatching = 0; if (currentChanged < 1 && !empty()) currentChanged = 1; } /** Current count of open cards */ int Pile::open() const { return currentOpen; } /** Current count of matching cards */ int Pile::getMatching() const { return currentMatching; } /** The two open top cards are matching */ bool Pile::topCardsMatches() const { return (open() >= 2 && card(count() - 1).matchesTo(card(count() - 2))); } /** Current count of selected cards */ int Pile::selected() const { return currentSelected; } /** Select up to max matching cards on the end of this pile */ void Pile::select(int max) { currentSelected = 0; if (open() > 0) { currentSelected = 1; for (int i = count(); --i > count() - open(); ) if (card(i).matchesTo(card(i - 1))) currentSelected++; else break; } if (currentSelected > max && max > 0) currentSelected = max; if (currentChanged < currentSelected) currentChanged = currentSelected; } /** Unselect this pile */ void Pile::unselect() { if (currentChanged < currentSelected) currentChanged = currentSelected; currentSelected = 0; } /** Adapt the selection to match an other pile */ void Pile::adaptSelectionTo(const Pile* other) { if (!other->empty()) { if (currentChanged < currentSelected) currentChanged = currentSelected; int diff = other->top().rank - top().rank; if (diff > 0 && diff <= currentSelected) currentSelected = diff; else currentSelected = 0; } } /** Matches the selection to an other pile? */ bool Pile::selectionMatchesTo(const Pile* other, bool matchSuit) const { return (!other->empty() && (other->top().rank == top().rank + currentSelected) && (other->top().suit == top().suit || !matchSuit)); } /** Is the heap changed? */ bool Pile::changed() const { return (Heap::changed() || currentChanged > 0); } /** Reset changed property */ void Pile::resetChanged() { Heap::resetChanged(); currentChanged = 0; } /** How many cards are changed? */ int Pile::cardsChanged() const { return currentChanged; } /** --- class FinalHeap ---------------------------------------------------- **/ /** Constructor */ FinalHeap::FinalHeap(const Deck& deck) : Heap(deck.cardsInSuit) { bonus = false; } /** Set bonus of the final heap */ void FinalHeap::setBonus(bool newBonus) { bonus = newBonus; } /** Has this final heap bonus? */ bool FinalHeap::getBonus() const { return bonus; }