File indexing completed on 2024-05-26 04:08:30

0001 /*
0002  * Copyright (C) 2006-2009 Stephan Kulow <coolo@kde.org>
0003  *
0004  * This program is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU General Public License as
0006  * published by the Free Software Foundation; either version 2 of
0007  * the License, or (at your option) any later version.
0008  *
0009  * This program is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  * GNU General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU General Public License
0015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "grandfsolver.h"
0019 
0020 // own
0021 #include "../grandf.h"
0022 #include "../kpat_debug.h"
0023 
0024 #define PRINT 0
0025 
0026 /* These two routines make and unmake moves. */
0027 
0028 void GrandfSolver::make_move(MOVE *m)
0029 {
0030 #if PRINT
0031     if (m->totype == O_Type)
0032         fprintf(stderr, "\nmake move %d from %d out (at %d)\n\n", m->card_index, m->from, m->turn_index);
0033     else if (m->from == offs)
0034         fprintf(stderr, "\nmake redeal\n\n");
0035     else
0036         fprintf(stderr, "\nmake move %d from %d to %d (%d)\n\n", m->card_index, m->from, m->to, m->turn_index);
0037     print_layout();
0038 #else
0039     // print_layout();
0040 #endif
0041 
0042     card_t card = NONE;
0043 
0044     auto from = m->from;
0045     auto to = m->to;
0046 
0047     if (from == offs) {
0048         // redeal
0049         m_redeal++;
0050 
0051         card_t deck[52];
0052         int len = 0;
0053 
0054         for (int i = m_redeal * 7; i < m_redeal * 7 + 7; ++i) {
0055             Wlen[i] = 0;
0056             Wp[i] = &W[i][-1];
0057         }
0058 
0059         for (int pos = 6; pos >= 0; --pos) {
0060             int oldpile = (m_redeal - 1) * 7 + pos;
0061             for (int l = 0; l < Wlen[oldpile]; ++l) {
0062                 card_t card = W[oldpile][l];
0063                 deck[len++] = (SUIT(card) << 4) + RANK(card);
0064             }
0065         }
0066 
0067         int start = 0;
0068         int stop = 7 - 1;
0069         int dir = 1;
0070 
0071         for (int round = 0; round < 7; ++round) {
0072             int i = start;
0073             do {
0074                 card_t card = NONE;
0075                 if (len > 0) {
0076                     card = deck[--len];
0077                     int currentpile = m_redeal * 7 + i;
0078                     Wp[currentpile]++;
0079                     *Wp[currentpile] = card;
0080                     if (i != start)
0081                         *Wp[currentpile] += (1 << 7);
0082                     Wlen[currentpile]++;
0083                 }
0084                 i += dir;
0085             } while (i != stop + dir);
0086             int t = start;
0087             start = stop;
0088             stop = t + dir;
0089             dir = -dir;
0090         }
0091 
0092         int j = 0;
0093         while (len > 0) {
0094             card_t card = deck[--len];
0095             int currentpile = m_redeal * 7 + (j + 1);
0096             Wp[currentpile]++;
0097             *Wp[currentpile] = card;
0098             Wlen[currentpile]++;
0099             j = (j + 1) % 6;
0100         }
0101 
0102         for (int round = 0; round < 7; ++round) {
0103             int currentpile = m_redeal * 7 + round;
0104             if (Wlen[currentpile]) {
0105                 card_t card = W[currentpile][Wlen[currentpile] - 1];
0106                 W[currentpile][Wlen[currentpile] - 1] = (SUIT(card) << 4) + RANK(card);
0107             }
0108             hashpile(currentpile);
0109             hashpile(currentpile - 7);
0110         }
0111 
0112 #if PRINT
0113         print_layout();
0114 #endif
0115         return;
0116     }
0117 
0118     for (int l = m->card_index; l >= 0; --l) {
0119         card = W[from][Wlen[from] - l - 1];
0120         Wp[from]--;
0121         if (m->totype != O_Type) {
0122             Wp[to]++;
0123             *Wp[to] = card;
0124             Wlen[to]++;
0125         }
0126     }
0127     Wlen[from] -= m->card_index + 1;
0128 
0129     if (m->turn_index == 0) {
0130         if (DOWN(card))
0131             card = (SUIT(card) << 4) + RANK(card);
0132         else
0133             card += (1 << 7);
0134         W[to][Wlen[to] - m->card_index - 1] = card;
0135     } else if (m->turn_index != -1) {
0136         card_t card2 = *Wp[from];
0137         if (DOWN(card2))
0138             card2 = (SUIT(card2) << 4) + RANK(card2);
0139         *Wp[from] = card2;
0140     }
0141 
0142     hashpile(from);
0143     /* Add to pile. */
0144 
0145     if (m->totype == O_Type) {
0146         if (DOWN(W[offs][to]))
0147             W[offs][to] = (SUIT(card) << 4) + PS_ACE;
0148         else
0149             W[offs][to]++;
0150         Q_ASSERT(m->card_index == 0);
0151         hashpile(offs);
0152     } else {
0153         hashpile(to);
0154     }
0155 #if PRINT
0156     print_layout();
0157 #endif
0158 }
0159 
0160 void GrandfSolver::undo_move(MOVE *m)
0161 {
0162 #if PRINT
0163     if (m->totype == O_Type)
0164         fprintf(stderr, "\nundo move %d from %d out (at %d)\n\n", m->card_index, m->from, m->turn_index);
0165     else if (m->from == offs)
0166         fprintf(stderr, "\nundo redeal\n\n");
0167     else
0168         fprintf(stderr, "\nundo move %d from %d to %d (%d)\n\n", m->card_index, m->from, m->to, m->turn_index);
0169     print_layout();
0170 
0171 #endif
0172     int from, to;
0173     card_t card;
0174 
0175     from = m->from;
0176     to = m->to;
0177 
0178     if (from == offs) {
0179         /* just erase */
0180 
0181         for (int i = 0; i < 7; ++i) {
0182             int pile = m_redeal * 7 + i;
0183             Wlen[pile] = 0;
0184             Wp[pile] = &W[pile][0];
0185             hashpile(pile);
0186         }
0187         m_redeal--;
0188 #if PRINT
0189         print_layout();
0190 #endif
0191         return;
0192     }
0193 
0194     /* Add to 'from' pile. */
0195     if (m->turn_index > 0) {
0196         card_t card2 = *Wp[from];
0197         if (!DOWN(card2))
0198             card2 = (SUIT(card2) << 4) + RANK(card2) + (1 << 7);
0199         *Wp[from] = card2;
0200     }
0201 
0202     if (m->totype == O_Type) {
0203         card = W[offs][Osuit[to]];
0204         W[offs][to]--;
0205         Wp[from]++;
0206         *Wp[from] = card;
0207         Wlen[from]++;
0208     } else {
0209         for (int l = m->card_index; l >= 0; --l) {
0210             card = W[to][Wlen[to] - l - 1];
0211             Wp[from]++;
0212             *Wp[from] = card;
0213             Wlen[from]++;
0214             Wp[to]--;
0215         }
0216         Wlen[to] -= m->card_index + 1;
0217         hashpile(to);
0218     }
0219 
0220     if (m->turn_index == 0) {
0221         card_t card = *Wp[from];
0222         if (DOWN(card))
0223             card = (SUIT(card) << 4) + RANK(card);
0224         else
0225             card += (1 << 7);
0226         *Wp[from] = card;
0227     }
0228 
0229     hashpile(from);
0230 #if PRINT
0231     print_layout();
0232 #endif
0233 }
0234 
0235 /* Get the possible moves from a position, and store them in Possible[]. */
0236 
0237 int GrandfSolver::get_possible_moves(int *a, int *numout)
0238 {
0239     int w, o, empty;
0240     card_t card;
0241     MOVE *mp;
0242 
0243     /* Check for moves from W to O. */
0244 
0245     int n = 0;
0246     mp = Possible;
0247 
0248     for (w = m_redeal * 7 + 0; w < m_redeal * 7 + 7; ++w) {
0249         if (Wlen[w] > 0) {
0250             card = *Wp[w];
0251             o = SUIT(card);
0252             empty = DOWN(W[offs][o]);
0253             if ((empty && (RANK(card) == PS_ACE)) || (!empty && (RANK(card) == RANK(W[offs][o]) + 1))) {
0254                 mp->card_index = 0;
0255                 mp->from = w;
0256                 mp->to = o;
0257                 mp->totype = O_Type;
0258                 mp->pri = 127; /* unused */
0259                 mp->turn_index = -1;
0260                 if (Wlen[w] > 1 && DOWN(W[w][Wlen[w] - 2]))
0261                     mp->turn_index = 1;
0262                 n++;
0263                 mp++;
0264 
0265                 *a = true;
0266                 return n;
0267             }
0268         }
0269     }
0270 
0271     /* No more automoves, but remember if there were any moves out. */
0272 
0273     *a = false;
0274     *numout = n;
0275 
0276     for (int i = m_redeal * 7 + 0; i < m_redeal * 7 + 7; ++i) {
0277         int len = Wlen[i];
0278         for (int l = 0; l < len; ++l) {
0279             card_t card = W[i][Wlen[i] - 1 - l];
0280             if (DOWN(card))
0281                 break;
0282 
0283             for (int j = m_redeal * 7 + 0; j < m_redeal * 7 + 7; ++j) {
0284                 if (i == j)
0285                     continue;
0286 
0287                 int allowed = 0;
0288 
0289                 if (Wlen[j] > 0 && RANK(card) == RANK(*Wp[j]) - 1 && SUIT(card) == SUIT(*Wp[j])) {
0290                     allowed = 1;
0291                 }
0292                 if (RANK(card) == PS_KING && Wlen[j] == 0) {
0293                     if (l != Wlen[i] - 1)
0294                         allowed = 4;
0295                     else if (m_redeal < 2)
0296                         allowed = 1;
0297                 }
0298                 // TODO: there is no point in moving if we're not opening anything
0299                 // e.g. if both i and j have perfect runs below the cards
0300 #if 0
0301                 fprintf( stderr, "%d %d %d\n", i, l, j );
0302                 printcard( card, stderr );
0303                 printcard( *Wp[j], stderr );
0304                 fprintf( stderr, " allowed %d\n",allowed );
0305 #endif
0306                 if (allowed) {
0307                     mp->card_index = l;
0308                     mp->from = i;
0309                     mp->to = j;
0310                     mp->totype = W_Type;
0311                     mp->turn_index = -1;
0312                     if (Wlen[i] > l + 1 && DOWN(W[i][Wlen[i] - l - 2]))
0313                         mp->turn_index = 1;
0314                     if (mp->turn_index > 0 || Wlen[i] == l + 1)
0315                         mp->pri = 30;
0316                     else
0317                         mp->pri = 1;
0318                     /*if (mp->pri == 30 && mp->from == 9 && mp->to == 10)
0319                       abort();*/
0320                     n++;
0321                     mp++;
0322                 }
0323             }
0324         }
0325     }
0326 
0327     if (m_redeal < 2) {
0328         mp->card_index = 0;
0329         mp->from = offs;
0330         mp->to = 0; // unused
0331         mp->totype = W_Type;
0332         mp->turn_index = -1;
0333         mp->pri = -1;
0334         n++;
0335         mp++;
0336     }
0337 
0338     return n;
0339 }
0340 
0341 unsigned int GrandfSolver::getClusterNumber()
0342 {
0343     return m_redeal;
0344 }
0345 
0346 void GrandfSolver::unpack_cluster(unsigned int k)
0347 {
0348     m_redeal = k;
0349 }
0350 
0351 bool GrandfSolver::isWon()
0352 {
0353     // maybe won?
0354     for (int o = 0; o < 4; ++o) {
0355         if (RANK(W[offs][o]) != PS_KING) {
0356             return false;
0357         }
0358     }
0359 
0360     return true;
0361 }
0362 
0363 int GrandfSolver::getOuts()
0364 {
0365     int outs = 0;
0366     for (int i = 0; i < 4; ++i)
0367         if (!DOWN(W[offs][i]))
0368             outs += RANK(W[offs][i]);
0369     return outs;
0370 }
0371 
0372 GrandfSolver::GrandfSolver(const Grandf *dealer)
0373     : Solver()
0374 {
0375     Osuit[0] = PS_DIAMOND;
0376     Osuit[1] = PS_CLUB;
0377     Osuit[2] = PS_HEART;
0378     Osuit[3] = PS_SPADE;
0379 
0380     offs = 7 * 3;
0381     deal = dealer;
0382     m_redeal = -1;
0383 }
0384 
0385 void GrandfSolver::translate_layout()
0386 {
0387     /* Read the workspace. */
0388 
0389     m_redeal = deal->numberOfDeals - 1;
0390 
0391     for (int w = 0; w < 7 * 3; ++w)
0392         Wlen[w] = 0;
0393 
0394     for (int w = 0; w < 7; ++w) {
0395         int i = translate_pile(deal->store[w], W[w + m_redeal * 7], 52);
0396         Wp[w + m_redeal * 7] = &W[w + m_redeal * 7][i - 1];
0397         Wlen[w + m_redeal * 7] = i;
0398     }
0399 
0400     Wlen[offs] = 4;
0401 
0402     for (int i = 0; i < 4; ++i)
0403         W[offs][i] = NONE;
0404 
0405     for (int i = 0; i < 4; ++i) {
0406         KCard *c = deal->target[i]->topCard();
0407         if (c)
0408             W[offs][translateSuit(c->suit()) >> 4] = translateSuit(c->suit()) + c->rank();
0409     }
0410     for (int i = 0; i < 4; ++i)
0411         if (W[offs][i] == NONE)
0412             W[offs][i] = (i << 4) + PS_ACE + (1 << 7);
0413 
0414     Wp[offs] = &W[offs][3];
0415 }
0416 
0417 MoveHint GrandfSolver::translateMove(const MOVE &m)
0418 {
0419     if (m.from == offs)
0420         return MoveHint();
0421 
0422     PatPile *frompile = nullptr;
0423     frompile = deal->store[m.from % 7];
0424 
0425     KCard *card = frompile->at(frompile->count() - m.card_index - 1);
0426 
0427     if (m.totype == O_Type) {
0428         PatPile *target = nullptr;
0429         PatPile *empty = nullptr;
0430         for (int i = 0; i < 4; ++i) {
0431             KCard *c = deal->target[i]->topCard();
0432             if (c) {
0433                 if (c->suit() == card->suit()) {
0434                     target = deal->target[i];
0435                     break;
0436                 }
0437             } else if (!empty)
0438                 empty = deal->target[i];
0439         }
0440         if (!target)
0441             target = empty;
0442         return MoveHint(card, target, m.pri);
0443     } else {
0444         return MoveHint(card, deal->store[m.to % 7], m.pri);
0445     }
0446 }
0447 
0448 void GrandfSolver::print_layout()
0449 {
0450     int i, w, o;
0451 
0452     fprintf(stderr, "print-layout-begin\n");
0453     for (w = 0; w < 21; ++w) {
0454         fprintf(stderr, "Play%d-%d(%d): ", w / 7, w % 7, w);
0455         for (i = 0; i < Wlen[w]; ++i) {
0456             printcard(W[w][i], stderr);
0457         }
0458         fputc('\n', stderr);
0459     }
0460     fprintf(stderr, "Off: ");
0461     for (o = 0; o < 4; ++o) {
0462         if (!DOWN(W[offs][o]))
0463             printcard(RANK(W[offs][o]) + Osuit[o], stderr);
0464     }
0465     fprintf(stderr, "\nRedeals: %d", m_redeal);
0466     fprintf(stderr, "\nprint-layout-end\n");
0467 }