自动计算空当接龙的步骤

时间:2022-03-04 03:24:04

///////////////////////////////////////////////////////////////////////////
// fc by daineng@nj.cpsecure
// MSN  : daineng@msn.com
// ------------------------------------------------------------------------
// This program will find the steps helping you walk out of the puzzle of
// the Micro$oft Game: 'Freecell', The steps is not the best, but it is
// that could be found out on Linux with 128M memory in VMWare, in little
// time.
// I write it w/ C++/STL in Redhat7.3 & Redhat9. For Simplify my explanation
// I pass some over, such as:
//    #include <vector>
//    using namespace std;
// these also include construction function, output function...
///////////////////////////////////////////////////////////////////////////


/*-------------------- BEGIN OF THE FILE : my_except.h ------------------*/
////////////////////////////////////////////////////////////////////
// Filename: my_except.h
// Microsoft Games, FreeCell
// 20060317 by daineng@nj.cpsecure
// -----------------------------------------------------------------
// I use the except to give the warnings and the chance to walk out
// of steps-finding-loop. Here is their declaration and implement.
////////////////////////////////////////////////////////////////////

class card_except : public exception {
    // It's simple, I will not dive into details.
public:
        enum EXCEPT_TYPE {UNDEF=0, WRONG_CID, WRONG_SCARD, WRONG_TYPE, WRONG_NUMB, WRONG_DUP, WRONG_MISS};
        const char* what() const throw();
        EXCEPT_TYPE m_type;
};

class state_except : public exception {
    // It's simple, I will not dive into details
public:
        enum EXCEPT_TYPE {UNDEF=0, WRONG_STATE_MISS, WRONG_STATE_CHG_ID,
            OVERFLOW_SPACE, OVERFLOW_PILES, OVERFLOW_SLOTS,
            FINAL_STATE, WRONG_ERROR
        };
        const char* what() const throw();
        EXCEPT_TYPE m_type;
};
/*-------------------- END OF THE FILE : my_except.t --------------------*/


/*--------------------- BEGIN OF THE FILE : cards.h ---------------------*/
////////////////////////////////////////////////////////////////////
// Filename: fc.cpp
// Microsoft Games, FreeCell
// 20060317 by daineng@nj.cpsecure
////////////////////////////////////////////////////////////////////

#include "my_except.h"

#define CARD_UNDEF     -1
#define CARD_SPADE      0
#define CARD_HEART      1
#define CARD_CLUB       2
#define CARD_DIAMOND    3

class CardState;

class Card {
    public:
        Card() : number(0), type(CARD_UNDEF) {}
        Card(const string &sc) {
            if (sc.length() < 2)
                throw card_except(card_except::WRONG_SCARD, sc);
            switch (sc.at(0)) {
                case 'S':
                    type = CARD_SPADE;
                    break;
                case 'H':
                    type = CARD_HEART;
                    break;
                case 'C':
                    type = CARD_CLUB;
                    break;
                case 'D':
                    type = CARD_DIAMOND;
                    break;
                default:
                    throw card_except(card_except::WRONG_SCARD, sc);
            }
            string snum = sc.substr(1);
            number = atoi(snum.c_str());
            if (number < 1 || number > 13)
                throw card_except(card_except::WRONG_SCARD, sc);
            --number;
        }
        Card(char c) {
            if (c < 0 || c > 51)
                throw card_except(card_except::WRONG_CID, short(c));
            type = c/13;
            number = c%13;
        }
        Card(const Card &c);
        Card& operator=(const Card &c);
        bool operator>(const Card &c) {
            return ((type*13+number) > (c.type*13+c.number));
        }
    public:
        char cid() { return char(type * 13 + number); }
        string looks() const;   // The human-readable string which represents the card
    private:
        friend class CardState;
        short number;
        short type;
};

#define SLOT_SIZE   26

