///////////////////////////////////////////////////////////////////////////
// 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. :-)