package org.alcibiade.eternity.editor.solver.backtracking; import org.alcibiade.eternity.editor.model.GridModel; import org.alcibiade.eternity.editor.model.Pattern; import org.alcibiade.eternity.editor.model.QuadModel; import org.alcibiade.eternity.editor.solver.collection.EnablingList; public class NeighborhoodMatcher { public GridNeighborhoods computeNeighborHoods(GridModel grid) { GridNeighborhoods neighborhoods = new GridNeighborhoods(); for (int i = 0; i < grid.getPositions(); i++) { QuadModel quad = grid.getQuad(i); EnablingList<QuadModel> otherQuads = new EnablingList<QuadModel>(); for (int j = 0; j < grid.getPositions(); j++) { if (i != j) { QuadModel otherQuad = grid.getQuad(j); if (quad.countDefaultPattern() >= otherQuad.countDefaultPattern()) { otherQuads.add(otherQuad); } } } computeNeighborhood(neighborhoods, quad, otherQuads); } return neighborhoods; } private void computeNeighborhood(GridNeighborhoods neighborhoods, QuadModel quad, EnablingList<QuadModel> otherQuads) { Pattern defpat = Pattern.getDefaultPattern(); Neighborhood neighborhood; int borders = quad.countDefaultPattern(); assert borders >= 0 && borders < 3; if (borders == 0) { neighborhood = new Neighborhood(3, 3); quad.copyTo(neighborhood.getQuad(1, 1)); } else if (borders == 1) { neighborhood = new Neighborhood(3, 2); QuadModel target = neighborhood.getQuad(1, 0); quad.copyTo(target); while (target.getPattern(QuadModel.DIR_NORTH) != defpat) { target.rotateClockwise(); } } else { neighborhood = new Neighborhood(2, 2); QuadModel target = neighborhood.getQuad(0, 0); quad.copyTo(target); while (target.getPattern(QuadModel.DIR_NORTH) != defpat || target.getPattern(QuadModel.DIR_WEST) != defpat) { target.rotateClockwise(); } } fillNeighborhood(neighborhoods, neighborhood, otherQuads); } private void fillNeighborhood(GridNeighborhoods neighborhoods, Neighborhood neighborhood, EnablingList<QuadModel> otherQuads) { int emptyIndex = -1; for (int i : neighborhood.getIndices()) { if (neighborhood.getQuad(i).isClear()) { emptyIndex = i; break; } } if (emptyIndex < 0) { if (neighborhood.isValidNeighborhood()) { Neighborhood n = new Neighborhood(neighborhood); neighborhoods.add(n); } } else { int otherQuadsSize = otherQuads.size(); for (int qix = 0; qix < otherQuadsSize; qix++) { QuadModel quad = otherQuads.get(qix); otherQuads.disable(quad); QuadModel emptyQuad = neighborhood.getQuad(emptyIndex); quad.copyTo(emptyQuad); for (int d = 0; d < 4; d++) { emptyQuad.rotateClockwise(); if (validate(neighborhood, emptyIndex)) { fillNeighborhood(neighborhoods, neighborhood, otherQuads); } } otherQuads.enable(quad); emptyQuad.clear(); } } } private boolean validate(Neighborhood neighborhood, int emptyIndex) { boolean validationResult = true; QuadModel quad = neighborhood.getQuad(emptyIndex); for (int d = 0; d < 4; d++) { QuadModel neighbor = neighborhood.getNeighbor(emptyIndex, d); if (neighbor != null && !neighbor.isClear()) { validationResult = validationResult && quad.getPattern(d) == neighbor.getPattern((d + 2) % 4); } } return validationResult; } }