// This is the state-class of freecell, all the states will stored into the 'state_set',
// and retrieved when it's needed.
class StateID {
    public:
        StateID() { initialize(); }
        StateID(const StateID &sid);
        StateID& operator=(const StateID &sid);
    public:
        void initialize() {
            memset(c_space, 0xff, sizeof(c_space));
            memset(c_piles[0], 0xff, sizeof(c_piles));
            memset(c_slots[0], 0xff, sizeof(c_slots));
        }
        void Set4Test() {
            initialize();
            char _piles[4][13] = {
                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33}
            };
            char _slots[8][SLOT_SIZE] = {
                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x0C, 0x05, 0x18, 0x11, 0x24, 0x1D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x0B, 0x04, 0x17, 0x10, 0x23, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x0A, 0x03, 0x16, 0x0F, 0x22, 0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x09, 0x02, 0x15, 0x0E, 0x21, 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x08, 0x01, 0x14, 0x0D, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x07, 0x00, 0x13, 0x26, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                {0x06, 0x19, 0x12, 0x25, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
            };
            memcpy(c_piles, _piles, sizeof(c_piles));
            memcpy(c_slots, _slots, sizeof(c_slots));
        }
        // give a reliable implement of less-than operator, or you'll encounter an odd error.
        // I leave the implement to you. ;-)
        bool operator<(const StateID &sid) const;

    public:
        void showout() const;   // Output the StateID to standard-output

    private:
        friend class CardState;
        // Sorry for that I can't show you the excat meaning of 'space', 'piles',
        // and the 'slots' because of my poor English. But I'm sure you'll find
        // out what they means when you're playing the game 'Freecell'. :-)
        char c_space[4];
        char c_piles[4][13];
        char c_slots[8][SLOT_SIZE];
};

typedef set <StateID> state_set_type;

