模擬撲克牌的洗牌發牌

在內存中模擬出一副牌,然後模擬洗牌,發牌等動作
流程:構建一副牌保存到一個數組中–>洗牌–>創建玩家–>向玩家發牌–>輸出每個玩家的牌

#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;
}

這裏寫圖片描述

發佈了73 篇原創文章 · 獲贊 107 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章