Skip to content

Commit

Permalink
Solitaire: Add stack for the playable cards on top of the waste stack
Browse files Browse the repository at this point in the history
While the waste stack and the playable card on top of the waste stack
are collectively referred to as the "waste", it's programatically nice
to separate them to enable 3-card-draw mode. In that mode, the playable
stack will contain 3 cards with a slight x-axis shift, while the waste
stack underneath will remain unshifted. So rather than introducing some
ugly logic to CardStack to handle this, it's more convenient to have a
separate stack on top of the waste stack.
  • Loading branch information
trflynn89 authored and awesomekling committed May 16, 2021
1 parent d5ea04c commit 3a45bf5
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 8 deletions.
15 changes: 14 additions & 1 deletion Userland/Games/Solitaire/CardStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ void CardStack::draw(GUI::Painter& painter, const Gfx::Color& background_color)
}
break;
case Waste:
break;
case Play:
if (is_empty() || (m_stack.size() == 1 && peek().is_moving()))
painter.draw_rect(m_base, background_color.darkened(0.5));
break;
Expand Down Expand Up @@ -131,7 +133,7 @@ void CardStack::add_all_grabbed_cards(const Gfx::IntPoint& click_location, Nonnu

bool CardStack::is_allowed_to_push(const Card& card) const
{
if (m_type == Stock || m_type == Waste)
if (m_type == Stock || m_type == Waste || m_type == Play)
return false;

if (m_type == Normal && is_empty())
Expand Down Expand Up @@ -191,6 +193,17 @@ NonnullRefPtr<Card> CardStack::pop()
return card;
}

void CardStack::move_to_stack(CardStack& stack)
{
while (!m_stack.is_empty()) {
auto card = m_stack.take_first();
m_stack_positions.take_first();
stack.push(move(card));
}

calculate_bounding_box();
}

void CardStack::calculate_bounding_box()
{
m_bounding_box = Gfx::IntRect(m_position, { Card::width, Card::height });
Expand Down
7 changes: 6 additions & 1 deletion Userland/Games/Solitaire/CardStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class CardStack final {
Stock,
Normal,
Waste,
Play,
Foundation
};

Expand All @@ -36,6 +37,7 @@ class CardStack final {

void push(NonnullRefPtr<Card> card);
NonnullRefPtr<Card> pop();
void move_to_stack(CardStack&);
void rebound_cards();

bool is_allowed_to_push(const Card&) const;
Expand All @@ -59,8 +61,11 @@ class CardStack final {
case Normal:
return { 0, 20, 1, 3 };
case Stock:
case Waste:
return { 2, 1, 8, 1 };
case Waste:
return { 0, 0, 1, 0 };
case Play:
return { 20, 0, 1, 0 };
default:
return {};
}
Expand Down
41 changes: 35 additions & 6 deletions Userland/Games/Solitaire/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Game::Game()

m_stacks[Stock] = CardStack({ 10, 10 }, CardStack::Type::Stock);
m_stacks[Waste] = CardStack({ 10 + Card::width + 10, 10 }, CardStack::Type::Waste);
m_stacks[Play] = CardStack({ 10 + Card::width + 10, 10 }, CardStack::Type::Play);
m_stacks[Foundation4] = CardStack({ Game::width - Card::width - 10, 10 }, CardStack::Type::Foundation);
m_stacks[Foundation3] = CardStack({ Game::width - 2 * Card::width - 20, 10 }, CardStack::Type::Foundation);
m_stacks[Foundation2] = CardStack({ Game::width - 3 * Card::width - 30, 10 }, CardStack::Type::Foundation);
Expand Down Expand Up @@ -148,16 +149,26 @@ void Game::mousedown_event(GUI::MouseEvent& event)

auto click_location = event.position();
for (auto& to_check : m_stacks) {
if (to_check.type() == CardStack::Type::Waste)
continue;

if (to_check.bounding_box().contains(click_location)) {
if (to_check.type() == CardStack::Type::Stock) {
auto& waste = stack(Waste);
auto& stock = stack(Stock);
auto& play = stack(Play);

if (stock.is_empty()) {
if (waste.is_empty())
if (waste.is_empty() && play.is_empty())
return;

update(waste.bounding_box());
update(play.bounding_box());

while (!play.is_empty()) {
auto card = play.pop();
stock.push(card);
}

while (!waste.is_empty()) {
auto card = waste.pop();
Expand All @@ -167,9 +178,9 @@ void Game::mousedown_event(GUI::MouseEvent& event)
update_score(-100);
update(stock.bounding_box());
} else {
move_card(stock, waste);
play.move_to_stack(waste);
move_card(stock, play);
}

} else if (!to_check.is_empty()) {
auto& top_card = to_check.peek();

Expand Down Expand Up @@ -213,12 +224,21 @@ void Game::mouseup_event(GUI::MouseEvent& event)
m_focused_stack->pop();
}

if (m_focused_stack->type() == CardStack::Type::Play) {
auto& waste = this->stack(Waste);
if (m_focused_stack->is_empty() && !waste.is_empty()) {
auto card = waste.pop();
m_focused_cards.append(card);
m_focused_stack->push(move(card));
}
}

update(m_focused_stack->bounding_box());
update(stack.bounding_box());

if (m_focused_stack->type() == CardStack::Type::Waste && stack.type() == CardStack::Type::Normal) {
if (m_focused_stack->type() == CardStack::Type::Play && stack.type() == CardStack::Type::Normal) {
update_score(5);
} else if (m_focused_stack->type() == CardStack::Type::Waste && stack.type() == CardStack::Type::Foundation) {
} else if (m_focused_stack->type() == CardStack::Type::Play && stack.type() == CardStack::Type::Foundation) {
update_score(10);
} else if (m_focused_stack->type() == CardStack::Type::Normal && stack.type() == CardStack::Type::Foundation) {
update_score(10);
Expand Down Expand Up @@ -279,7 +299,7 @@ void Game::doubleclick_event(GUI::MouseEvent& event)

auto click_location = event.position();
for (auto& to_check : m_stacks) {
if (to_check.type() == CardStack::Type::Foundation || to_check.type() == CardStack::Type::Stock)
if (to_check.type() == CardStack::Type::Foundation || to_check.type() == CardStack::Type::Stock || to_check.type() == CardStack::Type::Waste)
continue;

if (to_check.bounding_box().contains(click_location) && !to_check.is_empty()) {
Expand All @@ -296,6 +316,15 @@ void Game::doubleclick_event(GUI::MouseEvent& event)
else
break;

if (to_check.type() == CardStack::Type::Play) {
auto& waste = this->stack(Waste);
if (to_check.is_empty() && !waste.is_empty()) {
auto card = waste.pop();
m_focused_cards.append(card);
to_check.push(move(card));
}
}

update_score(10);
}
break;
Expand Down
1 change: 1 addition & 0 deletions Userland/Games/Solitaire/Game.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class Game final : public GUI::Frame {
enum StackLocation {
Stock,
Waste,
Play,
Foundation1,
Foundation2,
Foundation3,
Expand Down

0 comments on commit 3a45bf5

Please sign in to comment.