示例#1
0
StepCode EliminateNakedPairsStep::runOnHouse(House &cell_list) {
  bool modified = false;
  std::set<Mask> found_masks;
  std::set<Mask> duplicate_masks;
  for (const Cell *cell : cell_list) {
    if (cell->candidates.none()) {
      return {true, modified};
    }
    if (cell->candidates.count() != 2) {
      continue;
    }

    const Mask mask = cell->candidates.to_ulong();

    if (found_masks.count(mask)) {
      duplicate_masks.insert(cell->candidates.to_ulong());
    }

    found_masks.insert(mask);
  }

  for (auto &mask : duplicate_masks) {
    for (Cell *cell : cell_list) {
      if (cell->isFixed()) {
        continue;
      }

      CandidateSet *candidates = &cell->candidates;
      if (candidates->to_ulong() == mask) {
        continue;
      }

      auto new_cands = CandidateSet(candidates->to_ulong() & ~mask);
      if (*candidates == new_cands) {
        continue;
      }

      if (DEBUG) {
        const Mask intersection = candidates->to_ulong() & mask;
        dbgs() << "Naked Pair " << printCandidateString(mask) << " removes "
               << printCandidateString(intersection) << " from " << cell->coord
               << "\n";
      }

      modified = true;
      changed.insert(cell);
      *candidates = new_cands;
    }
  }

  return {false, modified};
}
示例#2
0
StepCode EliminateNakedTriplesStep::runOnHouse(House &house) {
  bool modified = false;

  if (house.size() <= 3) {
    return {false, modified};
  }

  std::vector<std::pair<Mask, std::vector<const Cell *>>> found_masks;
  for (const Cell *cell : house) {
    std::size_t num_candidates = cell->candidates.count();
    if (num_candidates == 0) {
      return {true, modified};
    }
    if (num_candidates != 2 && num_candidates != 3) {
      continue;
    }

    const Mask mask = cell->candidates.to_ulong();

    bool found_match = false;
    for (unsigned i = 0; i < found_masks.size(); ++i) {
      const Mask m = found_masks[i].first;

      // ORing the two masks together will switch on all candidates found in
      // both masks. If it's less than three, then we're still a triple
      // candidate.
      // TODO: If the current mask is size 2 and the OR of the two is 3, then
      // we should create two masks: one for the two and one for the OR.
      // Otherwise you could get 1/2 match with 1/2/3 and 1/2/4.
      // For now, only accept found masks of size 3. Easy naked triples.
      if (bitCount(m) == 3 && bitCount(mask | m) == 3) {
        found_match = true;
        found_masks[i].second.push_back(cell);
      }
    }

    if (!found_match) {
      std::pair<Mask, std::vector<const Cell *>> pair;
      pair.first = mask;
      pair.second.push_back(cell);
      found_masks.push_back(pair);
    }
  }

  for (auto &pair : found_masks) {
    if (pair.second.size() != 3) {
      continue;
    }

    auto &matches = pair.second;
    const Mask mask = pair.first;

    for (Cell *cell : house) {
      if (cell->isFixed()) {
        continue;
      }

      if (std::find(matches.begin(), matches.end(), cell) != matches.end()) {
        continue;
      }

      CandidateSet *candidates = &cell->candidates;
      if (candidates->to_ulong() == mask) {
        continue;
      }
      auto new_cands = CandidateSet(candidates->to_ulong() & ~mask);
      if (*candidates == new_cands) {
        continue;
      }

      if (DEBUG) {
        const Mask intersection = candidates->to_ulong() & mask;
        dbgs() << "Naked Triple " << printCandidateString(mask) << " removes "
               << printCandidateString(intersection) << " from " << cell->coord
               << "\n";
      }

      modified = true;
      changed.insert(cell);
      *candidates = new_cands;
    }
  }

  return {false, modified};
}