File indexing completed on 2024-06-09 04:03:37

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 "mod3solver.h"
0019 
0020 // own
0021 #include "../kpat_debug.h"
0022 #include "../mod3.h"
0023 
0024 #define PRINT 0
0025 #define PRINT2 0
0026 
0027 /* These two routines make and unmake moves. */
0028 
0029 void Mod3Solver::make_move(MOVE *m)
0030 {
0031 #if PRINT
0032     if (m->totype == O_Type)
0033         fprintf(stderr, "\nmake move %d from %d out %d (at %d)\n\n", m->card_index, m->from, m->to, m->turn_index);
0034     else
0035         fprintf(stderr, "\nmake move %d from %d to %d (%d)\n\n", m->card_index, m->from, m->to, m->turn_index);
0036     print_layout();
0037 #endif
0038 
0039     int from, to;
0040     from = m->from;
0041     to = m->to;
0042 
0043     if (from == deck) {
0044         int len = m->card_index;
0045         if (len > 8)
0046             len = 8;
0047         for (int i = 0; i < len; i++) {
0048             card_t card = *Wp[deck];
0049             Wlen[deck]--;
0050             Wp[deck]--;
0051 
0052             card = (card & PS_SUIT) + RANK(card);
0053             Wp[24 + i]++;
0054             Wlen[24 + i]++;
0055             *Wp[24 + i] = card;
0056             hashpile(24 + i);
0057         }
0058         hashpile(deck);
0059 #if PRINT
0060         print_layout();
0061 #endif
0062         return;
0063     }
0064 
0065     card_t card = *Wp[from];
0066     Wlen[from]--;
0067     Wp[from]--;
0068     hashpile(from);
0069 
0070     /* Add to pile. */
0071 
0072     Wp[to]++;
0073     *Wp[to] = card;
0074     Wlen[to]++;
0075     hashpile(to);
0076 
0077     if (m->turn_index == 1) {
0078         card_t card2 = *Wp[deck];
0079         Wlen[deck]--;
0080         Wp[deck]--;
0081 
0082         hashpile(deck);
0083         /* Add to pile. */
0084 
0085         Wp[from]++;
0086         *Wp[from] = RANK(card2) + (SUIT(card2) << 4);
0087         Wlen[from]++;
0088     }
0089 
0090     hashpile(from);
0091 #if PRINT
0092     print_layout();
0093 #endif
0094 }
0095 
0096 void Mod3Solver::undo_move(MOVE *m)
0097 {
0098 #if PRINT2
0099     if (m->totype == O_Type)
0100         fprintf(stderr, "\nundo move %d from %d out (at %d)\n\n", m->card_index, m->from, m->turn_index);
0101     else
0102         fprintf(stderr, "\nundo move %d from %d to %d (%d)\n\n", m->card_index, m->from, m->to, m->turn_index);
0103     print_layout();
0104 #endif
0105 
0106     int from, to;
0107     card_t card;
0108 
0109     from = m->from;
0110     to = m->to;
0111 
0112     if (from == deck) {
0113         int len = m->card_index;
0114         if (len > 8)
0115             len = 8;
0116         for (int i = len; i >= 0; i--) {
0117             if (Wlen[i] == 0) {
0118                 // there exists no card to move
0119                 /* TODO: determine if we need to call hashpile here
0120                 / or do any other work */
0121                 continue;
0122             }
0123             card_t card = *Wp[24 + i];
0124             Wlen[deck]++;
0125             Wp[deck]++;
0126             *Wp[deck] = (1 << 7) + card;
0127 
0128             Wp[24 + i]--;
0129             Wlen[24 + i]--;
0130             hashpile(24 + i);
0131         }
0132         hashpile(deck);
0133 #if PRINT2
0134         print_layout();
0135 #endif
0136         return;
0137     }
0138 
0139     if (m->turn_index == 1) {
0140         card_t card = *Wp[from];
0141         Wp[deck]++;
0142         Wlen[deck]++;
0143         *Wp[deck] = (1 << 7) + card;
0144         Wlen[from]--;
0145         Wp[from]--;
0146 
0147         hashpile(deck);
0148     }
0149 
0150     card = *Wp[to];
0151     Wp[from]++;
0152     *Wp[from] = card;
0153     Wlen[from]++;
0154     Wp[to]--;
0155     Wlen[to]--;
0156     hashpile(to);
0157     hashpile(from);
0158 
0159 #if PRINT2
0160     print_layout();
0161 #endif
0162 }
0163 
0164 /* Get the possible moves from a position, and store them in Possible[]. */
0165 
0166 int Mod3Solver::get_possible_moves(int *a, int *numout)
0167 {
0168     // print_layout();
0169 
0170     card_t card;
0171     MOVE *mp;
0172 
0173     *a = false;
0174     *numout = 0;
0175 
0176     int n = 0;
0177     mp = Possible;
0178 
0179     int first_empty_pile = -1;
0180 
0181     int firstfree[4] = {-1, -1, -1, -1};
0182 
0183     for (int i = 0; i < 32; ++i) {
0184         if (!Wlen[i])
0185             continue;
0186         card = *Wp[i];
0187 
0188         if (RANK(card) == PS_ACE) {
0189             mp->card_index = 0;
0190             mp->from = i;
0191             mp->to = aces;
0192             mp->totype = O_Type;
0193             mp->pri = 127; /* unused */
0194             mp->turn_index = -1;
0195             if (i >= 24 && Wlen[i] == 1 && Wlen[deck])
0196                 mp->turn_index = 1;
0197             n++;
0198             mp++;
0199             Possible[0] = mp[-1];
0200             *numout = 1;
0201             return 1;
0202         }
0203 
0204         for (int j = 0; j < 32; ++j) {
0205             if (i == j)
0206                 continue;
0207 
0208             int current_row = i / 8;
0209             int row = j / 8;
0210 
0211             if (!Wlen[j]) {
0212                 if (firstfree[row] < 0)
0213                     firstfree[row] = j;
0214 
0215                 // fprintf(stderr, "firstfree %d %d %d\n", row, firstfree[row], j);
0216                 if (j != firstfree[row] && row < 4)
0217                     continue;
0218             }
0219 
0220             if (Wlen[j] && RANK(*Wp[j]) != row + 2 + (Wlen[j] - 1) * 3) {
0221                 // fprintf( stderr, "rank %d %d\n", i, j );
0222                 continue;
0223             }
0224 
0225             if (row < 3) {
0226                 int min = (card & PS_SUIT) + row + 2;
0227                 if (Wlen[j]) {
0228                     if (RANK(*Wp[j]) > 10)
0229                         continue;
0230                     min = (*Wp[j] & PS_SUIT) + row + 2 + Wlen[j] * 3;
0231                 }
0232                 if (min != card)
0233                     continue;
0234 
0235                 // and now we figure if this makes sense at all
0236                 if (current_row == row) {
0237                     // if the only difference between i and j is the card,
0238                     // then it's not worth it
0239                     if (Wlen[i] == Wlen[j] + 1)
0240                         continue;
0241                 }
0242 
0243                 if (Wlen[j]) {
0244                     mp->pri = qMin(119, 12 + 20 * Wlen[j] + current_row * 2 + RANK(*Wp[j]) * 5);
0245                 } else {
0246                     mp->pri = 119; // TODO: Find out if this is really correct. We can certainly not touch Wp[j], but is this the correct mp->pri value?
0247                 }
0248 
0249                 mp->turn_index = -1;
0250                 if (i >= 24 && Wlen[i] == 1 && Wlen[deck])
0251                     mp->turn_index = 1;
0252 
0253             } else {
0254                 if (Wlen[j] || (Wlen[i] > 1 && current_row != 3))
0255                     continue;
0256 
0257                 if (current_row == 3 && Wlen[i] == 1)
0258                     continue;
0259 
0260                 if (RANK(card) == current_row + 2 && current_row != 3)
0261                     continue;
0262 
0263                 if (first_empty_pile != -1 && first_empty_pile != j)
0264                     continue;
0265 
0266                 if (first_empty_pile == -1)
0267                     first_empty_pile = j;
0268 
0269                 mp->pri = 0;
0270                 mp->turn_index = -1;
0271             }
0272 
0273             mp->card_index = 0;
0274             mp->from = i;
0275             mp->to = j;
0276             mp->totype = W_Type;
0277             n++;
0278             mp++;
0279         }
0280     }
0281 
0282     if (Wlen[deck]) {
0283         // move
0284         mp->card_index = 0;
0285         mp->from = deck;
0286         mp->to = 0;
0287         mp->totype = W_Type;
0288         mp->pri = -77; // last resort
0289         mp->turn_index = -1;
0290         mp->card_index = Wlen[deck];
0291         n++;
0292         mp++;
0293     }
0294 
0295     return n;
0296 }
0297 
0298 bool Mod3Solver::isWon()
0299 {
0300     return getOuts() == 52 * 2;
0301 }
0302 
0303 int Mod3Solver::getOuts()
0304 {
0305     int ret = Wlen[aces];
0306     for (int i = 0; i < 8 * 3; i++)
0307         ret += Wlen[i];
0308     return ret;
0309 }
0310 
0311 Mod3Solver::Mod3Solver(const Mod3 *dealer)
0312     : Solver()
0313 {
0314     deal = dealer;
0315 }
0316 
0317 void Mod3Solver::translate_layout()
0318 {
0319     /* Read the workspace. */
0320     int w = 0;
0321     for (int row = 0; row < 4; ++row) {
0322         for (int col = 0; col < 8; ++col) {
0323             int i = translate_pile(deal->stack[row][col], W[w], 52);
0324             Wp[w] = &W[w][i - 1];
0325             Wlen[w] = i;
0326             w++;
0327         }
0328     }
0329 
0330     aces = w;
0331     int i = translate_pile(deal->aces, W[w], 52);
0332     Wp[w] = &W[w][i - 1];
0333     Wlen[w] = i;
0334 
0335     deck = ++w;
0336 
0337     i = translate_pile(deal->talon, W[w], 104);
0338     Wp[w] = &W[w][i - 1];
0339     Wlen[w] = i;
0340 }
0341 
0342 MoveHint Mod3Solver::translateMove(const MOVE &m)
0343 {
0344     if (m.from == deck)
0345         return MoveHint();
0346 
0347     PatPile *frompile = deal->stack[m.from / 8][m.from % 8];
0348     KCard *card = frompile->topCard();
0349 
0350     if (m.to == aces) {
0351         return MoveHint(card, deal->aces, m.pri);
0352     } else {
0353         return MoveHint(card, deal->stack[m.to / 8][m.to % 8], m.pri);
0354     }
0355 }
0356 
0357 void Mod3Solver::print_layout()
0358 {
0359     int i, w = 0, o;
0360 
0361     fprintf(stderr, "print-layout-begin\n");
0362     for (int row = 0; row < 3; ++row) {
0363         fprintf(stderr, "Row%d: ", row);
0364         for (int col = 0; col < 8; col++) {
0365             if (Wlen[w])
0366                 printcard(*Wp[w], stderr);
0367             else
0368                 fprintf(stderr, "   ");
0369             fprintf(stderr, "(%02d) ", w);
0370             w++;
0371         }
0372         fputc('\n', stderr);
0373     }
0374 
0375     for (int col = 0; col < 8; col++) {
0376         fprintf(stderr, "Play%02d: ", w);
0377         for (i = 0; i < Wlen[w]; ++i) {
0378             printcard(W[w][i], stderr);
0379         }
0380         fputc('\n', stderr);
0381         w++;
0382     }
0383 
0384     fprintf(stderr, "Aces: ");
0385     for (o = 0; o < Wlen[aces]; ++o) {
0386         printcard(W[aces][o], stderr);
0387     }
0388     fputc('\n', stderr);
0389 
0390     fprintf(stderr, "Deck: ");
0391     for (o = 0; o < Wlen[deck]; ++o) {
0392         printcard(W[deck][o], stderr);
0393     }
0394 
0395     fprintf(stderr, "\nprint-layout-end\n");
0396 }