// I use it to output a state, change a state. This is the most important class.
class CardState {
    public:
        CardState() { clean_clear(); }
        CardState(const CardState &cs);
        CardState & operator=(const CardState &cs);
    public:
        void clean_clear(); // clear the steps, space, piles, and slots
        void str2state(const string &sstate) {
            clean_clear();
            int nloc;
            char cards[52];
            string str_slot, str_pile, str_card;
            string::size_type istrloc;
            str_slot = sstate;
            nloc = 0;
            memset(cards, 0, sizeof(cards));
            while (string::npos != (istrloc = str_slot.find(';'))) {
                str_pile = str_slot.substr(0, istrloc);
                str_slot = str_slot.substr(istrloc + 1);
                while (string::npos != (istrloc = str_pile.find(','))) {
                    str_card = str_pile.substr(0, istrloc);
                    str_pile = str_pile.substr(istrloc + 1);
                    Card card(str_card);
                    if (0 != cards[card.cid()])
                        throw card_except(card_except::WRONG_DUP, card.looks());
                    else
                        cards[card.cid()] = 0xff;
                    m_slots[nloc].push_back(card);
                }
                nloc++;
            }
            if (nloc < 8)
                throw state_except(state_except::WRONG_STATE_MISS);
            for (nloc = 0; nloc < 52; nloc++) {
                if ((char)0xff != cards[nloc])
                    throw card_except(card_except::WRONG_MISS, Card((char)nloc).looks());
            }
        }
        void sid2state(const StateID &sid) {
            clean_clear();
            int i, n;
            // Space
            i = 0;
            while (i < 4 && sid.c_space[i] != (char)0xff) {
                m_space.push_back(Card(sid.c_space[i]));
                ++i;
            }
            // Piles
            for (n = 0; n < 4; n++) {
                i = 0;
                while (i < 13 && sid.c_piles[n][i] != (char)0xff) {
                    m_piles[n].push_back(Card(sid.c_piles[n][i]));
                    ++i;
                }
            }
            // Slots
            for (n = 0; n < 8; n++) {
                i = 0;
                while (i < SLOT_SIZE && sid.c_slots[n][i] != (char)0xff) {
                    m_slots[n].push_back(Card(sid.c_slots[n][i]));
                    ++i;
                }
            }
        }
        void mkStateID(StateID &sid) {
            unsigned n, i;
            sid.initialize();
            // Space
            for (i = 0; i < m_space.size(); i++) {
                if (m_space.size() > 4)
                    throw state_except(state_except::OVERFLOW_SPACE);
                sid.c_space[i] = m_space[i].cid();
            }
            // Piles
            for (n = 0; n < 4; n++) {
                if (m_piles[n].size() > 13)
                    throw state_except(state_except::OVERFLOW_PILES);
                for(i = 0; i < m_piles[n].size(); i++)
                    sid.c_piles[n][i] = m_piles[n][i].cid();
            }
            // Slots
            for (n = 0; n < 8; n++) {
                if (m_slots[n].size() > SLOT_SIZE)
                    throw state_except(state_except::OVERFLOW_SLOTS);
                for(i = 0; i < m_slots[n].size(); i++)
                    sid.c_slots[n][i] = m_slots[n][i].cid();
            }
        }
        void showsid() {
            StateID sid;
            mkStateID(sid);
            sid.showout();
        }
        void showout() { showout(cout); }
        void showout(ostream &_ostr) {
            unsigned int i, n;
            // Space
            _ostr << "Space: " << endl;
            for (i = 0; i < m_space.size(); i++) {
                _ostr << '[' << m_space[i].looks() << "]  ";
            }
            _ostr << endl << endl;
            // Piles
            _ostr << "Piles:" << endl;
            for (n = 0; n < 4; n++) {
                _ostr << "  Pile[ " << n << " ]:" << endl;
                for(i = 0; i < m_piles[n].size(); i++) {
                    _ostr << '[' << m_piles[n][i].looks() << "]  ";
                }
                _ostr << endl;
            }
            _ostr << endl;
            // Slots
            _ostr << "Slots:" << endl;
            for (n = 0; n < 8; n++) {
                _ostr << "  Slot[ " << n << " ]:" << endl;
                for(i = 0; i < m_slots[n].size(); i++) {
                    _ostr << '[' << m_slots[n][i].looks() << "]  ";
                }
                _ostr << endl;
            }
            _ostr << endl;
        }
    public:
        bool final_state() {
            int n;
            if (m_space.size() > 0)
                return false;
            for (n = 0; n < 8; n++) {
                if (m_slots[n].size() > 0)
                    return false;
            }
            for (n = 0; n < 4; n++) {
                if (m_piles[n].size() < 13)
                    return false;
            }
            return true;
        }
        enum { LIMIT_DEEPTH=11 };
        bool limit_state() {
            //cout << "bool limit_state()" << endl;
            vector< state_set_type::iterator >::reverse_iterator ritor(m_steps.rbegin());
            int ideep(0);
            while (ideep < LIMIT_DEEPTH && ritor != m_steps.rend()) {
                ++ideep;
                ritor++;
            }
            if (ritor == m_steps.rend())
                return false;
            CardState _state;
            _state.sid2state(**ritor);
            if (piles_size() <= _state.piles_size())
                return true;
            return false;
        }
        int priority_level(const CardState &cs) const {
            if (piles_size() > cs.piles_size())
                return 2;
            for (int iSlot(0); iSlot < 8; iSlot++) {
                if (m_slots[iSlot].size() > cs.m_slots[iSlot].size()) {
                    if (12 == m_slots[iSlot].front().number)
                        return 1;
                }
            }
            return 0;
        }
        bool chg_state(state_set_type &state_set, int state_chg_id) {
            if (state_chg_id < 8) {
                if (chgstate_slots2piles(state_set, state_chg_id))
                    return true;
            }
            else if (state_chg_id < 64 + 8) {
                if (chgstate_slots2slots(state_set, state_chg_id))
                    return true;
            }
            else if (state_chg_id < 8 + 64 + 8) {
                if (chgstate_slots2space(state_set, state_chg_id))
                    return true;
            }
            else if (state_chg_id < 4 + 8 + 64 + 8) {
                if (chgstate_space2piles(state_set, state_chg_id))
                    return true;
            }
            else if (state_chg_id < 32 + 4 + 8 + 64 + 8) {
                if (chgstate_space2slots(state_set, state_chg_id))
                    return true;
            }
            else {
                throw state_except(state_except::WRONG_STATE_CHG_ID, state_chg_id);
            }
            return false;
        }
    private:
        bool add_idstate(state_set_type &state_set) {
            pair < state_set_type::iterator, bool > pr;
            StateID sid;
            mkStateID(sid);
            pr = state_set.insert(sid);
            if (pr.second) {
                m_steps.push_back(pr.first);
                return true;
            }
            else {
                return false;
            }
        }

