@Override protected boolean doStep(SolutionStep step) { boolean handled = true; sudoku = finder.getSudoku(); switch (step.getType()) { case XY_WING: case W_WING: case XYZ_WING: for (Candidate cand : step.getCandidatesToDelete()) { sudoku.delCandidate(cand.getIndex(), cand.getValue()); } break; default: handled = false; } return handled; }
@Override protected boolean doStep(SolutionStep step) { boolean handled = false; switch (step.getType()) { case GIVE_UP: handled = true; break; default: handled = false; } return handled; }
/** * Creates a step for a W-Wing. <code>cand1</code> is the candidate for which eliminations can be * made, <code>cand2</code> is the connecting candidate. <code>index1</code> and <code>index2 * </code> are the bivalue cells, {@link #wIndex1} and {@link #wIndex2} are the strong link. * <code>elimSet</code> holds all cells where candidates can be eliminated. * * @param cand1 * @param cand2 * @param index1 * @param index2 * @param elimSet * @param onlyOne * @return */ private SolutionStep createWWingStep( int cand1, int cand2, int index1, int index2, SudokuSet elimSet, boolean onlyOne) { globalStep.reset(); globalStep.setType(SolutionType.W_WING); globalStep.addValue(cand1); globalStep.addValue(cand2); globalStep.addIndex(index1); globalStep.addIndex(index2); globalStep.addFin(index1, cand2); globalStep.addFin(index2, cand2); globalStep.addFin(wIndex1, cand2); globalStep.addFin(wIndex2, cand2); for (int i = 0; i < elimSet.size(); i++) { globalStep.addCandidateToDelete(elimSet.get(i), cand1); } SolutionStep step = (SolutionStep) globalStep.clone(); if (onlyOne) { return step; } else { steps.add(step); } return null; }
/** * Try all combinations of three bivalue cells (for xyz: one trivalue and two bivalue cells). The * following restrictions are in place: * * <ul> * <li>The three cells must have exactly three candidates together * <li>The first cell (pivot) must see both other cells (pincers) * <li>The pincers must have exactly one candidate that is the same (candidate z) * <li>z can be excluded from all cells that see both pincers (for xyz they must see the pivot * as well) * </ul> * * @param xyz * @param onlyOne * @return */ private SolutionStep getWing(boolean xyz, boolean onlyOne) { // first get all bivalue/trivalue cells int biValueCount = 0; int triValueCount = 0; for (int i = 0; i < Sudoku2.LENGTH; i++) { if (sudoku.getAnzCandidates(i) == 2) { biCells[biValueCount++] = i; } if (xyz && sudoku.getAnzCandidates(i) == 3) { triCells[triValueCount++] = i; } } // now iterate them; use local variables to cover xy and xyz int endIndex = xyz ? triValueCount : biValueCount; int[] biTri = xyz ? triCells : biCells; // we check all combinations of bivalue cells (one tri + 2 bi for xyz) for (int i = 0; i < endIndex; i++) { for (int j = xyz ? 0 : i + 1; j < biValueCount; j++) { // any given combination of two cells must give exactly three // candidates; if that is not the case, skip it right away if (Sudoku2.ANZ_VALUES[sudoku.getCell(biTri[i]) | sudoku.getCell(biCells[j])] != 3) { // cant become a wing continue; } for (int k = j + 1; k < biValueCount; k++) { int index1 = biTri[i]; int index2 = biCells[j]; int index3 = biCells[k]; int cell1 = sudoku.getCell(index1); int cell2 = sudoku.getCell(index2); int cell3 = sudoku.getCell(index3); // all three cells combined must have exactly three candidates if (Sudoku2.ANZ_VALUES[cell1 | cell2 | cell3] != 3) { // incorrect number of candidates continue; } // none of the cells may be equal if (cell1 == cell2 || cell2 == cell3 || cell3 == cell1) { // cant be a wing continue; } // three possibilities for XY-Wing: each cell could be the pincer // XYZ-Wing exits the loop after the first iteration int maxTries = xyz ? 1 : 3; for (int tries = 0; tries < maxTries; tries++) { // swap cells accordingly if (tries == 1) { index1 = biCells[j]; index2 = biTri[i]; cell1 = sudoku.getCell(index1); cell2 = sudoku.getCell(index2); } else if (tries == 2) { index1 = biCells[k]; index2 = biCells[j]; index3 = biTri[i]; cell1 = sudoku.getCell(index1); cell2 = sudoku.getCell(index2); cell3 = sudoku.getCell(index3); } // the pivot must see the pincers if (!Sudoku2.buddies[index1].contains(index2) || !Sudoku2.buddies[index1].contains(index3)) { // doesnt see them -> try another continue; } // the pincers must have exactly one candidate that is the same in both cells short cell = (short) (cell2 & cell3); if (Sudoku2.ANZ_VALUES[cell] != 1) { // no wing, sorry continue; } int candZ = Sudoku2.CAND_FROM_MASK[cell]; // are there candidates that can see the pincers? elimSet.setAnd(Sudoku2.buddies[index2], Sudoku2.buddies[index3]); elimSet.and(finder.getCandidates()[candZ]); if (xyz) { // the pivot as well elimSet.and(Sudoku2.buddies[index1]); } if (elimSet.isEmpty()) { // no candidates to delete continue; } // ok, wing found! globalStep.reset(); if (xyz) { globalStep.setType(SolutionType.XYZ_WING); } else { globalStep.setType(SolutionType.XY_WING); } int[] cands = sudoku.getAllCandidates(index1); globalStep.addValue(cands[0]); globalStep.addValue(cands[1]); if (xyz) { globalStep.addValue(cands[2]); } else { globalStep.addValue(candZ); } globalStep.addIndex(index1); globalStep.addIndex(index2); globalStep.addIndex(index3); if (xyz) { globalStep.addFin(index1, candZ); } globalStep.addFin(index2, candZ); globalStep.addFin(index3, candZ); for (int l = 0; l < elimSet.size(); l++) { globalStep.addCandidateToDelete(elimSet.get(l), candZ); } SolutionStep step = (SolutionStep) globalStep.clone(); if (onlyOne) { return step; } else { steps.add(step); } } } } } return null; }
@Override public String toString() { // return "ALS: " + candidates.toString() + " - " + indices.toString(); return "ALS: " + SolutionStep.getAls(this); }