int KlondikeSolver::get_possible_moves(int *a, int *numout) { int w, o, empty; card_t card; MOVE *mp; /* Check for moves from W to O. */ int n = 0; mp = Possible; for (w = 0; w < 8; ++w) { if (Wlen[w] > 0) { card = *Wp[w]; o = SUIT(card); empty = (O[o] == NONE); if ((empty && (RANK(card) == PS_ACE)) || (!empty && (RANK(card) == O[o] + 1))) { mp->card_index = 0; mp->from = w; mp->to = o; mp->totype = O_Type; mp->pri = 3; /* unused */ mp->turn_index = -1; if ( Wlen[w] > 1 && DOWN( W[w][Wlen[w]-2] ) ) mp->turn_index = 1; n++; mp++; /* If it's an automove, just do it. Automoves from the pile are problematic though in draw=3 because automoves can break the offset and break winnable games */ if (good_automove(o, RANK(card)) && (w != 7 || m_draw == 1 || Wlen[7] < 3)) { *a = true; mp[-1].pri = 127; if (n != 1) { Possible[0] = mp[-1]; return 1; } return n; } } } } /* No more automoves, but remember if there were any moves out. */ *a = false; *numout = n; /* check for deck->pile */ if ( Wlen[8] ) { mp->card_index = qMin( m_draw, Wlen[8] ); mp->from = 8; mp->to = 7; mp->totype = W_Type; mp->pri = 5; mp->turn_index = 0; n++; mp++; } // we first check where to put a king, so we don't // try each king on each empty pile int first_empty_pile = -1; for(int i=0; i<8; ++i) if ( !Wlen[i] ) { first_empty_pile = i; break; } for(int i=0; i<8; ++i) { int len = Wlen[i]; if ( i == 7 && Wlen[i] > 0) len = 1; for (int l=0; l < len; ++l ) { card_t card = W[i][Wlen[i]-1-l]; if ( DOWN( card ) ) break; for (int j = 0; j < 7; ++j) { if (i == j) continue; int allowed = 0; if ( Wlen[j] > 0 && RANK(card) == RANK(*Wp[j]) - 1 && suitable( card, *Wp[j] ) ) { allowed = 1; if ( Wlen[i] == l + 1 ) { allowed = 2; } else { if ( DOWN( W[i][Wlen[i]-l-2] ) ) allowed = 3; } } if ( RANK( card ) == PS_KING && j == first_empty_pile ) { if ( l != Wlen[i]-1 || i == 7 ) allowed = 4; } if ( allowed && i == 7 ) allowed = 5; if ( allowed == 1 ) { //print_layout(); card_t below = W[i][Wlen[i]-2-l]; int o = SUIT(below); bool empty = (O[o] == NONE); //fprintf( stderr, "%d %d\n", i, l ); //printcard( below, stderr ); if ( ( empty && RANK( below ) != PS_ACE ) || ( !empty && RANK( below ) != O[o] + 1 ) ) allowed = 0; //fprintf( stderr, " allowed %d %d %d %d\n",allowed, empty, RANK( below ), PS_ACE); } if ( allowed ) { mp->card_index = l; mp->from = i; mp->to = j; mp->totype = W_Type; mp->turn_index = -1; if ( Wlen[i] > l+1 && DOWN( W[i][Wlen[i]-l-2] ) ) mp->turn_index = 1; if ( i == 7 ) mp->pri = 40; else { if ( mp->turn_index > 0 || Wlen[i] == l+1) mp->pri = 30; else mp->pri = 1; } n++; mp++; } } } } if ( Wlen[8] == 0 && Wlen[7] > 1 ) { mp->card_index = 0; mp->from = 7; mp->to = 8; mp->totype = W_Type; mp->turn_index = 0; mp->pri = 2; n++; mp++; } return n; }
int FreecellSolver::get_possible_moves(int *a, int *numout) { int i, n, t, w, o, empty, emptyw; card_t card; MOVE *mp; /* Check for moves from W to O. */ n = 0; mp = Possible; for (w = 0; w < Nwpiles + Ntpiles; ++w) { if (Wlen[w] > 0) { card = *Wp[w]; o = SUIT(card); empty = (O[o] == NONE); if ((empty && (RANK(card) == PS_ACE)) || (!empty && (RANK(card) == O[o] + 1))) { mp->card_index = 0; mp->from = w; mp->to = o; mp->totype = O_Type; mp->turn_index = -1; mp->pri = 0; /* unused */ n++; mp++; /* If it's an automove, just do it. */ if (good_automove(o, RANK(card))) { *a = true; mp[-1].pri = 127; if (n != 1) { Possible[0] = mp[-1]; return 1; } return n; } } } } /* No more automoves, but remember if there were any moves out. */ *a = false; *numout = n; /* Check for moves from non-singleton W cells to one of any empty W cells. */ emptyw = -1; for (w = 0; w < Nwpiles; ++w) { if (Wlen[w] == 0) { emptyw = w; break; } } if (emptyw >= 0) { for (i = 0; i < Nwpiles + Ntpiles; ++i) { if (i == emptyw || Wlen[i] == 0) { continue; } bool allowed = false; if ( i < Nwpiles) allowed = true; if ( i >= Nwpiles ) allowed = true; if ( allowed ) { card = *Wp[i]; mp->card_index = 0; mp->from = i; mp->to = emptyw; mp->totype = W_Type; mp->turn_index = -1; if ( i >= Nwpiles ) mp->pri = Xparam[6]; else mp->pri = Xparam[3]; n++; mp++; } } } /* Check for moves from W to non-empty W cells. */ for (i = 0; i < Nwpiles + Ntpiles; ++i) { if (Wlen[i] > 0) { card = *Wp[i]; for (w = 0; w < Nwpiles; ++w) { if (i == w) { continue; } if (Wlen[w] > 0 && (RANK(card) == RANK(*Wp[w]) - 1 && suitable(card, *Wp[w]))) { mp->card_index = 0; mp->from = i; mp->to = w; mp->totype = W_Type; mp->turn_index = -1; if ( i >= Nwpiles ) mp->pri = Xparam[5]; else mp->pri = Xparam[4]; n++; mp++; } } } } /* Check for moves from W to one of any empty T cells. */ for (t = 0; t < Ntpiles; ++t) { if (!Wlen[t+Nwpiles]) { break; } } if (t < Ntpiles) { for (w = 0; w < Nwpiles; ++w) { if (Wlen[w] > 0) { card = *Wp[w]; mp->card_index = 0; mp->from = w; mp->turn_index = -1; mp->to = t+Nwpiles; mp->totype = W_Type; mp->pri = Xparam[7]; n++; mp++; } } } return n; }
int YukonSolver::get_possible_moves(int *a, int *numout) { int w, o, empty; card_t card; MOVE *mp; /* Check for moves from W to O. */ int n = 0; mp = Possible; for (w = 0; w < 7; w++) { if (Wlen[w] > 0) { card = *Wp[w]; o = SUIT(card); empty = (O[o] == NONE); if ((empty && (RANK(card) == PS_ACE)) || (!empty && (RANK(card) == O[o] + 1))) { mp->card_index = 0; mp->from = w; mp->to = o; mp->totype = O_Type; mp->pri = 3; /* unused */ mp->turn_index = -1; if ( Wlen[w] > 1 && DOWN( W[w][Wlen[w]-2] ) ) mp->turn_index = 1; n++; mp++; /* If it's an automove, just do it. */ if (good_automove(o, RANK(card))) { *a = true; mp[-1].pri = 127; if (n != 1) { Possible[0] = mp[-1]; return 1; } return n; } } } } /* No more automoves, but remember if there were any moves out. */ *a = false; *numout = n; for(int i=0; i<7; i++) { int len = Wlen[i]; for (int l=0; l < len; ++l ) { card_t card = W[i][Wlen[i]-1-l]; if ( DOWN( card ) ) break; for (int j = 0; j < 7; j++) { if (i == j) continue; int allowed = 0; if ( Wlen[j] > 0 && RANK(card) == RANK(*Wp[j]) - 1 && suitable( card, *Wp[j] ) ) { allowed = 1; if ( Wlen[i] == l + 1 ) { allowed = 2; } else { if ( DOWN( W[i][Wlen[i]-l-2] ) ) allowed = 3; } } if ( RANK( card ) == PS_KING && Wlen[j] == 0 ) { if ( l != Wlen[i]-1 || i == 7 ) allowed = 4; } // TODO: there is no point in moving if we're not opening anything // e.g. if both i and j have perfect runs below the cards #if 0 fprintf( stderr, "%d %d %d\n", i, l, j ); printcard( card, stderr ); printcard( *Wp[j], stderr ); fprintf( stderr, " allowed %d\n",allowed ); #endif if ( allowed ) { mp->card_index = l; mp->from = i; mp->to = j; mp->totype = W_Type; mp->turn_index = -1; if ( Wlen[i] > l+1 && DOWN( W[i][Wlen[i]-l-2] ) ) mp->turn_index = 1; if ( mp->turn_index > 0 || Wlen[i] == l+1) mp->pri = 30; else mp->pri = 1; n++; mp++; } } } } return n; }
int GypsySolver::get_possible_moves(int *a, int *numout) { MOVE *mp; /* Check for moves from W to O. */ int n = 0; mp = Possible; for (int w = 0; w < 8; ++w) { if (Wlen[w] > 0) { card_t card = *Wp[w]; int o = SUIT(card); for ( int off = 0; off < 2; ++off ) { bool empty = !Wlen[o*2+off+outs]; if ((empty && (RANK(card) == PS_ACE)) || (!empty && (RANK(card) == RANK( *Wp[outs+o*2+off] ) + 1 ) ) ) { mp->card_index = 0; mp->from = w; mp->to = outs+o*2+off; mp->totype = O_Type; mp->pri = params[4]; mp->turn_index = -1; if ( Wlen[w] > 1 && DOWN( W[w][Wlen[w]-2] ) ) mp->turn_index = 1; n++; mp++; /* If it's an automove, just do it. */ if (params[4] == 127 || good_automove(o, RANK(card))) { *a = true; mp[-1].pri = 127; if (n != 1) Possible[0] = mp[-1]; return 1; } } } } } /* No more automoves, but remember if there were any moves out. */ *a = false; *numout = n; for(int i=0; i<8; ++i) { int len = Wlen[i]; for (int l=0; l < len; ++l ) { card_t card = W[i][Wlen[i]-1-l]; if ( DOWN( card ) ) break; if ( l > 0 ) { card_t card_on_top = W[i][Wlen[i]-l]; if ( RANK( card ) != RANK( card_on_top ) + 1 ) break; if ( !suitable( card, card_on_top ) ) break; } bool wasempty = false; for (int j = 0; j < 8; ++j) { if (i == j) continue; bool allowed = false; if ( Wlen[j] > 0 && suitable( card, *Wp[j] ) && RANK(card) == RANK(*Wp[j]) - 1 ) { allowed = true; } if ( Wlen[j] == 0 && !wasempty ) { if ( l != Wlen[i]-1 ) { allowed = true; wasempty = true; } } if ( !allowed ) continue; mp->card_index = l; mp->from = i; mp->to = j; mp->totype = W_Type; mp->turn_index = -1; mp->pri = params[3]; if (Wlen[i] >= 2+l) { assert(Wlen[i]-2-l >= 0); card_t card2 = W[i][Wlen[i]-2-l]; if (DOWN(card2)) { mp->turn_index = 1; mp->pri = params[2]; } if ( Wlen[i] >= l+2 && RANK( card ) == RANK( card2 ) - 1 && COLOR( card ) != COLOR( card2 ) && !DOWN( card2 ) ) { int o = SUIT(card2); for ( int off = 0; off < 2; ++off ) { bool empty = !Wlen[o*2+off+outs]; if ((empty && (RANK(card2) == PS_ACE)) || (!empty && (RANK(card2) == RANK( *Wp[outs+o*2+off] ) + 1 ) ) ) { o = -1; break; } } if ( o > -1 ) mp->pri = -117; else mp->pri = ( int )qMin( qreal( 127. ), params[1] + qreal( l ) * params[5] / 10 ); } } n++; mp++; // leave one for redeal if (n >= MAXMOVES - 2) goto redeal; } } } redeal: if ( Wlen[deck] ) { /* check for redeal */ mp->card_index = 0; mp->from = deck; mp->to = 0; // unused mp->totype = W_Type; mp->pri = params[0]; mp->turn_index = -1; n++; mp++; } assert(n < MAXMOVES); return n; }