From 46299f385314196d9e527068c46a7ce3712bb115 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 28 Sep 2022 11:35:12 +0100 Subject: [PATCH] LibCards+Games: Move "create a deck" logic to LibCards `create_standard_deck()` is the usual 52-card deck, but more custom setups (such as Spider's multiples-of-one-suit) can be created by passing suit counts to `create_deck()`. --- Userland/Games/Hearts/Game.cpp | 12 ++------- Userland/Games/Solitaire/Game.cpp | 10 +------- Userland/Games/Spider/Game.cpp | 38 +++++++++++----------------- Userland/Libraries/LibCards/Card.cpp | 38 ++++++++++++++++++++++++++++ Userland/Libraries/LibCards/Card.h | 8 ++++++ 5 files changed, 64 insertions(+), 42 deletions(-) diff --git a/Userland/Games/Hearts/Game.cpp b/Userland/Games/Hearts/Game.cpp index a792c0647c..1207d6d21b 100644 --- a/Userland/Games/Hearts/Game.cpp +++ b/Userland/Games/Hearts/Game.cpp @@ -199,20 +199,12 @@ void Game::setup(String player_name, int hand_number) m_passing_button->set_focus(false); } - NonnullRefPtrVector deck; - deck.ensure_capacity(Card::card_count * 4); - - for (int i = 0; i < Card::card_count; ++i) { - deck.append(Card::construct(Cards::Suit::Clubs, static_cast(i))); - deck.append(Card::construct(Cards::Suit::Spades, static_cast(i))); - deck.append(Card::construct(Cards::Suit::Hearts, static_cast(i))); - deck.append(Card::construct(Cards::Suit::Diamonds, static_cast(i))); - } + NonnullRefPtrVector deck = Cards::create_standard_deck(Cards::Shuffle::Yes); for (auto& player : m_players) { player.hand.ensure_capacity(Card::card_count); for (uint8_t i = 0; i < Card::card_count; ++i) { - auto card = deck.take(get_random_uniform(deck.size())); + auto card = deck.take_last(); if constexpr (!HEARTS_DEBUG) { if (&player != &m_players[0]) card->set_upside_down(true); diff --git a/Userland/Games/Solitaire/Game.cpp b/Userland/Games/Solitaire/Game.cpp index 7a7b1ff3dc..cb6a8433ee 100644 --- a/Userland/Games/Solitaire/Game.cpp +++ b/Userland/Games/Solitaire/Game.cpp @@ -162,15 +162,7 @@ void Game::setup(Mode mode) if (on_undo_availability_change) on_undo_availability_change(false); - for (int i = 0; i < Card::card_count; ++i) { - m_new_deck.append(Card::construct(Cards::Suit::Clubs, static_cast(i))); - m_new_deck.append(Card::construct(Cards::Suit::Spades, static_cast(i))); - m_new_deck.append(Card::construct(Cards::Suit::Hearts, static_cast(i))); - m_new_deck.append(Card::construct(Cards::Suit::Diamonds, static_cast(i))); - } - - for (uint8_t i = 0; i < 200; ++i) - m_new_deck.append(m_new_deck.take(get_random_uniform(m_new_deck.size()))); + m_new_deck = Cards::create_standard_deck(Cards::Shuffle::Yes); m_focused_stack = nullptr; m_focused_cards.clear(); diff --git a/Userland/Games/Spider/Game.cpp b/Userland/Games/Spider/Game.cpp index dd1cd3517e..71f15e95c0 100644 --- a/Userland/Games/Spider/Game.cpp +++ b/Userland/Games/Spider/Game.cpp @@ -48,32 +48,24 @@ void Game::setup(Mode mode) m_score = 500; update_score(0); - NonnullRefPtrVector deck; - deck.ensure_capacity(Card::card_count * 2); + unsigned heart_suits = 0; + unsigned spade_suits = 0; - for (int i = 0; i < Card::card_count; ++i) { - switch (m_mode) { - case Mode::SingleSuit: - for (int j = 0; j < 8; j++) { - deck.append(Card::construct(Cards::Suit::Spades, static_cast(i))); - } - break; - case Mode::TwoSuit: - for (int j = 0; j < 4; j++) { - deck.append(Card::construct(Cards::Suit::Spades, static_cast(i))); - deck.append(Card::construct(Cards::Suit::Hearts, static_cast(i))); - } - break; - default: - VERIFY_NOT_REACHED(); - break; - } + switch (m_mode) { + case Mode::SingleSuit: + spade_suits = 8; + heart_suits = 0; + break; + case Mode::TwoSuit: + spade_suits = 4; + heart_suits = 4; + break; + default: + VERIFY_NOT_REACHED(); + break; } - m_new_deck.clear_with_capacity(); - m_new_deck.ensure_capacity(deck.size()); - while (!deck.is_empty()) - m_new_deck.append(deck.take(get_random_uniform(deck.size()))); + m_new_deck = Cards::create_deck(0, 0, heart_suits, spade_suits, Cards::Shuffle::Yes); m_focused_stack = nullptr; m_focused_cards.clear(); diff --git a/Userland/Libraries/LibCards/Card.cpp b/Userland/Libraries/LibCards/Card.cpp index a42d0279e6..8bb98e2d55 100644 --- a/Userland/Libraries/LibCards/Card.cpp +++ b/Userland/Libraries/LibCards/Card.cpp @@ -1,11 +1,13 @@ /* * Copyright (c) 2020, Till Mayer * Copyright (c) 2022, the SerenityOS developers. + * Copyright (c) 2022, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #include "Card.h" +#include #include namespace Cards { @@ -50,4 +52,40 @@ void Card::clear_and_draw(GUI::Painter& painter, Color const& background_color) save_old_position(); } +NonnullRefPtrVector create_standard_deck(Shuffle shuffle) +{ + return create_deck(1, 1, 1, 1, shuffle); +} + +NonnullRefPtrVector create_deck(unsigned full_club_suit_count, unsigned full_diamond_suit_count, unsigned full_heart_suit_count, unsigned full_spade_suit_count, Shuffle shuffle) +{ + NonnullRefPtrVector deck; + deck.ensure_capacity(Card::card_count * (full_club_suit_count + full_diamond_suit_count + full_heart_suit_count + full_spade_suit_count)); + + auto add_cards_for_suit = [&deck](Cards::Suit suit, unsigned number_of_suits) { + for (auto i = 0u; i < number_of_suits; ++i) { + for (auto rank = 0; rank < Card::card_count; ++rank) { + deck.append(Card::construct(suit, static_cast(rank))); + } + } + }; + + add_cards_for_suit(Cards::Suit::Clubs, full_club_suit_count); + add_cards_for_suit(Cards::Suit::Diamonds, full_diamond_suit_count); + add_cards_for_suit(Cards::Suit::Hearts, full_heart_suit_count); + add_cards_for_suit(Cards::Suit::Spades, full_spade_suit_count); + + if (shuffle == Shuffle::Yes) + shuffle_deck(deck); + + return deck; +} + +void shuffle_deck(NonnullRefPtrVector& deck) +{ + auto iteration_count = deck.size() * 4; + for (auto i = 0u; i < iteration_count; ++i) + deck.append(deck.take(get_random_uniform(deck.size()))); +} + } diff --git a/Userland/Libraries/LibCards/Card.h b/Userland/Libraries/LibCards/Card.h index b3644013a4..ec4255807b 100644 --- a/Userland/Libraries/LibCards/Card.h +++ b/Userland/Libraries/LibCards/Card.h @@ -123,6 +123,14 @@ private: bool m_inverted { false }; }; +enum class Shuffle { + No, + Yes, +}; +NonnullRefPtrVector create_standard_deck(Shuffle); +NonnullRefPtrVector create_deck(unsigned full_club_suit_count, unsigned full_diamond_suit_count, unsigned full_heart_suit_count, unsigned full_spade_suit_count, Shuffle); +void shuffle_deck(NonnullRefPtrVector&); + } template<>