        bool chgstate_slots2piles(state_set_type &state_set, int state_chg_id) {
            int nSlot = state_chg_id;
            if (m_slots[nSlot].size() <= 0)
                return false;
            if (pass_to_pile(m_slots[nSlot].back())) {
                m_slots[nSlot].pop_back();
                if (add_idstate(state_set))
                    return true;
            }
            return false;
        }

        bool chgstate_slots2slots(state_set_type &state_set, int state_chg_id) {
            int mnSlot = state_chg_id - 8;
            if (m_slots[mnSlot/8].size() <= 0)
                return false;
            if (pass_to_slot(m_slots[mnSlot/8].back(), mnSlot%8)) {
                m_slots[mnSlot/8].pop_back();
                if (add_idstate(state_set)) {
                    return true;
                }
            }
            return false;
        }

        bool chgstate_slots2space(state_set_type &state_set, int state_chg_id) {
            int nSlot = state_chg_id - 8 - 64;
            if (m_slots[nSlot].size() <= 0)
                return false;
            if (pass_to_space(m_slots[nSlot].back())) {
                m_slots[nSlot].pop_back();
                if (add_idstate(state_set))
                    return true;
            }
            return false;
        }

        bool chgstate_space2piles(state_set_type &state_set, int state_chg_id) {
            int nSpace = state_chg_id - 8 - 64 - 8;
            if (nSpace >= (int)m_space.size())
                return false;
            if (pass_to_pile(m_space[nSpace])) {
                m_space.erase(m_space.begin() + nSpace);
                if (add_idstate(state_set))
                    return true;
            }
            return false;
        }

        bool chgstate_space2slots(state_set_type &state_set, int state_chg_id) {
            int mn = state_chg_id - 8 - 64 - 8 -4;
            int nSpace = mn/8;
            int nSlot = mn%8;
            if (nSpace >= (int)m_space.size())
                return false;
            if (pass_to_slot(m_space[nSpace], nSlot)) {
                m_space.erase(m_space.begin() + nSpace);
                if (add_idstate(state_set))
                    return true;
            }
            return false;
        }

        bool pass_to_pile(const Card &c) {
            for (int iPile(0); iPile < 4; iPile++) {
                if ((m_piles[iPile].size() == 0) && (c.number == 0)) {
                    m_piles[iPile].push_back(c);
                    return true;
                }
                if ((m_piles[iPile].size() > 0) &&
                        (m_piles[iPile].back().type == c.type) &&
                        (m_piles[iPile].back().number == c.number - 1)) {
                    m_piles[iPile].push_back(c);
                    return true;
                }
            }
            return false;
        }

        bool pass_to_slot(const Card &c, int iSlot) {
            if (m_slots[iSlot].size() <= 0) {
                m_slots[iSlot].push_back(c);
                return true;
            }
            else {
                if (m_slots[iSlot].back().number == c.number + 1) {
                    if (((m_slots[iSlot].back().type == CARD_SPADE || m_slots[iSlot].back().type == CARD_CLUB) &&
                                (c.type == CARD_HEART || c.type == CARD_DIAMOND)) ||
                            ((m_slots[iSlot].back().type == CARD_HEART || m_slots[iSlot].back().type == CARD_DIAMOND) &&
                             (c.type == CARD_SPADE || c.type == CARD_CLUB))) {
                        m_slots[iSlot].push_back(c);
                        return true;
                    }
                }
            }
            return false;
        }

        bool pass_to_space(const Card &c) {
            if (m_space.size() >= 4)
                return false;
            vector<Card>::iterator itor;
            for (itor = m_space.begin(); itor != m_space.end(); itor++) {
                if (*itor > c)
                    break;
            }
            m_space.insert(itor, c);
            return true;
        }

        vector<Card>::size_type piles_size() const {
            return (m_piles[0].size() + m_piles[1].size() + m_piles[2].size() + m_piles[3].size());
        }

    public:
        vector< state_set_type::iterator > m_steps;

    private:
        vector<Card> m_space;
        vector<Card> m_piles[4];
        vector<Card> m_slots[8];
};
/*---------------------- END OF THE FILE : cards.h ----------------------*/

 

