本專案在記憶體中模擬一副 54 張撲克牌,實作洗牌、發牌、玩家管理與手牌排序功能,展示 C 結構體、指標陣列、動態記憶體管理與演算法應用。
enum Suit { HEART, SPADE, DIAMOND, CLUB, JOKER_SMALL, JOKER_BIG };
const int CARD_COUNT = 54;
struct Card {
int value; // 1=A, 11=J, 12=Q, 13=K, 14=小王, 15=大王
Suit suit;
};
struct Player {
char name[64];
Card** cards; // 指向原始牌陣列的指標陣列,節省空間
int cardCount;
};
Card g_deck[CARD_COUNT];
void InitDeck() {
int idx = 0;
// 52 張一般牌
for (int i = 0; i < CARD_COUNT - 2; i++) {
g_deck[idx].value = i / 4 + 1; // 1~13 循環 4 次
g_deck[idx].suit = static_cast(i % 4);
idx++;
}
// 兩張王
g_deck[idx++] = {14, JOKER_SMALL};
g_deck[idx++] = {15, JOKER_BIG};
}
使用 Fisher-Yates 洗牌,隨機交換位置,產生指標陣列避免移動實際 Card 結構。
Card** Shuffle() {
Card** shuffled = new Card*[CARD_COUNT];
Card** temp = new Card*[CARD_COUNT];
for (int i = 0; i < CARD_COUNT; i++) temp[i] = &g_deck[i];
for (int i = 0; i < CARD_COUNT; i++) {
int r = rand() % CARD_COUNT;
while (temp[r] == nullptr) r = (r + 1) % CARD_COUNT; // 找下一張未用
shuffled[i] = temp[r];
temp[r] = nullptr;
}
delete[] temp;
return shuffled;
}
void Deal(Player** players, int playerCount, Card** shuffled) {
int cardsPerPlayer = CARD_COUNT / playerCount + 1;
for (int i = 0; i < playerCount; i++) {
players[i]->cards = new Card*[cardsPerPlayer];
players[i]->cardCount = 0;
}
for (int i = 0; i < CARD_COUNT; i++) {
Player* p = players[i % playerCount];
p->cards[p->cardCount++] = shuffled[i];
}
}
支援自訂比較函數(升序/降序),使用氣泡排序教學示意。
typedef int (*CompareFunc)(Card*, Card*);
void SortHand(Card** hand, int count, CompareFunc cmp) {
for (int i = 0; i < count - 1; i++)
for (int j = 0; j < count - i - 1; j++)
if (cmp(hand[j], hand[j+1])) {
Card* tmp = hand[j];
hand[j] = hand[j+1];
hand[j+1] = tmp;
}
}
// 升序:先比點數,再比花色
int CompareAsc(Card* a, Card* b) {
if (a->value != b->value) return a->value > b->value;
return a->suit > b->suit;
}
// 降序
int CompareDesc(Card* a, Card* b) {
if (a->value != b->value) return a->value < b->value;
return a->suit < b->suit;
}
char* GetCardName(const Card* c) {
static const char* suits[] = {"紅桃", "黑桃", "方塊", "梅花"};
static const char* values[] = {"", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "小王", "大王"};
char* name = new char[16];
if (c->value >= 14) // 王
sprintf(name, "%s", values[c->value]);
else
sprintf(name, "%s%s", suits[c->suit], values[c->value]);
return name; // 呼叫端需 delete[]
}
int main() {
srand(time(nullptr));
InitDeck();
Card* shuffled = Shuffle();
Player p1{"隔壁老王"}, p2{"小明"}, p3{"田中龜孫"};
Player* players[] = {&p1, &p2, &p3};
Deal(players, 3, shuffled);
delete[] shuffled;
for (auto p : players) {
cout << p->name << ": ";
SortHand(p->cards, p->cardCount, CompareAsc);
for (int i = 0; i < p->cardCount; i++) {
char* name = GetCardName(p->cards[i]);
cout << name << ' ';
delete[] name;
}
cout << endl;
delete[] p->cards;
}
return 0;
}
隔壁老王: 梅花A 方塊2 紅桃3 黑桃4 ... 小明: 方塊A 梅花2 黑桃3 紅桃4 ... 田中龜孫: 黑桃A 紅桃2 梅花3 方塊4 ...
專案展示了指標陣列管理物件、回調函數實現策略模式、動態記憶體分配釋放等核心 C/C++ 技能。