package org.alcibiade.eternity.editor.solver.backtracking; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; 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.ClusterManager; import org.alcibiade.eternity.editor.solver.path.PathProvider; public class IterativePathSolverMkII extends IterativePathSolverMkI { private List<Set<Pattern>> patternSets = new ArrayList<Set<Pattern>>(); public IterativePathSolverMkII(GridModel grid, GridModel solutionGrid, ClusterManager clusterManager, PathProvider pathProvider) { super(grid, solutionGrid, clusterManager, pathProvider); for (int i = 0; i < (4 * positions); i++) { patternSets.add(new TreeSet<Pattern>()); } } @Override public String getSolverName() { return "Iterative Path Solver MkII $Revision: 234 $"; } @Override protected boolean validateUpdate(int srcOffset, int destOffset) { boolean result = super.validateUpdate(srcOffset, destOffset); if (result) { initializeLists(); result = isFit(srcOffset, destOffset); } return result; } private boolean isFit(int srcOffset, int destOffset) { QuadModel quad = pieces.getQuad(srcOffset).clone(); boolean result = false; for (int rot = 0; !result && rot < 4; rot++) { quad.rotateClockwise(); int matches = 0; for (int d = 0; d < 4; d++) { Pattern pattern = quad.getPattern(d); if (patternSets.get(4 * destOffset + d).contains(pattern)) { matches += 1; } } result = (matches == 4); } return result; } private void initializeLists() { for (int offs = 0; offs < positions; offs++) { fillNeighborValues(offs); Set<QuadModel> matches = findMatches(offs); for (int orientation = 0; orientation < 4; orientation++) { Set<Pattern> validPatterns = patternSets.get(offs * 4 + orientation); if (validPatterns.isEmpty()) { for (QuadModel match : matches) { validPatterns.add(match.getPattern(orientation)); } } } } for (int index = 0; index < positions; index++) { for (int d = 0; d < 4; d++) { int neighborIndex = solutionGrid.computeNeighborIndex(index, d); if (neighborIndex >= 0) { Set<Pattern> s1 = patternSets.get(index * 4 + d); Set<Pattern> s2 = patternSets.get(neighborIndex * 4 + ((d + 2) % 4)); Iterator<Pattern> s1It = s1.iterator(); while (s1It.hasNext()) { Pattern p = s1It.next(); if (!s2.contains(p)) { s1It.remove(); } } } } } } private Set<QuadModel> findMatches(int offs) { Set<QuadModel> matches = new HashSet<QuadModel>(); for (int srcOffset = 0; srcOffset < positions; srcOffset++) { QuadModel srcQuad = pieces.getQuad(srcOffset).clone(); for (int orientation = 0; orientation < 4; orientation++) { srcQuad.rotateClockwise(); boolean matching = true; for (int testDir = 0; testDir < 4; testDir++) { Set<Pattern> validPatterns = patternSets.get(offs * 4 + testDir); if (validPatterns.isEmpty() || validPatterns.contains(srcQuad.getPattern(testDir))) { // This is matching } else { matching = false; } } if (matching) { matches.add(srcQuad.clone()); } } } return matches; } private void fillNeighborValues(int offs) { QuadModel quad = solutionGrid.getQuad(offs); for (int d = 0; d < 4; d++) { Set<Pattern> validPatterns = patternSets.get(offs * 4 + d); validPatterns.clear(); if (quad.isClear()) { QuadModel neighbor = solutionGrid.getNeighbor(offs, d); if (neighbor == null) { // Border cell validPatterns.add(defaultpat); } else if (neighbor.isClear()) { // Empty neighbor // validPatterns.addAll(getAllSourcePatterns()); } else { // Standard piece neighbor Pattern neighborPattern = neighbor.getPattern((d + 2) % 4); validPatterns.add(neighborPattern); } } else { validPatterns.add(quad.getPattern(d)); } } } }