+ if (cagey) {
+ /*
+ * First, check that each laser the player has already
+ * fired is consistent with the layout. If not, show them
+ * one error they've made and reveal no further
+ * information.
+ *
+ * Failing that, check to see whether the player would have
+ * been able to fire any laser which distinguished the real
+ * solution from their guess. If so, show them one such
+ * laser and reveal no further information.
+ */
+ guesses = dup_game(state);
+ /* clear out BALL_CORRECT on guess, make BALL_GUESS BALL_CORRECT. */
+ for (x = 1; x <= state->w; x++) {
+ for (y = 1; y <= state->h; y++) {
+ GRID(guesses, x, y) &= ~BALL_CORRECT;
+ if (GRID(guesses, x, y) & BALL_GUESS)
+ GRID(guesses, x, y) |= BALL_CORRECT;
+ }
+ }
+ n = 0;
+ for (i = 0; i < guesses->nlasers; i++) {
+ if (guesses->exits[i] != LASER_EMPTY &&
+ guesses->exits[i] != laser_exit(guesses, i))
+ n++;
+ }
+ if (n) {
+ /*
+ * At least one of the player's existing lasers
+ * contradicts their ball placement. Pick a random one,
+ * highlight it, and return.
+ *
+ * A temporary random state is created from the current
+ * grid, so that repeating the same marking will give
+ * the same answer instead of a different one.
+ */
+ random_state *rs = random_new((char *)guesses->grid,
+ (state->w+2)*(state->h+2) *
+ sizeof(unsigned int));
+ n = random_upto(rs, n);
+ random_free(rs);
+ for (i = 0; i < guesses->nlasers; i++) {
+ if (guesses->exits[i] != LASER_EMPTY &&
+ guesses->exits[i] != laser_exit(guesses, i) &&
+ n-- == 0) {
+ state->exits[i] |= LASER_WRONG;
+ tmp = laser_exit(state, i);
+ if (RANGECHECK(state, tmp))
+ state->exits[tmp] |= LASER_WRONG;
+ state->justwrong = TRUE;
+ free_game(guesses);
+ return 0;
+ }
+ }
+ }
+ n = 0;
+ for (i = 0; i < guesses->nlasers; i++) {
+ if (guesses->exits[i] == LASER_EMPTY &&
+ laser_exit(state, i) != laser_exit(guesses, i))
+ n++;
+ }
+ if (n) {
+ /*
+ * At least one of the player's unfired lasers would
+ * demonstrate their ball placement to be wrong. Pick a
+ * random one, highlight it, and return.
+ *
+ * A temporary random state is created from the current
+ * grid, so that repeating the same marking will give
+ * the same answer instead of a different one.
+ */
+ random_state *rs = random_new((char *)guesses->grid,
+ (state->w+2)*(state->h+2) *
+ sizeof(unsigned int));
+ n = random_upto(rs, n);
+ random_free(rs);
+ for (i = 0; i < guesses->nlasers; i++) {
+ if (guesses->exits[i] == LASER_EMPTY &&
+ laser_exit(state, i) != laser_exit(guesses, i) &&
+ n-- == 0) {
+ fire_laser(state, i);
+ state->exits[i] |= LASER_OMITTED;
+ tmp = laser_exit(state, i);
+ if (RANGECHECK(state, tmp))
+ state->exits[tmp] |= LASER_OMITTED;
+ state->justwrong = TRUE;
+ free_game(guesses);
+ return 0;
+ }
+ }
+ }
+ free_game(guesses);
+ }
+