/*--------------------- BEGIN OF THE FILE : fc.cpp ----------------------*/
////////////////////////////////////////////////////////////////////
// Filename: fc.cpp
// Microsoft Games, FreeCell
// 20060317 by daineng@nj.cpsecure
////////////////////////////////////////////////////////////////////

#include "cards.h"

// a set of StateID
state_set_type state_set;
// a queue of CardState
typedef queue<CardState> state_queue_type;
typedef list< state_queue_type >::iterator state_queue_iterator;
list< state_queue_type > state_queue_list;
// a vector of final states

int main(int argc, char *argv[])
{
    ifstream fcard("cards.ini");
    string str_temp, str_card_state;
    string::size_type istrloc;
    while (getline(fcard, str_temp)) {
        if (string::npos != (istrloc = str_temp.rfind(';'))) {
            str_card_state = str_temp;
            if (argc > 1 && str_temp.substr(istrloc + 1) == argv[1]) {
                cout << "Get #" << argv[1] << endl;
                break;
            }
        }
    }
    if (str_card_state.length() < 160/*180*/) {
        cerr << "sError: The string of cards is not valid." << endl;
        return -1;
    }
    try {
        CardState state;
        StateID __sid;
        state_queue_type state_queue;
        if (1) { // set false if you want a test.
            state.str2state(str_card_state);
            //state.showout();
            state_queue.push(state);
            state_queue_list.push_front(state_queue);
            state.mkStateID(__sid);
        }
        else {
            __sid.Set4Test();
            state.sid2state(__sid);
            //state.showout();
            state_queue.push(state);
            state_queue_list.push_front(state_queue);
        }
        pair < state_set_type::iterator, bool > __pr;
        __pr = state_set.insert(__sid);
        state_set.insert(__sid);
        state_set.insert(__sid);
        if (!__pr.second) {
            cerr << "iError: first insertion set raise an error??" << endl;
            return -1;
        }
    }
    catch(const exception &ex) {
        cerr << "cErrro: " << ex.what() << endl;
        return -1;
    }

    CardState final_state;
    try {
        int levelPriority(0);
        while (state_queue_list.size() > 0) {
            cout << "State Queue List size is " << state_queue_list.size() << endl;
            state_queue_iterator _cur_state_queue(state_queue_list.begin());
            levelPriority = 0;
            while (_cur_state_queue->size() > 0) {
                CardState curState = _cur_state_queue->front();
                cout << "Pop out a state. which size is " << _cur_state_queue->size() << endl;
                _cur_state_queue->pop();
                if (curState.final_state()) {
                    //final_states.push_back(curState);
                    final_state = curState;
                    cout << "Get a final state." << endl;
                    throw state_except(state_except::FINAL_STATE);
                }
                else if (curState.limit_state()) {
                    continue;
                }
                else {
                    for (int iSCI(0); iSCI < 116; iSCI++) {
                        CardState cpState(curState);
                        //cpState.showout();
                        if (cpState.chg_state(state_set, iSCI)) {
                            //cpState.showsid();
                            //cpState.showout();
                            int level;
                            if ((level = cpState.priority_level(curState)) > 0) {
                                state_queue_type state_queue;
                                state_queue.push(cpState);
                                //cpState.showout();
                                if (level > levelPriority) {
                                    levelPriority = level;
                                    state_queue_list.push_front(state_queue);
                                }
                                else {
                                    state_queue_list.insert(++(state_queue_list.begin()), state_queue);
                                }
                            }
                            else {
                                _cur_state_queue->push(cpState);
                            }
                        }
                    }
                }
                if (levelPriority > 0) {
                    cout << "I get a Priority State Quere." << endl;
                    break;
                }
            }   // end of 'while (state_queue_...
            if (0 == levelPriority)
                state_queue_list.erase(_cur_state_queue);
        }
    }
    catch (const state_except &ex) {
        if (state_except::FINAL_STATE == ex.m_type) {
            cout << "... Total states is " << state_set.size() << endl;

            ofstream fout("result.log");
            fout << endl << "------------------------RESULT---------------------------" << endl << endl;
            //for (vector<CardState>::size_type i(0); i < final_states.size(); i++) {
            //fout << "Serial [ " << i << " ]" << endl;
            fout << "--------------------------------------------" << endl;
            CardState _state;
            //CardState lastState = final_states[i];
            CardState lastState = final_state;
            for (vector< state_set_type::iterator >::iterator itor(lastState.m_steps.begin());
                    itor != lastState.m_steps.end(); itor++) {
                _state.sid2state(**itor);
                _state.showout(fout);
                //(*itor)->showout();
            }
            //}
        }
        else {
            cerr << "fError: " << ex.what() << endl;
            return -1;
        }
    }
    catch (const exception &ex) {
        cerr << "fError: " << ex.what() << endl;
        return -1;
    }

    state_set.clear();
    return 0;
}
/*---------------------- END OF THE FILE : fc.cpp -----------------------*/

// At first, there is no 'state_queue_list', no 'limit_state', no 'priority_level',
// but the state_queue and state_set went biger and biger, and before I got a
// final_state I got an error of 'Out of Memory'. My process was killed by system.
// The program is not efficient, the number of all the states is huge.
// So i added the 'state_queue_list', 'limit_state' and 'priority_level' to fight
// with my limited memory and save time. ;-)


// Here is the content of cards.ini, 'S' is Spade, 'H' is Heart, 'C' is Club, 'D'
// is Diamond. I think it's very easy to you to familiar w/ the format.

/*-------------------- BEGIN OF THE FILE : cards.ini --------------------*/
C11,C12,S3,C4,H2,S13,S12,;C10,C5,S10,S7,C2,D8,S9,;C7,D6,C3,D4,H3,H12,C8,;S2,D2,S4,D7,S6,H4,D5,;C9,S8,S1,D13,H10,H13,;H11,D1,H7,C1,S5,H9,;C6,H6,D11,S11,D10,H1,;H5,H8,D12,D9,D3,C13,;17710
D6,C5,C3,S5,H7,H8,D11,;S2,C12,H10,D5,S8,S3,C13,;D13,C4,S12,C10,C8,C9,H6,;H4,S1,S10,S4,H13,H5,D12,;H1,D10,H2,S11,S13,D8,;D2,D4,D7,C1,S9,C7,;H12,H11,D3,D9,C11,S6,;D1,H3,C2,H9,S7,C6,;4740
H7,D2,H8,H11,H10,S9,C11,;C6,S12,S4,D6,H6,D1,H2,;D13,D10,C2,S8,H5,H1,D12,;S5,S2,H13,C7,D5,C5,S6,;H4,D7,C10,C13,C3,D8,;S1,S10,D3,H12,S7,D11,;D9,C9,C8,S3,C4,C12,;C1,S13,S11,D4,H3,H9,;13104
H1,C9,S3,C12,C10,D1,S12,;C13,C4,H9,S11,D3,H10,D10,;H13,D9,H3,H4,C6,S7,S8,;S4,D2,C5,D4,C1,S6,S5,;H5,H6,S10,H8,S1,D12,;D5,C7,H2,H12,S2,D6,;S13,C3,C8,C2,C11,H7,;D11,H11,D8,S9,D13,D7,;19482
H6,C3,D13,D6,S4,H5,D5,;C11,C7,C6,S9,S5,C9,H11,;D4,D11,C8,S12,S11,S1,H9,;D7,S7,H13,D12,D2,S3,S13,;H7,H4,H8,D8,H12,D10,;S8,S6,H10,C4,C1,C12,;C2,C10,H2,D9,C13,D3,;H3,S2,D1,C5,H1,S10,;18867
H6,H8,D6,S1,C2,S11,H10,;C7,C4,S7,C5,H2,C9,S2,;D4,C6,C1,S5,H1,C8,D11,;H7,C11,D9,S9,H11,C10,S12,;S13,H13,D13,H5,H3,H9,;S8,D10,D12,C12,D2,H4,;D3,H12,C13,S3,S4,D7,;D8,S6,S10,D5,C3,D1,;17641
/*--------------------- END OF THE FILE : cards.ini ---------------------*/

// complie it, run it, check it, enjoy it. :-)