Skip to content

Instantly share code, notes, and snippets.

@kevyonan
Last active June 5, 2025 02:20
Show Gist options
  • Select an option

  • Save kevyonan/60a5be1259d811a4b1676a3999b3527a to your computer and use it in GitHub Desktop.

Select an option

Save kevyonan/60a5be1259d811a4b1676a3999b3527a to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
static size_t bits_popcount(uint64_t const x) {
size_t count = 0;
for( uint64_t i=x; i > 0; count++ ) {
i &= (i - 1);
}
return count;
}
static char const *const restrict abs_cards_cstr = "🂡🂢🂣🂤🂥🂦🂧🂨🂩🂪🂫🂬🂭🂮🂱🂲🂳🂴🂵🂶🂷🂸🂹🂺🂻🂼🂽🂾🃁🃂🃃🃄🃅🃆🃇🃈🃉🃊🃋🃌🃍🃎🃑🃒🃓🃔🃕🃖🃗🃘🃙🃚🃛🃜🃝🃞🂠";
static char const *const restrict abs_cards_cstrs[] = {
"🂡","🂢","🂣","🂤","🂥","🂦","🂧","🂨","🂩","🂪","🂫","🂭","🂮",
"🂱","🂲","🂳","🂴","🂵","🂶","🂷","🂸","🂹","🂺","🂻","🂽","🂾",
"🃁","🃂","🃃","🃄","🃅","🃆","🃇","🃈","🃉","🃊","🃋","🃍","🃎",
"🃑","🃒","🃓","🃔","🃕","🃖","🃗","🃘","🃙","🃚","🃛","🃝","🃞",
"🂠",
};
static char const *const restrict abf_cards_cstr = "🂡🂱🃁🃑🂢🂲🃂🃒🂣🂳🃃🃓🂤🂴🃄🃔🂥🂵🃅🃕🂦🂶🃆🃖🂧🂷🃇🃗🂨🂸🃈🃘🂩🂹🃉🃙🂪🂺🃊🃚🂫🂻🃋🃛🂭🂽🃍🃝🂮🂾🃎🃞🂠";
static char const *const restrict abf_cards_cstrs[] = {
"🂡","🂱","🃁","🃑",
"🂢","🂲","🃂","🃒",
"🂣","🂳","🃃","🃓",
"🂤","🂴","🃄","🃔",
"🂥","🂵","🃅","🃕",
"🂦","🂶","🃆","🃖",
"🂧","🂷","🃇","🃗",
"🂨","🂸","🃈","🃘",
"🂩","🂹","🃉","🃙",
"🂪","🂺","🃊","🃚",
"🂫","🂻","🃋","🃛",
"🂭","🂽","🃍","🃝",
"🂮","🂾","🃎","🃞",
"🂠",
};
static char const *const restrict suits_cstr = "♠♥♦♣";
static char const *const restrict suits_cstrs[] = {
"♠","♥","♦","♣",
};
static char const *const restrict rank_cstr = "A23456789TJQK";
/**
* Two ways to represent cards in a bitwise pattern:
* Arrange by suits or arrange by face
*
* - Arranged by Suits (ABS):
* ♣♣♣♣♣♣♣♣♣♣♣♣♣ ♦♦♦♦♦♦♦♦♦♦♦♦♦ ♥♥♥♥♥♥♥♥♥♥♥♥♥ ♠♠♠♠♠♠♠♠♠♠♠♠♠
* UNUSED-------- KQJX98765432A_KQJX98765432A_KQJX98765432A_KQJX98765432A
* 0000_0000_0000 0000000000000_0000000000000_0000000000000_0000000000000
*
*
* - Arranged by Face (ABF):
* ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠ ♣♦♥♠
* UNUSED-------- KKKK_QQQQ_JJJJ_XXXX_9999_8888_7777_6666_5555_4444_3333_2222_AAAA
* 0000_0000_0000 0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000
*/
enum {
MAX_FACES = 13,
FACE_MASK = MAX_FACES - 1,
SPADE = 0,
HEART = 1,
DIAMOND = 2,
CLUB = 3,
MAX_SUITS = 4,
MAX_CARDS = MAX_FACES * MAX_SUITS,
SPADE_IDX = MAX_FACES * SPADE, /// 0
HEART_IDX = MAX_FACES * HEART, /// 13
DIAMOND_IDX = MAX_FACES * DIAMOND, /// 26
CLUB_IDX = MAX_FACES * CLUB, /// 39
/// Arranged by Suits
ABS_ACES = (1ull << (SPADE_IDX+ 0ull)) | (1ull << (HEART_IDX+ 0ull)) | (1ull << (DIAMOND_IDX+ 0ull)) | (1ull << (CLUB_IDX+ 0ull)),
ABS_TWOS = (1ull << (SPADE_IDX+ 1ull)) | (1ull << (HEART_IDX+ 1ull)) | (1ull << (DIAMOND_IDX+ 1ull)) | (1ull << (CLUB_IDX+ 1ull)),
ABS_THREES = (1ull << (SPADE_IDX+ 2ull)) | (1ull << (HEART_IDX+ 2ull)) | (1ull << (DIAMOND_IDX+ 2ull)) | (1ull << (CLUB_IDX+ 2ull)),
ABS_FOURS = (1ull << (SPADE_IDX+ 3ull)) | (1ull << (HEART_IDX+ 3ull)) | (1ull << (DIAMOND_IDX+ 3ull)) | (1ull << (CLUB_IDX+ 3ull)),
ABS_FIVES = (1ull << (SPADE_IDX+ 4ull)) | (1ull << (HEART_IDX+ 4ull)) | (1ull << (DIAMOND_IDX+ 4ull)) | (1ull << (CLUB_IDX+ 4ull)),
ABS_SIXES = (1ull << (SPADE_IDX+ 5ull)) | (1ull << (HEART_IDX+ 5ull)) | (1ull << (DIAMOND_IDX+ 5ull)) | (1ull << (CLUB_IDX+ 5ull)),
ABS_SEVENS = (1ull << (SPADE_IDX+ 6ull)) | (1ull << (HEART_IDX+ 6ull)) | (1ull << (DIAMOND_IDX+ 6ull)) | (1ull << (CLUB_IDX+ 6ull)),
ABS_EIGHTS = (1ull << (SPADE_IDX+ 7ull)) | (1ull << (HEART_IDX+ 7ull)) | (1ull << (DIAMOND_IDX+ 7ull)) | (1ull << (CLUB_IDX+ 7ull)),
ABS_NINES = (1ull << (SPADE_IDX+ 8ull)) | (1ull << (HEART_IDX+ 8ull)) | (1ull << (DIAMOND_IDX+ 8ull)) | (1ull << (CLUB_IDX+ 8ull)),
ABS_TENS = (1ull << (SPADE_IDX+ 9ull)) | (1ull << (HEART_IDX+ 9ull)) | (1ull << (DIAMOND_IDX+ 9ull)) | (1ull << (CLUB_IDX+ 9ull)),
ABS_JACKS = (1ull << (SPADE_IDX+10ull)) | (1ull << (HEART_IDX+10ull)) | (1ull << (DIAMOND_IDX+10ull)) | (1ull << (CLUB_IDX+10ull)),
ABS_QUEENS = (1ull << (SPADE_IDX+11ull)) | (1ull << (HEART_IDX+11ull)) | (1ull << (DIAMOND_IDX+11ull)) | (1ull << (CLUB_IDX+11ull)),
ABS_KINGS = (1ull << (SPADE_IDX+12ull)) | (1ull << (HEART_IDX+12ull)) | (1ull << (DIAMOND_IDX+12ull)) | (1ull << (CLUB_IDX+12ull)),
ABS_SPADES = 0x0000000001FFFull,
ABS_HEARTS = 0x0000003FFE000ull,
ABS_DIAMONDS = 0x0007FFC000000ull,
ABS_CLUBS = 0xFFF8000000000ull,
ABS_ROYALS = 0x1E01ull,
ABF_ACES = 0x000000000000Full,
ABF_TWOS = 0x00000000000F0ull,
ABF_THREES = 0x0000000000F00ull,
ABF_FOURS = 0x000000000F000ull,
ABF_FIVES = 0x00000000F0000ull,
ABF_SIXES = 0x0000000F00000ull,
ABF_SEVENS = 0x000000F000000ull,
ABF_EIGHTS = 0x00000F0000000ull,
ABF_NINES = 0x0000F00000000ull,
ABF_TENS = 0x000F000000000ull,
ABF_JACKS = 0x00F0000000000ull,
ABF_QUEENS = 0x0F00000000000ull,
ABF_KINGS = 0xF000000000000ull,
ABF_SPADES = 0x1111111111111ull,
ABF_HEARTS = 0x2222222222222ull,
ABF_DIAMONDS = 0x4444444444444ull,
ABF_CLUBS = 0x8888888888888ull,
ABF_ROYALS = 0x1111000000001ull,
/**
* Winning Hands of Texas Hold Em:
* - Royal Flush
* - Straight Flush
* - Four of a Kind
* - Full House
* - Flush
* - Straight (Aces can be higher/lower)
* - Three of a Kind
* - Two Pair
* - One Pair
* - High Card
*/
};
char const *abs_hand_to_cstr(uint64_t const hand) {
enum{ CARD_CSTR_SIZE = sizeof "🂠" - 1 };
static char buf[MAX_CARDS * CARD_CSTR_SIZE + 2];
memset(buf, 0, sizeof buf);
for( size_t i=0; i < MAX_CARDS; i++ ) {
if( (hand&(1ull << i)) > 0 ) {
strcat(buf, abs_cards_cstrs[i]);
strcat(buf, " ");
}
}
return buf;
}
char const *abf_hand_to_cstr(uint64_t const hand) {
enum{ CARD_CSTR_SIZE = sizeof "🂠" - 1 };
static char buf[MAX_CARDS * CARD_CSTR_SIZE + 2];
memset(buf, 0, sizeof buf);
for( size_t i=0; i < MAX_CARDS; i++ ) {
if( (hand&(1ull << i)) > 0 ) {
strcat(buf, abf_cards_cstrs[i]);
strcat(buf, " ");
}
}
return buf;
}
uint64_t init_deck(void) {
return (1ull << MAX_CARDS) - 1;
}
uint64_t put_card_into_deck(uint64_t const deck, uint_fast8_t const idx) {
return deck | (1ull << idx);
}
uint64_t remove_card_from_deck(uint64_t const deck, uint_fast8_t const idx) {
return deck & ~(1ull << idx);
}
/// index = 13 * suit + rank /// ABS (suit 0=♣,…; rank 0=A,…,12=K)
uint64_t make_hand_abs(size_t const num, uint_fast8_t const suit[], uint_fast8_t const face[]) {
uint64_t hand = 0;
for( size_t i=0; i < num; i++ ) {
hand |= (1ull << ((MAX_FACES * suit[i]) + face[i]));
}
return hand;
}
/// index = 4 * rank + suit /// ABF (rank 0=A, 12=K; suit 0=♣,1=♦,2=♥,3=♠)
uint64_t make_hand_abf(size_t const num, uint_fast8_t const suit[], uint_fast8_t const face[]) {
uint64_t hand = 0;
for( size_t i=0; i < num; i++ ) {
hand |= (1ull << ((MAX_SUITS * face[i]) + suit[i]));
}
return hand;
}
int abs_is_royal_flush(uint64_t const hand) {
for( size_t i=SPADE_IDX; i <= CLUB_IDX; i += MAX_FACES ) {
uint64_t const mask = ABS_ROYALS << i;
if( (hand&mask)==mask ) {
return 1;
}
}
return 0;
}
int abf_is_royal_flush(uint64_t const hand) {
for( size_t i=0; i < MAX_SUITS; i++ ) {
uint64_t const mask = ABF_ROYALS << i;
if( (hand&mask)==mask ) {
return 1;
}
}
return 0;
}
size_t abs_count_rank(uint64_t const hand, size_t const rank) {
if( rank >= MAX_FACES ) {
return 0;
}
uint64_t const mask = (1ull << (SPADE_IDX+rank))
| (1ull << (HEART_IDX+rank))
| (1ull << (DIAMOND_IDX+rank))
| (1ull << (CLUB_IDX+rank));
return bits_popcount(hand&mask);
}
size_t abf_count_rank(uint64_t const hand, size_t const rank) {
if( rank >= MAX_FACES ) {
return 0;
}
return bits_popcount(hand&(0xf << (rank*MAX_SUITS)));
}
int abs_is_n_of_kind(uint64_t const hand, size_t const n) {
for( size_t i=0; i < MAX_FACES; i++ ) {
if( abs_count_rank(hand, i)==n ) {
return 1;
}
}
return 0;
}
int abf_is_n_of_kind(uint64_t const hand, size_t const n) {
for( size_t i=0; i < MAX_FACES; i++ ) {
if( abf_count_rank(hand, i)==n ) {
return 1;
}
}
return 0;
}
int abs_is_flush(uint64_t const hand) {
return bits_popcount(hand&ABS_SPADES) >= 5
|| bits_popcount(hand&ABS_HEARTS) >= 5
|| bits_popcount(hand&ABS_DIAMONDS) >= 5
|| bits_popcount(hand&ABS_CLUBS) >= 5;
}
int abf_is_flush(uint64_t const hand) {
return bits_popcount(hand&ABF_SPADES) >= 5
|| bits_popcount(hand&ABF_HEARTS) >= 5
|| bits_popcount(hand&ABF_DIAMONDS) >= 5
|| bits_popcount(hand&ABF_CLUBS) >= 5;
}
/// Straight detection has to handle Wheel and Broadway straights:
/// Wheel Straight is where the Ace is the lower card (i.e. A2345)
/// And Broadway Straight is where is the ace is the higher card (i.e. TJQKA)
int _is_straight(uint32_t c) {
c |= ((c&1)<<13); /// copy ace to bit 13.
return (c & (c >> 1) & (c >> 2) & (c >> 3) & (c >> 4)) > 0;
}
int abs_is_str8(uint64_t const hand) {
uint32_t c = 0;
c |= (hand&ABS_SPADES) >> (MAX_FACES * 0);
c |= (hand&ABS_HEARTS) >> (MAX_FACES * 1);
c |= (hand&ABS_DIAMONDS) >> (MAX_FACES * 2);
c |= (hand&ABS_CLUBS) >> (MAX_FACES * 3);
return _is_straight(c);
}
int abf_is_str8(uint64_t const hand) {
uint32_t c = 0;
for( size_t i=0; i < MAX_FACES; i++ ) {
uint64_t const rank_bits = 0xFull << (i*MAX_SUITS);
c |= ( (uint64_t)( (hand&rank_bits) > 0 ) ) << i;
}
return _is_straight(c);
}
int abs_is_str8_flush(uint64_t const hand) {
return abs_is_flush(hand) && abs_is_str8(hand);
}
int abf_is_str8_flush(uint64_t const hand) {
return abf_is_flush(hand) && abf_is_str8(hand);
}
int abs_is_full_house(uint64_t const hand) {
size_t x = 0;
for( size_t i=0; i < MAX_FACES && x != 3; i++ ) {
size_t const c = abs_count_rank(hand, i);
if( c >= 3 ) {
x |= 1 << (x&1);
} else if( c >= 2 ) {
x |= 2;
}
}
return x==3;
}
int abf_is_full_house(uint64_t const hand) {
size_t x = 0;
for( size_t i=0; i < MAX_FACES && x != 3; i++ ) {
size_t const c = abf_count_rank(hand, i);
if( c >= 3 ) {
x |= 1 << (x&1);
} else if( c >= 2 ) {
x |= 2;
}
}
return x==3;
}
size_t abs_hand_score(uint64_t const hand) {
size_t score = abs_count_rank(hand, 0) * 13;
for( size_t i=1; i < MAX_FACES; i++ ) {
score += abs_count_rank(hand, i) * i;
}
return score;
}
size_t abf_hand_score(uint64_t const hand) {
size_t score = abf_count_rank(hand, 0) * 13;
for( size_t i=1; i < MAX_FACES; i++ ) {
score += abf_count_rank(hand, i) * i;
}
return score;
}
/**
* Game States of Texas Hold Em Poker.
* - Setup: Players start with certain money and order.
* - Choose: call, fold, bet, or check.
* - Flop3: Emplace 3 community cards. -> Choose-State if not all-in, Flop4 otherwise.
* - Flop4: Emplace 4th card to community. Choose-State if not all-in, Flop5 otherwise.
* - Flop5: Emplace 5th, final card to community. Choose-State if not all-in, Determine-Winner otherwise.
* - Determine Winner: compare cards in mix of community, highest hand wins.
* if people go all in, Choose state is ignored.
*/
enum {
STATE_SETUP = 0,
STATE_CHOOSE = 1,
STATE_3CARD = 2,
STATE_CARD4 = 4,
STATE_CARD5 = 8,
STATE_SHOWDOWN = 16,
};
int main(int argc, char *argv[]) {
//uint64_t cards = init_deck();
//uint64_t const abs_hand = make_hand_abs(5, (uint_fast8_t[]){CLUB, HEART, HEART, DIAMOND, HEART}, (uint_fast8_t[]){0,12,11,10,9});
//uint64_t const abs_hand = make_hand_abs(5, (uint_fast8_t[]){CLUB, HEART, SPADE, DIAMOND, HEART}, (uint_fast8_t[]){0,0,0,10,10});
uint64_t const abs_hand = make_hand_abs(7, (uint_fast8_t[]){CLUB, HEART, SPADE, DIAMOND, HEART}, (uint_fast8_t[]){0,0,0,12,12,12,10});
printf("ABS hand: %#"PRIx64" | '%s'\n", abs_hand, abs_hand_to_cstr(abs_hand));
printf("ABS:: is royal flush: %i\n", abs_is_royal_flush(abs_hand));
printf("ABS:: is straight flush: %i\n", abs_is_str8_flush(abs_hand));
printf("ABS:: is four of a kind: %i\n", abs_is_n_of_kind(abs_hand, 4));
printf("ABS:: is straight: %i\n", abs_is_str8(abs_hand));
printf("ABS:: is flush: %i\n", abs_is_flush(abs_hand));
printf("ABS:: is full house: %i\n", abs_is_full_house(abs_hand));
printf("ABS:: hand score: %zu\n\n", abs_hand_score(abs_hand));
uint64_t const abf_hand = make_hand_abf(5, (uint_fast8_t[]){SPADE, DIAMOND, HEART, CLUB, SPADE}, (uint_fast8_t[]){0,12,11,10,9});
printf("ABF hand: %#"PRIx64" | '%s'\n", abf_hand, abf_hand_to_cstr(abf_hand));
printf("ABF:: is royal flush: %i\n", abf_is_royal_flush(abf_hand));
printf("ABF:: is straight flush: %i\n", abf_is_str8_flush(abf_hand));
printf("ABF:: is four of a kind: %i\n", abf_is_n_of_kind(abf_hand, 4));
printf("ABF:: is straight: %i\n", abf_is_str8(abf_hand));
printf("ABF:: is flush: %i\n", abf_is_flush(abf_hand));
printf("ABF:: is full house: %i\n", abf_is_full_house(abf_hand));
printf("ABF:: hand score: %zu\n\n", abf_hand_score(abf_hand));
}
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
enum CardSuit {
SUIT_HEART,
SUIT_DIAMOND,
SUIT_SPADE,
SUIT_CLUB,
MAX_SUITS,
};
enum CardFace {
ACE, TWO, THREE,
FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN,
JACK, QUEEN, KING,
MAX_FACES,
};
/// Valid cards only use up 6 bits.
enum { NULL_CARD = 0xFF };
uint8_t
make_card(enum CardSuit const suit, enum CardFace const face) {
return suit | (face << 2);
}
bool
card_is_suit(uint8_t const card, enum CardSuit const suit) {
return ( card & 3 ) == suit;
}
bool
card_is_face(uint8_t const card, enum CardFace const face) {
return ( card >> 2 ) == face;
}
void
print_card(uint8_t const card) {
char const *suit_str = NULL;
switch( card & 3 ) {
case SUIT_HEART: suit_str = "heart"; break;
case SUIT_DIAMOND: suit_str = "diamond"; break;
case SUIT_SPADE: suit_str = "spade"; break;
case SUIT_CLUB: suit_str = "club"; break;
}
char const *face_str = NULL;
switch( card >> 2 ) {
case ACE: face_str = "A"; break;
case TWO: face_str = "2"; break;
case THREE: face_str = "3"; break;
case FOUR: face_str = "4"; break;
case FIVE: face_str = "5"; break;
case SIX: face_str = "6"; break;
case SEVEN: face_str = "7"; break;
case EIGHT: face_str = "8"; break;
case NINE: face_str = "9"; break;
case TEN: face_str = "10"; break;
case JACK: face_str = "J"; break;
case QUEEN: face_str = "Q"; break;
case KING: face_str = "K"; break;
}
printf("card is: %s - %s\n", suit_str, face_str);
}
void
print_cards(size_t const len, uint8_t const card[const static len]) {
for( size_t i=0; i < len; i++ ) {
print_card(card[i]);
}
}
void
init_deck(uint8_t (*const deck)[MAX_SUITS * MAX_FACES]) {
for( enum CardSuit suit = SUIT_HEART; suit < MAX_SUITS; suit++ ) {
for( enum CardFace face = ACE; face < MAX_FACES; face++ ) {
(*deck)[(suit * MAX_FACES) + face] = (suit | (face << 2));
}
}
}
void
print_deck(uint8_t const (*const deck)[MAX_SUITS * MAX_FACES]) {
for( enum CardSuit suit = SUIT_HEART; suit < MAX_SUITS; suit++ ) {
for( enum CardFace face = ACE; face < MAX_FACES; face++ ) {
print_card((*deck)[(suit * MAX_FACES) + face]);
}
}
}
struct CardDeck {
uint8_t cards[MAX_SUITS * MAX_FACES];
uint64_t removed; /// what card[s] were removed from deck.
};
struct CardDeck
card_deck_make(void) {
struct CardDeck deck;
init_deck(&deck.cards);
deck.removed = 0;
return deck;
}
void
card_deck_print(struct CardDeck const deck) {
print_deck(&deck.cards);
}
uint_fast8_t
card_deck_draw_by_index(struct CardDeck *const deck, size_t const index) {
if( index >= sizeof deck->cards ) {
return NULL_CARD;
}
size_t const bitflag = 1LU << index;
if( deck->removed & bitflag ) {
return NULL_CARD;
}
uint_fast8_t const card = deck->cards[index];
deck->removed |= bitflag;
return card;
}
uint_fast8_t
card_deck_draw_random(struct CardDeck *const deck) {
size_t index = ( size_t )(rand() % (MAX_SUITS * MAX_FACES));
uint_fast8_t card = card_deck_draw_by_index(deck, index);
if( card==NULL_CARD && deck->removed != (uint64_t)(-1LLU) ) {
while( card==NULL_CARD ) {
index = ( size_t )(rand() % (MAX_SUITS * MAX_FACES));
card = card_deck_draw_by_index(deck, index);
}
}
return card;
}
void
card_deck_draw_random_to_hands(struct CardDeck *const restrict deck, size_t const hand_len, uint8_t hand[const restrict static hand_len]) {
for( size_t i=0; i < hand_len; i++ ) {
hand[i] = card_deck_draw_random(deck);
}
}
void
sort_cards_by_face_ascending(size_t const hand_len, uint8_t hand[const static hand_len]) {
for( size_t i=0; i < hand_len; i++ ) {
for( size_t j=0; j < hand_len; j++ ) {
if( i==j ) {
continue;
} else if( (hand[i] >> 2) < (hand[j] >> 2) ) {
uint_fast8_t t = hand[i];
hand[i] = hand[j];
hand[j] = t;
}
}
}
}
void
sort_cards_by_suit_ascending(size_t const hand_len, uint8_t hand[const static hand_len]) {
for( size_t i=0; i < hand_len; i++ ) {
for( size_t j=0; j < hand_len; j++ ) {
if( i==j ) {
continue;
} else if( (hand[i] & 3) < (hand[j] & 3) ) {
uint_fast8_t t = hand[i];
hand[i] = hand[j];
hand[j] = t;
}
}
}
}
uint8_t*
combine_decks(
size_t const hand1_len,
size_t const hand2_len,
uint8_t const hand1[const restrict static hand1_len],
uint8_t const hand2[const restrict static hand2_len]
) {
uint8_t *combined_hand = calloc(hand1_len + hand2_len, sizeof *combined_hand);
for( size_t i=0; i < hand1_len; i++ ) {
combined_hand[i] = hand1[i];
}
for( size_t i=0; i < hand2_len; i++ ) {
combined_hand[hand1_len + i] = hand2[i];
}
return combined_hand;
}
bool
is_straight(
size_t const community_len,
size_t const hand_len,
uint8_t const community[const restrict static community_len],
uint8_t const hand[const restrict static hand_len],
size_t const num_cards
) {
if( num_cards > hand_len+community_len ) {
return false;
}
uint8_t *combined_hand = combine_decks(community_len, hand_len, community, hand);
size_t const combined_hand_len = community_len + hand_len;
sort_cards_by_face_ascending(combined_hand_len, combined_hand);
bool is_straight_hand = false;
for( size_t i=0; i < combined_hand_len; i++ ) {
if( is_straight_hand ) {
break;
}
size_t cascade = 0;
if( i+(num_cards-1) < combined_hand_len ) {
for( size_t n=0; n < num_cards-1; n++ ) {
cascade += (combined_hand[i+n] >> 2) == ((combined_hand[i+n+1] >> 2) - 1);
}
is_straight_hand = cascade==num_cards-1;
}
}
free(combined_hand);
return is_straight_hand;
}
bool
is_flush(
size_t const community_len,
size_t const hand_len,
uint8_t const community[const restrict static community_len],
uint8_t const hand[const restrict static hand_len],
size_t const num_cards
) {
if( num_cards > hand_len+community_len ) {
return false;
}
uint8_t *combined_hand = combine_decks(community_len, hand_len, community, hand);
size_t const combined_hand_len = community_len + hand_len;
sort_cards_by_suit_ascending(combined_hand_len, combined_hand);
bool is_flush_hand = false;
for( size_t i=0; i < combined_hand_len; i++ ) {
if( is_flush_hand ) {
break;
}
size_t cascade = 0;
if( i+(num_cards-1) < combined_hand_len ) {
for( size_t n=0; n < num_cards-1; n++ ) {
cascade += (combined_hand[i+n] & 3) == (combined_hand[i+n+1] & 3);
}
is_flush_hand = cascade==num_cards-1;
}
}
free(combined_hand);
return is_flush_hand;
}
bool
is_straight_flush(
size_t const community_len,
size_t const hand_len,
uint8_t const community[const restrict static community_len],
uint8_t const hand[const restrict static hand_len],
size_t const num_cards
) {
return is_straight(community_len, hand_len, community, hand, num_cards) && is_flush(community_len, hand_len, community, hand, num_cards);
}
bool
is_nth_of_kind(
size_t const community_len,
size_t const hand_len,
uint8_t const community[const restrict static community_len],
uint8_t const hand[const restrict static hand_len],
size_t const num_cards
) {
if( num_cards > hand_len+community_len ) {
return false;
}
uint8_t *combined_hand = combine_decks(community_len, hand_len, community, hand);
size_t const combined_hand_len = community_len + hand_len;
sort_cards_by_face_ascending(combined_hand_len, combined_hand);
bool is_nth_of_a_kind = false;
for( size_t i=0; i < combined_hand_len; i++ ) {
if( is_nth_of_a_kind ) {
break;
}
size_t cascade = 0;
if( i+(num_cards-1) < combined_hand_len ) {
for( size_t n=0; n < (num_cards-1); n++ ) {
cascade += (combined_hand[i] >> 2) == (combined_hand[i+n+1] >> 2);
}
is_nth_of_a_kind = cascade==(num_cards-1);
}
}
free(combined_hand);
return is_nth_of_a_kind;
}
int main(int const argc, char *argv[const static argc]) {
srand(time(NULL));
struct CardDeck cards = card_deck_make();
card_deck_print(cards);
puts("");
/*
enum{ HAND_SIZE = 5 };
uint8_t hand[HAND_SIZE];
card_deck_draw_random_to_hands(&cards, HAND_SIZE, hand);
print_cards(HAND_SIZE, hand);
puts("");
sort_cards_by_face_ascending(HAND_SIZE, hand);
print_cards(HAND_SIZE, hand);
*/
puts("");
bool const straight = is_straight(5, 2, (uint8_t[]){ make_card(SUIT_HEART, FOUR), make_card(SUIT_CLUB, THREE), make_card(SUIT_DIAMOND, TWO), make_card(SUIT_SPADE, FIVE), make_card(SUIT_SPADE, SIX) }, (uint8_t[]){ make_card(SUIT_HEART, KING), make_card(SUIT_CLUB, QUEEN) }, 5);
printf("is straight?: %s\n", straight? "yes" : "no");
puts("");
bool const flushed = is_flush(5, 2, (uint8_t[]){ make_card(SUIT_HEART, FOUR), make_card(SUIT_HEART, THREE), make_card(SUIT_HEART, TWO), make_card(SUIT_HEART, FIVE), make_card(SUIT_HEART, SIX) }, (uint8_t[]){ make_card(SUIT_CLUB, KING), make_card(SUIT_CLUB, QUEEN) }, 5);
printf("is flush?: %s\n", flushed? "yes" : "no");
bool const foured = is_nth_of_kind(5, 2, (uint8_t[]){ make_card(SUIT_HEART, FOUR), make_card(SUIT_CLUB, FOUR), make_card(SUIT_DIAMOND, FOUR), make_card(SUIT_HEART, FIVE), make_card(SUIT_HEART, SIX) }, (uint8_t[]){ make_card(SUIT_SPADE, FOUR), make_card(SUIT_CLUB, QUEEN) }, 4);
printf("is foured?: %s\n", foured? "yes" : "no");
}
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
enum CardSuit {
SUIT_CLUB,
SUIT_DIAMOND,
SUIT_HEART,
SUIT_SPADE,
MAX_SUITS,
};
enum CardFace {
TWO, THREE,
FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN,
JACK, QUEEN, KING,
ACE,
MAX_FACES,
};
static char const *restrict cards_cstr[] = {
"🃒", "🃓", "🃔", "🃕", "🃖", "🃗", "🃘", "🃙", "🃚", "🃛", "🃝", "🃞", "🃑",
"🃂", "🃃", "🃄", "🃅", "🃆", "🃇", "🃈", "🃉", "🃊", "🃋", "🃍", "🃎", "🃁",
"🂲", "🂳", "🂴", "🂵", "🂶", "🂷", "🂸", "🂹", "🂺", "🂻", "🂽", "🂾", "🂱",
"🂢", "🂣", "🂤", "🂥", "🂦", "🂧", "🂨", "🂩", "🂪", "🂫", "🂭", "🂮", "🂡",
"🂠", "🂠", "🂠", "🂠", "🂠", "🂠", "🂠", "🂠", "🂠", "🂠", "🂠", "🂠",
};
enum {
MAX_DECK_CSTR_LEN = sizeof "🂡" * (MAX_CARDS),
MAX_CARDS = (MAX_SUITS * MAX_FACES),
};
size_t
bit_index_from_card(enum CardSuit const suit, enum CardFace const face) {
return (suit * MAX_FACES) + face;
}
void
card_from_bit_index(size_t const index, enum CardSuit *const suit, enum CardFace *const face) {
*suit = index / MAX_FACES;
*face = index % MAX_FACES;
}
uint64_t
bit_index_to_deck(size_t const idx) {
return (1ULL << idx);
}
uint64_t
card_to_deck(enum CardSuit const suit, enum CardFace const face) {
return (1ULL << bit_index_from_card(suit, face));
}
uint64_t
make_52_card_deck(void) {
return (1ULL << 52ULL) - 1;
}
bool
has_card_idx(uint64_t const hand, size_t const idx) {
return (hand & (1ULL << idx)) > 0;
}
bool
has_card(uint64_t const hand, enum CardSuit const suit, enum CardFace const face) {
return has_card_idx(hand, bit_index_from_card(suit, face));
}
uint64_t
rm_card_idx(uint64_t const hand, size_t const idx) {
return hand & ~(1ULL << idx);
}
uint64_t
rm_card(uint64_t const hand, enum CardSuit const suit, enum CardFace const face) {
return rm_card_idx(hand, bit_index_from_card(suit, face));
}
uint64_t
add_card_idx(uint64_t const hand, size_t const idx) {
return hand | (1ULL << idx);
}
uint64_t
add_card(uint64_t const hand, enum CardSuit const suit, enum CardFace const face) {
return add_card_idx(hand, bit_index_from_card(suit, face));
}
char const*
cards_to_cstr(uint64_t const hand, char cards_buff[const static MAX_DECK_CSTR_LEN + 1]) {
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
for( size_t face=0; face < MAX_FACES; face++ ) {
size_t const idx = bit_index_from_card(suit, face);
if( has_card_idx(hand, idx) ) {
strcat(cards_buff, cards_cstr[idx]);
}
}
}
return cards_buff;
}
size_t
count_face_in_hand(uint64_t const hand, enum CardFace const face) {
size_t sum = 0;
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
size_t const bit_idx = bit_index_from_card(suit, face);
if( (hand & (1ULL << bit_idx))==0 ) {
continue;
}
sum += 1;
}
return sum;
}
enum CardFace
highest_face_in_hand(uint64_t const hand) {
for( size_t face=KING; face < MAX_FACES; face-- ) {
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
size_t const bit_idx = bit_index_from_card(suit, face);
if( hand & (1ULL << bit_idx) ) {
return face;
}
}
}
return MAX_FACES;
}
bool
has_flush(uint64_t const hand, size_t const num) {
bool flush = false;
if( num > MAX_FACES ) {
return flush;
}
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
if( flush ) {
break;
}
size_t cascade = 0;
for( size_t face=0; face < MAX_FACES; face++ ) {
size_t const bit_idx = bit_index_from_card(suit, face);
if( (hand & (1ULL << bit_idx))==0 ) {
continue;
}
cascade += 1;
}
flush = cascade==num;
}
return flush;
}
bool
has_straight(uint64_t const hand, size_t const num) {
bool straight = false;
if( num > MAX_FACES ) {
return straight;
}
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
if( straight ) {
break;
}
size_t cascade = 0;
bool found_first = false;
for( size_t face=0; face < MAX_FACES; face++ ) {
size_t const bit_idx = bit_index_from_card(suit, face);
if( (hand & (1ULL << bit_idx))==0 ) {
if( !found_first ) {
continue;
} else {
break;
}
}
found_first = true;
cascade += 1;
}
straight = cascade==num;
}
return straight;
}
bool
has_straight_flush(uint64_t const hand, size_t const num) {
return has_flush(hand, num) && has_straight(hand, num);
}
bool
has_royal_flush(uint64_t const hand, size_t const num) {
bool const flushed = has_flush(hand, num);
if( !flushed ) {
return false;
}
size_t num_faces[MAX_FACES] = {0};
for( size_t face=0; face < MAX_FACES; face++ ) {
num_faces[face] = count_face_in_hand(hand, face);
}
return num_faces[ACE] && num_faces[KING] && num_faces[QUEEN] && num_faces[JACK] && num_faces[TEN];
}
bool
has_nth_of_kind(uint64_t const hand, size_t const num) {
bool nth_kind = false;
if( num > MAX_SUITS ) {
return nth_kind;
}
for( size_t face=0; face < MAX_FACES; face++ ) {
if( nth_kind ) {
break;
}
size_t cascade = 0;
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
size_t const bit_idx = bit_index_from_card(suit, face);
if( (hand & (1ULL << bit_idx))==0 ) {
continue;
}
cascade += 1;
}
nth_kind = cascade==num;
}
return nth_kind;
}
bool
has_full_house(uint64_t const hand, size_t const num) {
if( num > MAX_FACES ) {
return false;
}
size_t num_faces[MAX_FACES] = {0};
for( size_t face=0; face < MAX_FACES; face++ ) {
num_faces[face] = count_face_in_hand(hand, face);
}
/// sort descending order.
for( size_t i=0; i < MAX_FACES; i++ ) {
for( size_t j=0; j < MAX_FACES; j++ ) {
if( i==j ) {
continue;
} else if( num_faces[i] > num_faces[j] ) {
size_t t = num_faces[i];
num_faces[i] = num_faces[j];
num_faces[j] = t;
}
}
}
return (num_faces[0] + num_faces[1])==num;
}
int
main(int const argc, char *argv[const restrict static argc]) {
srand(time(NULL));
/*
printf("has_flush: %i\n", has_flush(31, 5));
printf("has_straight: %i\n", has_straight(0x1F00000, 5));
printf("has_nth_of_kind: %i\n", has_nth_of_kind(card_to_deck(SUIT_HEART, ACE) | card_to_deck(SUIT_DIAMOND, ACE) | card_to_deck(SUIT_CLUB, ACE) | card_to_deck(SUIT_SPADE, ACE), 4));
printf("has_full_house: %i\n", has_full_house(card_to_deck(SUIT_HEART, ACE) | card_to_deck(SUIT_DIAMOND, ACE) | card_to_deck(SUIT_CLUB, ACE) | card_to_deck(SUIT_SPADE, TWO) | card_to_deck(SUIT_DIAMOND, TWO) | card_to_deck(SUIT_CLUB, TWO), 6));
printf("has_royal_flush: %i\n", has_royal_flush(card_to_deck(SUIT_HEART, ACE) | card_to_deck(SUIT_HEART, KING) | card_to_deck(SUIT_HEART, QUEEN) | card_to_deck(SUIT_HEART, JACK) | card_to_deck(SUIT_HEART, NINE) | card_to_deck(SUIT_CLUB, TWO), 5));
*/
enum {
NUM_PLAYERS = 5,
START_CASH = 1000,
START_BLIND = 20,
MAIN_PLAYER = 0,
};
bool keep_playing = true;
enum GameState {
INIT = 0, /// give everybody their cards, remove blinds from players.
PLAY = 1, /// fold, bet, raise, or check if nobody raised, for each player.
DRAW3 = 2, /// get the first 3 community cards.
DRAW1_1 = 4, /// get the second-to-last community card.
DRAW1_2 = 8, /// get the last community card.
SHOWDOWN, /// determine winner, winner takes all.
};
while( keep_playing ) {
uint64_t deck = make_52_card_deck();
uint32_t player_folded[NUM_PLAYERS] = {false};
//uint32_t player_cash[NUM_PLAYERS] = {START_CASH};
uint64_t player_hands[NUM_PLAYERS] = {0};
uint64_t community = 0;
for( size_t i=0; i < NUM_PLAYERS; i++ ) {
size_t saved_index = ( size_t )(rand()) % (MAX_CARDS);
while( !has_card_idx(deck, saved_index) ) {
saved_index = ( size_t )(rand()) % (MAX_CARDS);
}
deck = rm_card_idx(deck, saved_index);
player_hands[i] = add_card_idx(player_hands[i], saved_index);
while( !has_card_idx(deck, saved_index) ) {
saved_index = ( size_t )(rand()) % (MAX_CARDS);
}
deck = rm_card_idx(deck, saved_index);
player_hands[i] = add_card_idx(player_hands[i], saved_index);
}
char hand_cstr[MAX_DECK_CSTR_LEN + 1] = {0};
printf("your hand: %s\nwould you like to fold or play?:\n", cards_to_cstr(player_hands[MAIN_PLAYER], hand_cstr));
char response[12] = {0};
scanf(" %11s", response);
#define FLUSH_STDIN() \
do { \
int c = 0; \
while((c = getchar()) != '\n' && c != EOF); \
} while(0)
FLUSH_STDIN();
if( tolower(response[0]) != 'p' ) {
printf("would you like to keep playing?:\n");
scanf(" %11s", response);
FLUSH_STDIN();
keep_playing = response[0]=='1' || tolower(response[0])=='y';
continue;
}
/// have AI determine if it should fold or not. Later...
/// Get community cards.
for( size_t i=0; i < 3; i++ ) {
size_t saved_index = ( size_t )(rand()) % MAX_CARDS;
while( !has_card_idx(deck, saved_index) ) {
saved_index = ( size_t )(rand()) % MAX_CARDS;
}
deck = rm_card_idx(deck, saved_index);
community = add_card_idx(community, saved_index);
}
/// Make bet, raise, or check.
/// Get Penultimate community card.
/// Make bet, raise, or check.
/// Get final community card.
/// Make final bet, raise, or check.
/// Showdown and determine winner.
}
}
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
enum CardSuit {
SUIT_AT,
SUIT_HASH,
SUIT_DOLLAR,
SUIT_PERCENT,
MAX_SUITS,
};
enum {
MAX_FACES = sizeof(uint16_t),
};
struct CardFace {
uint8_t val : 4;
};
size_t
bit_index_from_card(enum CardSuit const suit, struct CardFace const face) {
return (suit * MAX_FACES) + face.val;
}
void
card_from_bit_index(size_t const index, enum CardSuit *const suit, struct CardFace *const face) {
*suit = index / sizeof(uint16_t);
face->val = index % sizeof(uint16_t);
}
uint64_t
bit_index_to_deck(size_t const idx) {
return (1ULL << idx);
}
uint64_t
card_to_deck(enum CardSuit const suit, struct CardFace const face) {
return (1ULL << bit_index_from_card(suit, face));
}
uint64_t
make_hex_card_deck(void) {
return -1ULL;
}
bool
has_card_idx(uint64_t const hand, size_t const idx) {
return (hand & (1ULL << idx)) > 0;
}
bool
has_card(uint64_t const hand, enum CardSuit const suit, struct CardFace const face) {
return has_card_idx(hand, bit_index_from_card(suit, face));
}
uint64_t
rm_card_idx(uint64_t const hand, size_t const idx) {
return hand & ~(1ULL << idx);
}
uint64_t
rm_card(uint64_t const hand, enum CardSuit const suit, struct CardFace const face) {
return rm_card_idx(hand, bit_index_from_card(suit, face));
}
uint64_t
add_card_idx(uint64_t const hand, size_t const idx) {
return hand | (1ULL << idx);
}
uint64_t
add_card(uint64_t const hand, enum CardSuit const suit, struct CardFace const face) {
return add_card_idx(hand, bit_index_from_card(suit, face));
}
char const*
cards_to_cstr(uint64_t const hand, char cards_buff[const static (MAX_SUITS * MAX_FACES) + 1]) {
char const suits[] = "@#$%";
char const faces[] = "0123456789ABCDEF";
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
for( size_t face=0; face < MAX_FACES; face++ ) {
size_t const idx = bit_index_from_card(suit, (struct CardFace){face});
if( has_card_idx(hand, idx) ) {
sprintf(cards_buff, "%c%c", suits[suit], faces[face]);
}
}
}
return cards_buff;
}
size_t
count_face_in_hand(uint64_t const hand, struct CardFace const face) {
size_t sum = 0;
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
size_t const bit_idx = bit_index_from_card(suit, face);
if( (hand & (1ULL << bit_idx))==0 ) {
continue;
}
sum += 1;
}
return sum;
}
int
highest_face_in_hand(uint64_t const hand) {
for( size_t face=0xF; face < MAX_FACES; face-- ) {
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
size_t const bit_idx = bit_index_from_card(suit, (struct CardFace){face});
if( hand & (1ULL << bit_idx) ) {
return face;
}
}
}
return -1;
}
bool
has_flush(uint64_t const hand, size_t const num) {
bool flush = false;
if( num > MAX_FACES ) {
return flush;
}
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
if( flush ) {
break;
}
size_t cascade = 0;
for( size_t face=0; face < MAX_FACES; face++ ) {
size_t const bit_idx = bit_index_from_card(suit, (struct CardFace){face});
if( (hand & (1ULL << bit_idx))==0 ) {
continue;
}
cascade += 1;
}
flush = cascade==num;
}
return flush;
}
bool
has_straight(uint64_t const hand, size_t const num) {
bool straight = false;
if( num > MAX_FACES ) {
return straight;
}
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
if( straight ) {
break;
}
size_t cascade = 0;
bool found_first = false;
for( size_t face=0; face < MAX_FACES; face++ ) {
size_t const bit_idx = bit_index_from_card(suit, (struct CardFace){face});
if( (hand & (1ULL << bit_idx))==0 ) {
if( !found_first ) {
continue;
} else {
break;
}
}
found_first = true;
cascade += 1;
}
straight = cascade==num;
}
return straight;
}
bool
has_straight_flush(uint64_t const hand, size_t const num) {
return has_flush(hand, num) && has_straight(hand, num);
}
bool
has_royal_flush(uint64_t const hand, size_t const num) {
bool const flushed = has_flush(hand, num);
if( !flushed ) {
return false;
}
size_t num_faces[MAX_FACES] = {0};
for( size_t face=0; face < MAX_FACES; face++ ) {
num_faces[face] = count_face_in_hand(hand, (struct CardFace){face});
}
return num_faces[0xb] && num_faces[0xc] && num_faces[0xd] && num_faces[0xe] && num_faces[0xf];
}
bool
has_nth_of_kind(uint64_t const hand, size_t const num) {
bool nth_kind = false;
if( num > MAX_SUITS ) {
return nth_kind;
}
for( size_t face=0; face < MAX_FACES; face++ ) {
if( nth_kind ) {
break;
}
size_t cascade = 0;
for( size_t suit=0; suit < MAX_SUITS; suit++ ) {
size_t const bit_idx = bit_index_from_card(suit, (struct CardFace){face});
if( (hand & (1ULL << bit_idx))==0 ) {
continue;
}
cascade += 1;
}
nth_kind = cascade==num;
}
return nth_kind;
}
bool
has_full_house(uint64_t const hand, size_t const num) {
if( num > MAX_FACES ) {
return false;
}
size_t num_faces[MAX_FACES] = {0};
for( size_t face=0; face < MAX_FACES; face++ ) {
num_faces[face] = count_face_in_hand(hand, (struct CardFace){face});
}
/// sort descending order.
for( size_t i=0; i < MAX_FACES; i++ ) {
for( size_t j=0; j < MAX_FACES; j++ ) {
if( i==j ) {
continue;
} else if( num_faces[i] > num_faces[j] ) {
size_t t = num_faces[i];
num_faces[i] = num_faces[j];
num_faces[j] = t;
}
}
}
return (num_faces[0] + num_faces[1])==num;
}
int
main(int const argc, char *argv[const restrict static argc]) {
srand(time(NULL));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment