Optimize "whole hand" conditions checks for Joker effects (#213)
* Introduce a ContainedHandTypes type * Separate computing of hand_type and _contained_hand_types variables --------- Co-authored-by: MathisMartin31 <mathis.martin31@gmail.com>
This commit is contained in:
+32
-1
@@ -84,10 +84,10 @@ enum HandType
|
||||
PAIR,
|
||||
TWO_PAIR,
|
||||
THREE_OF_A_KIND,
|
||||
FOUR_OF_A_KIND,
|
||||
STRAIGHT,
|
||||
FLUSH,
|
||||
FULL_HOUSE,
|
||||
FOUR_OF_A_KIND,
|
||||
STRAIGHT_FLUSH,
|
||||
ROYAL_FLUSH,
|
||||
FIVE_OF_A_KIND,
|
||||
@@ -95,6 +95,34 @@ enum HandType
|
||||
FLUSH_FIVE
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
// Store all contained hands to optimize "whole hand condition" Jokers
|
||||
typedef struct ContainedHandTypes
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 HIGH_CARD : 1;
|
||||
u16 PAIR : 1;
|
||||
u16 TWO_PAIR : 1;
|
||||
u16 THREE_OF_A_KIND : 1;
|
||||
u16 STRAIGHT : 1;
|
||||
u16 FLUSH : 1;
|
||||
u16 FULL_HOUSE : 1;
|
||||
u16 FOUR_OF_A_KIND : 1;
|
||||
u16 STRAIGHT_FLUSH : 1;
|
||||
u16 ROYAL_FLUSH : 1;
|
||||
u16 FIVE_OF_A_KIND : 1;
|
||||
u16 FLUSH_HOUSE : 1;
|
||||
u16 FLUSH_FIVE : 1;
|
||||
u16 : 3;
|
||||
};
|
||||
u16 value;
|
||||
};
|
||||
} ContainedHandTypes;
|
||||
// clang-format on
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int substate;
|
||||
@@ -119,6 +147,9 @@ bool card_is_face(Card* card);
|
||||
List* get_jokers_list(void);
|
||||
List* get_expired_jokers_list(void);
|
||||
|
||||
ContainedHandTypes* get_contained_hands(void);
|
||||
enum HandType* get_hand_type(void);
|
||||
|
||||
int get_deck_top(void);
|
||||
int get_num_discards_remaining(void);
|
||||
int get_num_hands_remaining(void);
|
||||
|
||||
+146
-102
@@ -496,10 +496,10 @@ static const HandValues hand_base_values[] = {
|
||||
{.chips = 10, .mult = 2, .display_name = "PAIR" }, // PAIR
|
||||
{.chips = 20, .mult = 2, .display_name = "2 PAIR" }, // TWO_PAIR
|
||||
{.chips = 30, .mult = 3, .display_name = "3 OAK" }, // THREE_OF_A_KIND
|
||||
{.chips = 60, .mult = 7, .display_name = "4 OAK" }, // FOUR_OF_A_KIND
|
||||
{.chips = 30, .mult = 4, .display_name = "STRT" }, // STRAIGHT
|
||||
{.chips = 35, .mult = 4, .display_name = "FLUSH" }, // FLUSH
|
||||
{.chips = 40, .mult = 4, .display_name = "FULL H" }, // FULL_HOUSE
|
||||
{.chips = 60, .mult = 7, .display_name = "4 OAK" }, // FOUR_OF_A_KIND
|
||||
{.chips = 100, .mult = 8, .display_name = "STRT F" }, // STRAIGHT_FLUSH
|
||||
{.chips = 100, .mult = 8, .display_name = "ROYAL F"}, // ROYAL_FLUSH
|
||||
{.chips = 120, .mult = 12, .display_name = "5 OAK" }, // FIVE_OF_A_KIND
|
||||
@@ -540,6 +540,7 @@ static enum HandState hand_state = HAND_DRAW;
|
||||
static enum PlayState play_state = PLAY_STARTING;
|
||||
|
||||
static enum HandType hand_type = NONE;
|
||||
static ContainedHandTypes _contained_hands = {0};
|
||||
|
||||
static CardObject* main_menu_ace = NULL;
|
||||
|
||||
@@ -921,15 +922,6 @@ bool is_joker_owned(int joker_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool card_is_face(Card* card)
|
||||
{
|
||||
// Card is a face card, or Pareidolia is present
|
||||
return (
|
||||
card->rank == JACK || card->rank == QUEEN || card->rank == KING ||
|
||||
is_joker_owned(PAREIDOLIA_JOKER_ID)
|
||||
);
|
||||
}
|
||||
|
||||
List* get_jokers_list(void)
|
||||
{
|
||||
return &_owned_jokers_list;
|
||||
@@ -1254,6 +1246,148 @@ static void sort_cards(void)
|
||||
reorder_card_sprites_layers();
|
||||
}
|
||||
|
||||
static ContainedHandTypes compute_contained_hand_types(void)
|
||||
{
|
||||
ContainedHandTypes hand_types = {0};
|
||||
|
||||
// Idk if this is how Balatro does it but this is how I'm doing it
|
||||
if (hand_selections == 0 || hand_state == HAND_DISCARD)
|
||||
{
|
||||
return hand_types;
|
||||
}
|
||||
|
||||
hand_types.HIGH_CARD = 1;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_hand_distribution(ranks, suits);
|
||||
|
||||
// The following can be optimized better but not sure how much it matters
|
||||
u8 n_of_a_kind = hand_contains_n_of_a_kind(ranks);
|
||||
|
||||
// Pair and 2 Pair
|
||||
if (n_of_a_kind >= 2)
|
||||
{
|
||||
hand_types.PAIR = 1;
|
||||
|
||||
if (hand_contains_two_pair(ranks))
|
||||
{
|
||||
hand_types.TWO_PAIR = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 3 OAK
|
||||
if (n_of_a_kind >= 3)
|
||||
{
|
||||
hand_types.THREE_OF_A_KIND = 1;
|
||||
}
|
||||
|
||||
// Straight
|
||||
if (hand_contains_straight(ranks))
|
||||
{
|
||||
hand_types.STRAIGHT = 1;
|
||||
}
|
||||
|
||||
// Flush
|
||||
if (hand_contains_flush(suits))
|
||||
{
|
||||
hand_types.FLUSH = 1;
|
||||
}
|
||||
|
||||
// Full House
|
||||
if (n_of_a_kind >= 3 && hand_contains_full_house(ranks))
|
||||
{
|
||||
hand_types.FULL_HOUSE = 1;
|
||||
}
|
||||
|
||||
// 4 OAK
|
||||
if (n_of_a_kind >= 4)
|
||||
{
|
||||
hand_types.FOUR_OF_A_KIND = 1;
|
||||
}
|
||||
|
||||
// Straight Flush
|
||||
if (hand_types.STRAIGHT && hand_types.FLUSH)
|
||||
{
|
||||
hand_types.STRAIGHT_FLUSH = 1;
|
||||
}
|
||||
|
||||
// Royal Flush
|
||||
if (hand_types.STRAIGHT_FLUSH)
|
||||
{
|
||||
if (ranks[TEN] && ranks[JACK] && ranks[QUEEN] && ranks[KING] && ranks[ACE])
|
||||
{
|
||||
hand_types.ROYAL_FLUSH = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 5 OAK
|
||||
if (n_of_a_kind >= 5)
|
||||
{
|
||||
hand_types.FIVE_OF_A_KIND = 1;
|
||||
}
|
||||
|
||||
// Flush House and Five
|
||||
if (hand_types.FLUSH)
|
||||
{
|
||||
if (hand_types.FULL_HOUSE)
|
||||
{
|
||||
hand_types.FLUSH_HOUSE = 1;
|
||||
}
|
||||
|
||||
if (hand_types.FIVE_OF_A_KIND)
|
||||
{
|
||||
hand_types.FLUSH_FIVE = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return hand_types;
|
||||
}
|
||||
|
||||
ContainedHandTypes* get_contained_hands(void)
|
||||
{
|
||||
return &_contained_hands;
|
||||
}
|
||||
|
||||
enum HandType compute_hand_type(struct ContainedHandTypes contained_types)
|
||||
{
|
||||
enum HandType ret;
|
||||
|
||||
// test each pit see if it's set to 1, and return the first one
|
||||
for (ret = FLUSH_FIVE; ret > NONE; ret--)
|
||||
{
|
||||
// Shift the bit we want to check to the front and mask it with 1 to keep only that
|
||||
// Since the ContainedHandTypes is ordered the same way as the HandType enum, we
|
||||
// can shift right by ret-1 to have the bit we want at the front
|
||||
if ((contained_types.value >> (ret - 1)) & 0x1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we broke early, ret contains the value of the HandType enum corresponding to
|
||||
// the position of the highest bit set to 1 in contained_types.value, which is the
|
||||
// most powerful poker hand contained in the current Hand
|
||||
// If not, then it contains NONE, which is what we're supposed to return when there
|
||||
// are no Hands contained in what we played
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum HandType* get_hand_type(void)
|
||||
{
|
||||
return &hand_type;
|
||||
}
|
||||
|
||||
// Returns true if the card is *considered* a face card
|
||||
bool card_is_face(Card* card)
|
||||
{
|
||||
// Card is a face card, or Pareidolia is present
|
||||
return (
|
||||
card->rank == JACK || card->rank == QUEEN || card->rank == KING ||
|
||||
is_joker_owned(PAREIDOLIA_JOKER_ID)
|
||||
);
|
||||
}
|
||||
|
||||
/* Copies the appropriate item into the top left panel (blind/shop icon)
|
||||
* from where it was put outside the screenview
|
||||
*/
|
||||
@@ -1686,97 +1820,6 @@ static void display_discards(int value)
|
||||
);
|
||||
}
|
||||
|
||||
static inline enum HandType hand_get_type(void)
|
||||
{
|
||||
enum HandType res_hand_type = NONE;
|
||||
|
||||
// Idk if this is how Balatro does it but this is how I'm doing it
|
||||
if (hand_selections == 0 || hand_state == HAND_DISCARD)
|
||||
{
|
||||
res_hand_type = NONE;
|
||||
return res_hand_type;
|
||||
}
|
||||
|
||||
res_hand_type = HIGH_CARD;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_hand_distribution(ranks, suits);
|
||||
|
||||
// Check for flush
|
||||
if (hand_contains_flush(suits))
|
||||
res_hand_type = FLUSH;
|
||||
|
||||
// Check for straight
|
||||
if (hand_contains_straight(ranks))
|
||||
{
|
||||
if (res_hand_type == FLUSH)
|
||||
res_hand_type = STRAIGHT_FLUSH;
|
||||
else
|
||||
res_hand_type = STRAIGHT;
|
||||
}
|
||||
|
||||
// The following can be optimized better but not sure how much it matters
|
||||
u8 n_of_a_kind = hand_contains_n_of_a_kind(ranks);
|
||||
|
||||
if (n_of_a_kind >= 5)
|
||||
{
|
||||
if (res_hand_type == FLUSH)
|
||||
{
|
||||
return FLUSH_FIVE;
|
||||
}
|
||||
return FIVE_OF_A_KIND;
|
||||
}
|
||||
|
||||
// Check for royal flush vs regular straight flush
|
||||
if (res_hand_type == STRAIGHT_FLUSH)
|
||||
{
|
||||
if (ranks[TEN] && ranks[JACK] && ranks[QUEEN] && ranks[KING] && ranks[ACE])
|
||||
return ROYAL_FLUSH;
|
||||
return STRAIGHT_FLUSH;
|
||||
}
|
||||
|
||||
if (n_of_a_kind == 4)
|
||||
{
|
||||
return FOUR_OF_A_KIND;
|
||||
}
|
||||
|
||||
if (n_of_a_kind == 3 && hand_contains_full_house(ranks))
|
||||
{
|
||||
return FULL_HOUSE;
|
||||
}
|
||||
|
||||
// Flush and Straight are more valuable than the remaining hand types, so return them now
|
||||
if (res_hand_type == FLUSH)
|
||||
{
|
||||
if (n_of_a_kind >= 5)
|
||||
{
|
||||
return FLUSH_HOUSE;
|
||||
}
|
||||
return FLUSH;
|
||||
}
|
||||
if (res_hand_type == STRAIGHT)
|
||||
{
|
||||
return STRAIGHT;
|
||||
}
|
||||
|
||||
if (n_of_a_kind == 3)
|
||||
{
|
||||
return THREE_OF_A_KIND;
|
||||
}
|
||||
|
||||
if (n_of_a_kind == 2)
|
||||
{
|
||||
if (hand_contains_two_pair(ranks))
|
||||
{
|
||||
return TWO_PAIR;
|
||||
}
|
||||
return PAIR;
|
||||
}
|
||||
|
||||
return res_hand_type; // should be HIGH_CARD
|
||||
}
|
||||
|
||||
static void print_hand_type(const char* hand_type_str)
|
||||
{
|
||||
if (hand_type_str == NULL)
|
||||
@@ -1793,7 +1836,8 @@ static void print_hand_type(const char* hand_type_str)
|
||||
static void set_hand(void)
|
||||
{
|
||||
tte_erase_rect_wrapper(HAND_TYPE_RECT);
|
||||
hand_type = hand_get_type();
|
||||
_contained_hands = compute_contained_hand_types();
|
||||
hand_type = compute_hand_type(_contained_hands);
|
||||
|
||||
HandValues hand = hand_base_values[hand_type];
|
||||
|
||||
|
||||
+15
-79
@@ -516,12 +516,8 @@ static u32 jolly_joker_effect(
|
||||
SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
// This is really inefficient but the only way at the moment to check for whole-hand conditions
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_n_of_a_kind(ranks) >= 2)
|
||||
if (get_contained_hands()->PAIR)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -543,12 +539,7 @@ static u32 zany_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
// This is really inefficient but the only way at the moment to check for whole-hand conditions
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_n_of_a_kind(ranks) >= 3)
|
||||
if (get_contained_hands()->THREE_OF_A_KIND)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -570,11 +561,7 @@ static u32 mad_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_two_pair(ranks))
|
||||
if (get_contained_hands()->TWO_PAIR)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -596,11 +583,7 @@ static u32 crazy_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_straight(ranks))
|
||||
if (get_contained_hands()->STRAIGHT)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -622,11 +605,7 @@ static u32 droll_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_flush(suits))
|
||||
if (get_contained_hands()->FLUSH)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -648,11 +627,7 @@ static u32 sly_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_n_of_a_kind(ranks) >= 2)
|
||||
if (get_contained_hands()->PAIR)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -674,11 +649,7 @@ static u32 wily_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_n_of_a_kind(ranks) >= 3)
|
||||
if (get_contained_hands()->THREE_OF_A_KIND)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -700,11 +671,7 @@ static u32 clever_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_two_pair(ranks))
|
||||
if (get_contained_hands()->TWO_PAIR)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -726,11 +693,7 @@ static u32 devious_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_straight(ranks))
|
||||
if (get_contained_hands()->STRAIGHT)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -752,11 +715,7 @@ static u32 crafty_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_flush(suits))
|
||||
if (get_contained_hands()->FLUSH)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -1314,12 +1273,7 @@ static u32 the_duo_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
// This is really inefficient but the only way at the moment to check for whole-hand conditions
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_n_of_a_kind(ranks) >= 2)
|
||||
if (get_contained_hands()->PAIR)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -1341,12 +1295,7 @@ static u32 the_trio_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
// This is really inefficient but the only way at the moment to check for whole-hand conditions
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_n_of_a_kind(ranks) >= 3)
|
||||
if (get_contained_hands()->THREE_OF_A_KIND)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -1368,12 +1317,7 @@ static u32 the_family_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
// This is really inefficient but the only way at the moment to check for whole-hand conditions
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_n_of_a_kind(ranks) >= 4)
|
||||
if (get_contained_hands()->FOUR_OF_A_KIND)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -1395,11 +1339,7 @@ static u32 the_order_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_straight(ranks))
|
||||
if (get_contained_hands()->STRAIGHT)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
@@ -1421,11 +1361,7 @@ static u32 the_tribe_joker_effect(
|
||||
|
||||
u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
|
||||
|
||||
u8 suits[NUM_SUITS];
|
||||
u8 ranks[NUM_RANKS];
|
||||
get_played_distribution(ranks, suits);
|
||||
|
||||
if (hand_contains_flush(suits))
|
||||
if (get_contained_hands()->FLUSH)
|
||||
{
|
||||
*joker_effect = &shared_joker_effect;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user