在內存中模擬出一副牌,然後模擬洗牌,發牌等動作
流程:構建一副牌保存到一個數組中–>洗牌–>創建玩家–>向玩家發牌–>輸出每個玩家的牌
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
//一副牌的數量
#define CARD_COUNT 54
//定義撲克的花色, 黑,紅,梅,方,小王 ,大王
enum Color{BLACK, RED, CLUB, DIAMOND, JOKER1, JOKER2};
//定義撲克結構體
typedef struct Card
{
int val; //撲克牌點數
enum Color color; //花色
}Card;
//定義玩家
typedef struct Player
{
char name[64]; //玩家名字
Card** cards; //玩家分到的牌,每項是一個指針,指向原始一副牌數組中的一項,這樣可以節省空間
int cardsCount; //每個玩家分到的牌的數量
}Player;
//分完牌後調用的函數的類型
typedef int (*pCompare)(Card*, Card*);
//原始一副牌所在的數組
Card pokers[CARD_COUNT];
//初始化一副牌
void InitOnePoker()
{
//前52張
int i=0;
for (i=0; i<CARD_COUNT-2; ++i)
{
pokers[i].val = i/4 + 1;
pokers[i].color = (Color)(i%4);
}
//剩下的大王和小王
pokers[i].val = i/4 + 1;
pokers[i].color = JOKER1;
//大王
pokers[i+1].val = i/4 + 2;
pokers[i+1].color = JOKER2;
}
//洗牌,參數是最原始的一副牌,返回洗完後的牌
Card** Shuffle(Card* pokers)
{
//分牌返回牌數組的內存空間
Card** retPokers = (Card**)malloc(sizeof(Card*)*CARD_COUNT);
//爲了不改動原始的一副牌,另建一個數組,保存原始牌的指針(注意每項不是牌,而是牌的指針)
Card** pokers2 = (Card**)malloc(sizeof(Card*)*CARD_COUNT);
for (int i=0; i<CARD_COUNT; ++i)
{
pokers2[i] = &pokers[i];
}
//種下隨機種子,種子取當前時間,保證了每次運行程序時,產生的隨機數不同
srand(time(NULL));
//取得隨機序號,從pokers2取出序號所指的項,依次加入到retPokers中
for (int i=0; i<CARD_COUNT; ++i)
{
unsigned int index = rand() % CARD_COUNT;
//說明沒有選過
if (pokers2[index] != NULL)
{
retPokers[i] = pokers2[index];
pokers2[index] = NULL;
}
else
{
--i;
}
}
free(pokers2);
//返回洗完牌後的數組
return retPokers;
}
//發牌
//players是玩家數組,playerCount是玩家數量,shuffledCard是洗完後的一副牌
void DispatchCards(Player** players, int playerCount, Card** shuffledCard)
{
//計算每個玩家手中牌的數組的容量,如果每個玩家手中的牌不一樣
//最多就差一張,加1是爲了保證數組分配的空間足夠容納分到的牌
int numberCards = CARD_COUNT/playerCount + 1;
//爲每個玩家的牌數組分配空間
for (int i=0; i<playerCount; ++i)
{
Card** cards = (Card**)malloc(sizeof(Card*)*numberCards);
players[i]->cards = cards;
}
//輪流向每個玩家發牌
for (int i=0; i<CARD_COUNT; ++i)
{
//取當前玩家
Player* curPlayer = players[i%playerCount];
//向玩家發牌
curPlayer->cards[curPlayer->cardsCount] = shuffledCard[i];
//玩家手中實際的牌數增加
curPlayer->cardsCount++;
}
}
//排序函數
//cards是要排序的牌,每一項是牌的指針,cardsCount是牌的數量,compare_fun是比較函數
void SortCards(Card** cards, int cardsCount, pCompare compare_fun)
{
//Optimize Bubble Sort
bool flag = true;
for (int i=0; i<cardsCount-1; ++i)
{
flag = true;
for (int j=0; j<cardsCount-1-i; ++j)
{
if (compare_fun(cards[j], cards[j+1]))
{
//swap
Card* tmp = cards[j];
cards[j] = cards[j+1];
cards[j+1] = tmp;
flag = false;
}
}
if (flag)
break;
}
}
//比較函數1:先比較點數再比較花色(升序)
int compare1(Card* a, Card* b)
{
if (a->val > b->val)
return 1;
else if (a->val < b->val)
return 0;
else
{
if (a->color > b->color)
return 1;
else
return 0;
}
}
//比較函數2:比較點數再比較花色(降序)
int compare2(Card* a, Card* b)
{
if (a->val < b->val)
return 1;
else if (a->val > b->val)
return 0;
else
{
if (a->color < b->color)
return 1;
else
return 0;
}
}
//獲取牌的名字
//返回牌的名字字符串,調用着用完之後要free()之
char* GetCardName(const Card* card)
{
//存放花色名字
char ColorStr[16] = "";
switch (card->color)
{
case BLACK: strcpy(ColorStr, "黑桃"); break;
case RED: strcpy(ColorStr, "紅桃"); break;
case CLUB: strcpy(ColorStr, "梅花"); break;
case DIAMOND: strcpy(ColorStr, "方塊"); break;
}
//存放點數名字
char valStr[16] = "";
switch (card->val)
{
case 1: strcpy(valStr, "A"); break;
case 11:strcpy(valStr, "J"); break;
case 12:strcpy(valStr, "Q"); break;
case 13:strcpy(valStr, "K"); break;
case 14:strcpy(valStr, "小王"); break;
case 15:strcpy(valStr, "大王"); break;
default:sprintf(valStr, "%d", card->val); break;
}
//動態分配足夠的空間
char* ret = (char*)malloc(sizeof(char)*16);
//將兩個字符串合併到ret中
sprintf(ret, "%s%s", ColorStr, valStr);
return ret;
}
//打印玩家手中的牌
void PrintCard(Player** players, int n)
{
//打印每個玩家手中的牌
for (int i=0; i<n; ++i)
{
//打印玩家名字
printf("%s:\n", players[i]->name);
//對玩家手中的牌排序
SortCards(players[i]->cards, players[i]->cardsCount, compare1);
//打印玩家手中的牌
int fomart = 0;
for (int j=0; j<players[i]->cardsCount; ++j)
{
//得到牌的名字
char* name = GetCardName(players[i]->cards[j]);
//打印牌的名字
printf("%s\t", name);
++fomart;
if (fomart%5 == 0)
printf("\n");
//釋放
free(name);
name = NULL;
}
printf("\n");
}
}
int main()
{
//初始化一副牌
InitOnePoker();
//洗牌,shuffledPokers保存洗後的牌
Card** shuffledPokers = Shuffle(pokers);
//構建n個玩家
int n;
printf("please input the number of player: ");
scanf("%d", &n);
Player* playersInfo = (Player*)malloc(sizeof(Player)*n);
char name[16] = "";
printf("please input the name of every player: ");
for (int i=0; i<n; ++i)
{
scanf("%s", name);
strcpy(playersInfo[i].name, name);
playersInfo[i].cards = NULL;
playersInfo[i].cardsCount = 0;
}
//把n個放在一個數組中,以便傳入發牌函數中
Player** players = (Player**)malloc(sizeof(Player*)*n);
for (int i=0; i<n; ++i)
{
players[i] = &playersInfo[i];
}
//發牌
DispatchCards(players, n, shuffledPokers);
//洗後的牌用完了,釋放掉
free(shuffledPokers);
//打印玩家手中的牌
PrintCard(players, n);
//釋放玩家手中的牌數組
for (int i=0; i<n; ++i)
{
free(players[i]->cards);
}
//釋放每個玩家所在的數組
free(players);
players = NULL;
//釋放每個玩家的信息
free(playersInfo);
playersInfo = NULL;
return 0;
}