puzzle delete_heap (void) { puzzle return_val; puzzle tmp; int favored_child; int index; if (heap_size == 0) { printf ("Heap underflow\n"); exit (-1); } return_val = heap[0]; heap[0] = heap[heap_size-1]; heap_size--; index = 0; while (LCHILD(index) < heap_size) { if (RCHILD(index) >= heap_size) favored_child = LCHILD(index); else if (superior(RCHILD(index),LCHILD(index))) favored_child = RCHILD(index); else favored_child = LCHILD(index); if (superior(index, favored_child)) break; tmp = heap[index]; heap[index] = heap[favored_child]; heap[favored_child] = tmp; index = favored_child; } return return_val; }
/// Compares the costs of two strategies. /// @ingroup strat inline bool operator < (const StrategyCost &c1, const StrategyCost &c2) { #if USE_UNNAMED_STRUCT return c1.value < c2.value; #else return superior(c1, c2, MinWorst); //return *(const long long *)&c1 < *(const long long *)&c2; #endif }
void insert_heap(puzzle b) { puzzle tmp; int index; if (heap_size == MAX_HEAP_SIZE) { printf ("Heap overflow\n"); exit(-1); } heap[heap_size] = b; index = heap_size; heap_size++; while ((index > 0) && superior(index, PARENT(index))) { tmp = heap[index]; heap[index] = heap[PARENT(index)]; heap[PARENT(index)] = tmp; index = PARENT(index); } }
/** * Returns an obviously-optimal guess if one exists. * We will only make a guess from the list of remaining possibilities. * * @param e Algorithm engine. * @param possibilities List of remaining possibilities. * @param max_depth Maximum number of guesses allowed, including the * initial guess. * @param min_obj Minimum objective that an obvious guess must meet. * @param cost If an obvious guess is found, stores the cost of an optimal * strategy that begins with this guess. * @param obj If an obvious guess is found, stores in what sense is this * guess optimal. * * @returns An obvious guess such that an optimal strategy starting with * this guess has the smallest number of total steps, will not take * more than max_depth depth, and achieves at least min_obj. */ Codeword make_obvious_guess( const Engine *e, CodewordConstRange possibilities, int max_depth, StrategyObjective min_obj, StrategyCost &cost, StrategyObjective &obj) { int count = (int)possibilities.size(); // If there are no remaining possibilities, no guess is needed. if (count == 0) return Codeword(); // Now we need to make at least one guess. If that's not allowed, return. if (max_depth < 1) return Codeword(); // If there is only one possibility left, guess it. if (count == 1) { cost = StrategyCost(1, 1, 1); obj = MinWorst; return possibilities[0]; } // Now we need to make at least two guesses to reveal every secret. // If that's not allowed, return. if (max_depth < 2) return Codeword(); // If there are only two possibilities left, guess the first one. if (count == 2) { cost = StrategyCost(3, 2, 1); obj = MinWorst; return possibilities[0]; } // If the number of possibilities is greater than the number of // distinct feedbacks, there will (very likely) be no obvious guess. // So we won't make any further attempt. int p = e->rules().pegs(); if (count > p*(p+3)/2) return Codeword(); // Check each remaining possiblity as guess in turn. // - If a guess partitions the remaining possibilities into singleton // cells, return it immediately. // - If no such guess exists but one exists that partitions them into // (n-1) singleton cells and one cell with 2 secrets, return it. // Note however that such a guess may only be optimal in terms of // total steps; a non-possible guess may yield lower depth (i.e. 1). // - Otherwise, keep the best guess that partitions the remaining // possibilities into cells with no more than two secrets. Compare // this cost with an estimated obvious lower bound of a non-possible // guess. If the cost < lower bound, return this guess firmly. If // cost = lower bound, then this guess is only optimal in terms of // total number of steps, but not in depth. Codeword best_guess; int best_extra = -1; for (int i = 0; i < count; ++i) { Codeword guess = possibilities[i]; FeedbackFrequencyTable freq = e->compare(guess, possibilities); unsigned int nonzero = 1; // 4A0B unsigned int maxfreq = 0; for (size_t j = 0; j < freq.size() - 2; ++j) // skip 3A0B and 4A0B { if (freq[j]) { maxfreq = std::max(maxfreq, freq[j]); ++nonzero; } } if (maxfreq == 1) // all cells are singleton cells { cost = StrategyCost(2*count-1, 2, (unsigned short)(count-1)); obj = MinWorst; return guess; } if (maxfreq > 2) { continue; } int extra = (int)(count - nonzero); // number of cells with 2 secrets if (best_extra < 0 || extra < best_extra) { best_extra = extra; best_guess = guess; } } // If no guess partitions the remaining possibilities into cells with // no more than two secrets, there is no obvious strategy. if (best_extra < 0) return Codeword(); // Update the cost. cost = StrategyCost(2*count-1+best_extra, 3, 1); // If exactly one cell contains two secrets and all the rest are // singleton, then this guess is guaranteed to be optimal in steps, // and we needn't check further if that's what's required. if (best_extra == 1 && min_obj == MinSteps) { obj = MinSteps; return best_guess; } // Now it's not obvious whether our guess is optimal. We make an attempt // to estimate the lower bound of cost of any non-possible guess. #if 1 StrategyCost lb = estimate_obvious_lowerbound(e->rules(), possibilities); if (!superior(lb, cost, min_obj)) { obj = min_obj; return best_guess; } #endif return Codeword(); }