Beispiel #1
0
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;
}
Beispiel #2
0
/// 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
}
Beispiel #3
0
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();
}