Ще цікавіше. Для початку визначимо, що будемо називати колодою. В моїх уявленях колодою можна назвати будь-яку 1-вимірну впорядковану колекцію карт. За замовчаням будемо уважати, що гравець може взяти тільки верхню або нижню карту з колоди, при цьому кількість карт в колоді зменшиться на 1 і кількість карт у гравця збільшиться на 1. Крім того, іноді колоду треба буде перемішувати (shuffle), для цього можна розбити колоду на 2 менші колоди. Майже кожна карта в колоді має "сусіда" з верху і з низу.
Все це впливає на вибір структури даних, в яких будемо зберігати всі карти колоди. В даному випадку 1-вимірний 2-напрямний звязний список прекрасно підійде для зберіганя і розбитя колоди. Структура "колода" (struct deck) буде містити інфо про (вказівники на) верхній і низній "елементи". Сам "елемент" (node) буде містити карту і інфо про (вказівники на) "сусідів" (елементи під- (next) і над- (prev)).
// Deck.h
#ifndef _DECK_H
#define _DECK_H
#include<stdbool.h>
#include"Card.h"
#include"Uint.h"
// Колода карт
typedef struct Deck {
    struct Node *top;
    struct Node *bottom;
} Deck;
typedef struct Node {
    Card card;
    struct Node *next;
    struct Node *prev;
} Node;
Deck const EMPTY_DECK;
bool is_empty(Deck const *const);
int get_cards_count(Deck const *const);
void put_card_on_top(Deck *, Card const);
void put_card_under_bottom(Deck *, Card const);
void unite_decks(Deck *bottom, Deck *top);
Card take_card_from_top(Deck *);
Card take_card_from_bottom(Deck *);
Deck *take_deck_from(Deck *, int count);
void free_deck(Deck *);
Deck *new_deck(Uint const min_rank, Uint const max_rank);
Deck *new_deck_36(void);
Deck *new_deck_52(void);
void rotate_deck(Deck *, int offset);
void shuffle_deck(Deck *);
void print_deck(Deck const *const, Uint const columns);
void print_deck_with(Deck const *const, Uint const columns, int(*const printf)(char const *const, ...));
#endif // _DECK_H
Деякі функції далекі від оптимального рішеня. Якщо знайдете косяки, пишіть.
Функції new_deck* виділяють память під нову колоду, наповнюють її, і повертають вказівник на неї. Не загубіть його, бо потім цю память треба буде звільнити через free_deck (або free, залежить від користаня).
Функція shuffle_deck симулює перемішуваня карт в колоді так, як це робить людина.
// Deck.c
#include<stdbool.h>
#include<stdio.h>
#include<stdlib.h>
#include"Card.h"
#include"Deck.h"
#include"Rank.h"
#include"Uint.h"
Deck const EMPTY_DECK = { NULL, NULL };
bool is_empty(Deck const *const deck) { return !deck->top; }
int get_cards_count(Deck const *const deck) {
    int count = 0;
    if(deck) {
        Node *node = deck->top;
        while(node) {
            ++count;
            node = node->next;
        }
    }
    return count;
}
void put_card_on_top(Deck *deck, Card const card) {
    if(!deck) return;
    Node *const top = malloc(sizeof(Node));
    *top = (Node){ card, deck->top, NULL };
    if(deck->top) deck->top->prev = top;
    else deck->bottom = top;
    deck->top = top;
}
void put_card_under_bottom(Deck *deck, Card const card) {
    if(!deck) return;
    Node *const bottom = malloc(sizeof(Node));
    *bottom = (Node){ card, NULL, deck->bottom };
    if(deck->bottom) deck->bottom->next = bottom;
    else deck->top = bottom;
    deck->bottom = bottom;
}
void unite_decks(Deck *bottom, Deck *top) {
    if(!bottom || !top) return;
    if(top->bottom) top->bottom->next = bottom->top;
    if(bottom->top) bottom->top->prev = top->bottom;
    if(bottom->bottom) top->bottom = bottom->bottom;
    else bottom->bottom = top->bottom;
    if(top->top) bottom->top = top->top;
    else top->top = bottom->top;
}
Card take_card_from_top(Deck *deck) {
    if(!deck) return NO_CARD;
    Node *const top = deck->top;
    if(!top) return NO_CARD;
    if(deck->top = top->next)
        deck->top->prev = NULL;
    else deck->bottom = NULL;
    top->next = NULL;
    Card const card = top->card;
    top->card = NO_CARD;
    free(top);
    return card;
}
Card take_card_from_bottom(Deck *deck) {
    rotate_deck(deck, -1);
    return take_card_from_top(deck);
}
Deck *take_deck_from(Deck *deck, int count) {
    Deck *const top = malloc(sizeof(Deck));
    *top = EMPTY_DECK;
    if(!count || !deck || !deck->top) return top;
    if(count < 0) {
        if(-count < get_cards_count(deck))
            rotate_deck(deck, count);
        count = -count;
    }
    Node *node = deck->top, *next = node->next;
    while(--count > 0 && next)
        next = (node = next)->next;
    *top = (Deck){ deck->top, node };
    if(deck->top = next)
        next->prev = NULL;
    else deck->bottom = NULL;
    node->next = NULL;
    return top;
}
void free_deck(Deck *deck) {
    if(!deck) return;
    Node *node = deck->top, *next;
    while(node) {
        next = node->next;
        // *node = (Node){ (Card){ 0 }, NULL, NULL };
        free(node);
        node = next;
    }
    // *deck = EMPTY_DECK;
    free(deck);
}
Deck *new_deck(Uint const min_rank, Uint const max_rank) {
    Deck *const deck = malloc(sizeof(Deck));
    *deck = EMPTY_DECK;
    for(Uint r = min_rank; r <= max_rank; ++r)
        for(Uint s = 0; s < 4; ++s)
            put_card_on_top(deck, (Card){ s, r });
    return deck;
}
Deck *new_deck_36(void) { return new_deck(6, Ace); }
Deck *new_deck_52(void) { return new_deck(2, Ace); }
void rotate_deck(Deck *deck, int offset) {
    int count = get_cards_count(deck);
    if(count <= 1) return;
    offset = (offset % count + count) % count;
    if(!offset) return;
    Node *node = deck->bottom;
    (node->next = deck->top)->prev = node;
    do
        node = node->next;
    while(--offset > 0);
    (deck->top = node->next)->prev = NULL;
    (deck->bottom = node)->next = NULL;
}
void shuffle_deck(Deck *deck) {
    int count = get_cards_count(deck);
    if(count <= 1) return;
    int few_times = rand() % 3 + 3;
    Deck *base, *left, *top, *bottom;
    do {
        base = take_deck_from(NULL, 0);
        left = deck;
        do {
            top = take_deck_from(left, rand() % ((count >> 3) + 1) + 1);
            bottom = take_deck_from(left, -(rand() % ((count >> 3) + 1)));
            unite_decks(bottom, top);
            unite_decks(base, top);
            free(top);
            free(bottom);
        } while(left->top);
        *deck = *base;
        free(base);
        rotate_deck(deck, rand());
    } while(--few_times);
}
void print_deck(Deck const *const deck, Uint const columns) {
    print_deck_with(deck, columns, printf);
}
void print_deck_with(Deck const *const deck, Uint const columns, int(*const printf)(char const *const, ...)) {
    printf("\r\n");
    if(!deck) return;
    Node *node = deck->top;
    int i = 0;
    while(node) {
        printf(" ");
        print_card_with(node->card, printf);
        node = node->next;
        if(columns <= ++i) {
            printf("\r\n");
            i = 0;
        }
    }
}