import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.Random; import java.io.*; public class EternityII { public static void main(String... args) throws IOException { for (int id = 0; id < 1; id++) { Solver solver = new Solver(id, true, 2, "A6x6With1Hint.txt", "sol1_11.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); /* solver = new Solver(id, true, 0, "tiles2_11_5.17", "sol2_11.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 0, "tiles3_11_5.17", "sol3_11.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 0, "tiles4_11_5.17", "sol4_11.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 0, "tiles5_11_5.17", "sol5.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 0, "tiles1_12_5.17", "sol1_l2.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 0, "tiles2_12_5.17", "sol2_l2.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 0, "tiles3_12_5.17", "sol3_12.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 0, "tiles5_12_5.17", "sol5_12.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 5, "tiles2_13_5.17_9hints_1", "sol13_9_15.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 5, "tiles2_13_5.17_9hints_2", "sol13_9_25.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 7, "tiles_12_5.17.txt_hints", "sol12_hints.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); solver = new Solver(id, true, 4, "tiles1_13_5.17_manyhints", "sol1_13_manyhints.txt"); solver.solve(); solver.storeNumSolutions(); solver.printStats(); */ } } } final class Solver { // defines public static boolean STATS = false; public static boolean STOP_AFTER_FIRST_CORNER_PIECE = false; public static boolean DUMP_SOLUTION_FOUND = true; public static boolean DUMP_MIN_DEPTH = true; public static final int NORMAL = 0; public static final int BORDER = 1; public static final int CORNER = 2; public static final int HINT = 3; public static final int TO_RIGHT_BOTTOM = 0; public static final int TO_LEFT = 1; public static final int TO_TOP = 2; public static final int TO_ALL = 3; public static final int CHECK_ALL = 0; public static final int CHECK_LT = 1; public static final int CHECK_TR = 2; public static final int CHECK_BL = 3; public static final int CHECK_LTB = 4; public static final int CHECK_LTR = 5; public static final int CHECK_TRB = 6; public static final int CHECK_RBL = 7; private static long _startTime; int _solverId; int _sizeX; int _sizeY; int _numEdgeTypes; int _numPieces; int _numEdges; boolean _useHints; int[][] _hintAdjustment; long _numPiecesPlaced; //CHECK_RBL List _allPieceRotations; List[][] _pieceMatchesLT; List[][] _pieceMatchesTR; List[][] _pieceMatchesBL; List[][][] _pieceMatchesLTB; List[][][] _pieceMatchesLTR; List[][][] _pieceMatchesTRB; List[][][] _pieceMatchesRBL; List[][][][] _pieceMatches; List _hintPieces; FileWriter _boardFile; IntegerRef _boardEdges[]; int _numSolutions; PieceLocation[] _rowScanVector; String _piecesFileName; int _maxDepth; private List _hintStrategy; //#ifdef STATS int[] _nodeCounts; int[] _xPlaced; int[] _yPlaced; int[][] _xyCount; //#endif final static class PieceLocation { private final IntegerRef top; private final IntegerRef right; private final IntegerRef bottom; private final IntegerRef left; public boolean isUsed; public int type; public int check; public int direction; public int pos; PieceLocation(IntegerRef theTop, IntegerRef theRight, IntegerRef theBottom, IntegerRef theLeft, int thePos) { top = theTop; right = theRight; bottom = theBottom; left = theLeft; pos = thePos; type = NORMAL; check = CHECK_LT; direction = TO_RIGHT_BOTTOM; isUsed = false; } public int top() { return top.getValue(); } public int right() { return right.getValue(); } public int bottom() { return bottom.getValue(); } public int left() { return left.getValue(); } public void setTop(int i) { top.setValue(i); } public void setRight(int i) { right.setValue(i); } public void setBottom(int i) { bottom.setValue(i); } public void setLeft(int i) { left.setValue(i); } } final static class PieceRotation { public int top; public int right; public int bottom; public int left; private BooleanRef isUsed; public int type; PieceRotation(int theTop, int theRight, int theBottom, int theLeft, BooleanRef theIsUsed) { top = theTop; right = theRight; bottom = theBottom; left = theLeft; isUsed = theIsUsed; type = NORMAL; if (top == 1 || right == 1 || bottom == 1 || left == 1) type = BORDER; if ( (top == 1 && right == 1) || (right == 1 && bottom == 1) || (bottom == 1 && left == 1) || (left == 1 && top == 1) ) type = CORNER; } public boolean isUsed() { return isUsed.getValue(); } public void setUsed(boolean b) { isUsed.setValue(b); } } final static class HintPiece { final int posX; final int posY; final int id; final int rotation; HintPiece(int thePosX, int thePosY, int theId, int theRotation) { posX = thePosX; posY = thePosY; id = theId; rotation = theRotation; } } static void setStartTime() { _startTime = System.currentTimeMillis(); } static long usedTime() { return System.currentTimeMillis() - _startTime; } static long usedMsecs() { return usedTime(); } void shuffleVector(List pieces) { Collections.shuffle(pieces, new Random()); } List getMatches(PieceLocation solutionPiece) { return _pieceMatches[solutionPiece.left.getValue()][solutionPiece.top.getValue()][solutionPiece.right.getValue()][solutionPiece.bottom.getValue()]; } List getMatchesFast(PieceLocation solutionPiece) { switch (solutionPiece.check) { case CHECK_LT: { return _pieceMatchesLT[solutionPiece.left.getValue()][solutionPiece.top.getValue()]; } case CHECK_TR: { return _pieceMatchesTR[solutionPiece.top.getValue()][solutionPiece.right.getValue()]; } case CHECK_BL: { return _pieceMatchesBL[solutionPiece.bottom.getValue()][solutionPiece.left.getValue()]; } case CHECK_LTB: { return _pieceMatchesLTB[solutionPiece.left.getValue()][solutionPiece.top.getValue()][solutionPiece.bottom.getValue()]; } case CHECK_LTR: { return _pieceMatchesLTR[solutionPiece.left.getValue()][solutionPiece.top.getValue()][solutionPiece.right.getValue()]; } case CHECK_TRB: { return _pieceMatchesTRB[solutionPiece.top.getValue()][solutionPiece.right.getValue()][solutionPiece.bottom.getValue()]; } case CHECK_RBL: { return _pieceMatchesRBL[solutionPiece.right.getValue()][solutionPiece.bottom.getValue()][solutionPiece.left.getValue()]; } case CHECK_ALL: { return _pieceMatches[solutionPiece.left.getValue()][solutionPiece.top.getValue()][solutionPiece.right.getValue()][solutionPiece.bottom.getValue()]; } } return null; } int getMatchCount(PieceLocation solutionPiece) { return getMatches(solutionPiece).size(); } int getMatchCountFast(PieceLocation solutionPiece) { return getMatchesFast(solutionPiece).size(); } public Solver(int solverId, boolean useHints, int numRotations, String pieceFileName, String solutionFileName) throws IOException { _solverId = solverId; _sizeX = 0; _sizeY = 0; _numSolutions = 0; _piecesFileName = pieceFileName; _boardFile= new FileWriter(solutionFileName); _useHints = useHints; _numPiecesPlaced = 0; readPieceFile(numRotations); } void storeBoard() throws IOException { int numEdgesBoard = (_sizeX+1)*(_sizeY)+ (_sizeX)*(_sizeY+1); int i; int edgePos = 0; _boardFile.write( String.format("\nSolution %d:\n", _numSolutions) ); while (edgePos=numEdgesBoard) break; for (i=0; i<_sizeY+1; i++) { _boardFile.write("|"); if (_boardEdges[i+edgePos].getValue()<=0) _boardFile.write(" | "); else { if (_boardEdges[i+edgePos].getValue()<=10) _boardFile.write("0"); _boardFile.write( String.format("%d| ", _boardEdges[i+edgePos].getValue() - 1) ); } } edgePos+=_sizeY+1; } storeStats(); _boardFile.flush(); } void storeStats() throws IOException { if( STATS ) { _boardFile.write("\nNodeCounts:\n"); for (int d = 1; d <= _numPieces; d++) { _boardFile.write(String.format("\n%3d %9d x=%d y=%d", d, _nodeCounts[d], _xPlaced[d], _yPlaced[d])); } _boardFile.write("\n\nxyNodeCounts:\n"); _boardFile.write("\nY= "); for (int y = 0; y < _sizeY; y++) { _boardFile.write(String.format("%12d", y)); } for (int x = 0; x < _sizeX; x++) { _boardFile.write(String.format("\nX=%2d ", x)); for (int y = 0; y < _sizeY; y++) { _boardFile.write(String.format("%12d", _xyCount[x][y])); } } _boardFile.write("\n"); } } void storeStrategy(List scanVector) { try { _boardFile.write("\nStrategy:\n"); for (int p = 0; p < _numPieces; p++) { PieceLocation piece = scanVector.get(p); _boardFile.write(String.format("\n %d x=%d y=%d", p+1, piece.pos / _sizeY, piece.pos % _sizeY)); } } catch(IOException ex) { throw new RuntimeException(ex); } } void storeNumSolutions() throws IOException { _boardFile.write(String.format("\n number of solutions: %d\n", _numSolutions)); storeStats(); _boardFile.flush(); } void printStats() { System.out.print(String.format("\nSolver %d -%s- Time: %d msec Solutions: %d", _solverId, _piecesFileName, usedMsecs(), _numSolutions) ); System.out.print(String.format("\n Number of placements : %d", _numPiecesPlaced) ); System.out.print(String.format("\n Millions placements per sec: %f", ((double) (_numPiecesPlaced / (usedMsecs()+1)) / 1000))); System.out.flush(); } int initHintFactor(int x, int y) { return x+y; } @SuppressWarnings({"unchecked"}) void createArrays() { _allPieceRotations = new ArrayList(); _pieceMatches = new ArrayList[_numEdgeTypes][_numEdgeTypes][_numEdgeTypes][_numEdgeTypes]; _pieceMatchesLT = new ArrayList[_numEdgeTypes][_numEdgeTypes]; _pieceMatchesTR = new ArrayList[_numEdgeTypes][_numEdgeTypes]; _pieceMatchesBL = new ArrayList[_numEdgeTypes][_numEdgeTypes]; _pieceMatchesLTR = new ArrayList[_numEdgeTypes][_numEdgeTypes][_numEdgeTypes]; _pieceMatchesLTB = new ArrayList[_numEdgeTypes][_numEdgeTypes][_numEdgeTypes]; _pieceMatchesTRB = new ArrayList[_numEdgeTypes][_numEdgeTypes][_numEdgeTypes]; _pieceMatchesRBL = new ArrayList[_numEdgeTypes][_numEdgeTypes][_numEdgeTypes]; _hintAdjustment = new int[_sizeX][_sizeY]; for (int i=0; i < _numEdgeTypes; i++) { for (int j=0; j<_numEdgeTypes; j++) { _pieceMatchesLT[i][j] = new ArrayList(); _pieceMatchesTR[i][j] = new ArrayList(); _pieceMatchesBL[i][j] = new ArrayList(); for (int k=0; k<_numEdgeTypes; k++) { _pieceMatchesLTR[i][j][k] = new ArrayList(); _pieceMatchesLTB[i][j][k] = new ArrayList(); _pieceMatchesTRB[i][j][k] = new ArrayList(); _pieceMatchesRBL[i][j][k] = new ArrayList(); for (int l=0; l<_numEdgeTypes; l++) { _pieceMatches[i][j][k][l]= new ArrayList(); } } } } int x; for (x = 0; x < _sizeX; x++) { for (int y = 0; y < _sizeY; y++) { _hintAdjustment[x][y] = initHintFactor(x,y); } } if( STATS ) { _nodeCounts = new int[_numPieces+1]; _xPlaced = new int[_numPieces+1]; _yPlaced = new int[_numPieces+1]; for (int d = 0; d <= _numPieces; d++) { _nodeCounts[d] = 0; _xPlaced[d] = 0; _xPlaced[d] = 0; } _xyCount = new int[_sizeX][_sizeY]; for (x = 0; x < _sizeX; x++) { for (int y = 0; y < _sizeY; y++) { _xyCount[x][y] = 0; } } } } void computePieceMatches() { for (int i = 0; i < _allPieceRotations.size(); i++) { PieceRotation p = _allPieceRotations.get(i); // eliminate symmetries boolean symmetric = false; for (int j = 1; j <= 3 && i-j >= 0; j++) { PieceRotation p2 = _allPieceRotations.get(i-j); if (p.left == p2.left && p.top == p2.top && p.right == p2.right && p.bottom == p2.bottom) { symmetric = true; break; } } if (!symmetric) { _pieceMatches[p.left][p.top][p.right][p.bottom].add(p); _pieceMatches[0][p.top][p.right][p.bottom].add(p); _pieceMatches[p.left][0][p.right][p.bottom].add(p); _pieceMatches[p.left][p.top][0][p.bottom].add(p); _pieceMatches[p.left][p.top][p.right][0].add(p); _pieceMatches[0][0][p.right][p.bottom].add(p); _pieceMatches[0][p.top][0][p.bottom].add(p); _pieceMatches[0][p.top][p.right][0].add(p); _pieceMatches[p.left][0][0][p.bottom].add(p); _pieceMatches[p.left][0][p.right][0].add(p); _pieceMatches[p.left][p.top][0][0].add(p); _pieceMatches[0][0][0][p.bottom].add(p); _pieceMatches[0][0][p.right][0].add(p); _pieceMatches[0][p.top][0][0].add(p); _pieceMatches[p.left][0][0][0].add(p); _pieceMatches[0][0][0][0].add(p); if (p.type != HINT) { if (p.right > 1 && p.bottom > 1) _pieceMatchesLT[p.left][p.top].add(p); if (p.bottom > 1 && p.left > 1) _pieceMatchesTR[p.top][p.right].add(p); if (p.top > 1 && p.right > 1) _pieceMatchesBL[p.bottom][p.left].add(p); if (p.bottom > 1) _pieceMatchesLTR[p.left][p.top][p.right].add(p); if (p.right > 1) _pieceMatchesLTB[p.left][p.top][p.bottom].add(p); if (p.left > 1) _pieceMatchesTRB[p.top][p.right][p.bottom].add(p); if (p.top > 1) _pieceMatchesRBL[p.right][p.bottom][p.left].add(p); } } } } void readPieceFile(int numRotations) throws IOException { LineNumberReader f = new LineNumberReader(new FileReader(_piecesFileName)); List pieces = new ArrayList(); String line = f.readLine(); while( line != null ) { String[] desc = line.split(" "); for( String i : desc ) { if( !i.trim().equals("") ) pieces.add(new Integer(i)); } line = f.readLine(); } f.close(); int[] pieceArr = new int[pieces.size()]; int i = 0; for( Integer ip : pieces ) pieceArr[i++] = ip; readPieces(pieceArr, numRotations); } void readEdges(/*int[] pieces, IntegerRef pos*/) { _numPieces = _sizeX*_sizeY; _numEdges = (_sizeX+1)*(_sizeY)+ (_sizeX)*(_sizeY+1); _boardEdges = new IntegerRef[_numEdges]; createArrays(); int i, numEdgesAtLine = 1+2*_sizeY; for (i=0; i<_numEdges; i++) { if ((i<_sizeY)|| ( (i%numEdgesAtLine)==(_sizeY))|| ( (i%numEdgesAtLine)==(numEdgesAtLine-1))|| ( (i>(_numEdges-_sizeY-1)))) _boardEdges[i] = new IntegerRef(1); // border else _boardEdges[i] = new IntegerRef(0); // wildcard } } void readEdgesNoHint(int[] pieces, IntegerRef pos) { _sizeX = pieces[pos.getValue()]; pos.plusplus(); _sizeY = pieces[pos.getValue()]; pos.plusplus(); _numEdgeTypes = pieces[pos.getValue()] + 2; // 0=wildcard 1=border pos.plusplus(); readEdges(/*pieces, pos*/); } void readEdgesHint(int[] pieces, IntegerRef pos) { int i; _sizeX = _sizeY = pieces[pos.getValue()]; pos.plusplus(); _numEdgeTypes = pieces[pos.getValue()] + 2; // 0=wildcard 1=border pos.plusplus(); int numHints = pieces[pos.getValue()]; pos.plusplus(); _hintPieces = new ArrayList(); for (i = 0; i < numHints; i++) { int posX = pieces[pos.getValue()]; pos.plusplus(); int posY = pieces[pos.getValue()]; pos.plusplus(); int id = pieces[pos.getValue()]; pos.plusplus(); int rotation = pieces[pos.getValue()]; pos.plusplus(); HintPiece hpiece = new HintPiece(posX, posY, id, rotation); _hintPieces.add(hpiece); } readEdges(/*pieces, pos*/); } void adjustHintFactor(int x, int y) { int ix,iy; if ((x <= _sizeX/2+1 && y <= _sizeY/2+1) || Math.abs(x-y) <= (_sizeX+_sizeY) / 6) { for (ix = 0; ix < x; ix++) { for (iy = 0; iy < y; iy++) _hintAdjustment[ix][iy] += -1000; } } } void adjustHintFactors() { for (int x = 0; x < _sizeX; x++) { for (int y = 0; y < _sizeY; y++) _hintAdjustment[x][y] = initHintFactor(x,y); } for (int p=0; p<_numPieces; p++) { if (_rowScanVector[p].type == HINT) { int x = p / _sizeY; int y = p % _sizeY; adjustHintFactor(x, y); } } } void setHintPieces() { for (HintPiece hpiece : _hintPieces) { int x = hpiece.posX - 1; int y = hpiece.posY - 1; int p = y + _sizeY * x; PieceLocation solPiece = _rowScanVector[p]; // our rotation is counter clockwise int prIndex = 4 * (hpiece.id - 1); for (int j = 0; j < 4; j++) _allPieceRotations.get(prIndex + j).type = HINT; int hintRotation = (4 - hpiece.rotation) % 4; PieceRotation pieceRotation = _allPieceRotations.get(prIndex + hintRotation); solPiece.setLeft(pieceRotation.left); solPiece.setTop(pieceRotation.top); solPiece.setRight(pieceRotation.right); solPiece.setBottom(pieceRotation.bottom); solPiece.type = HINT; } adjustHintFactors(); } void assignType(PieceLocation piece, int p, int x, int y) { if (piece.type != HINT) { if ((x==0 && y==0) || (x==_sizeX-1 && y==_sizeY-1) || (x==0 && y==_sizeY-1) || (x==_sizeX-1 && y==0)) piece.type = CORNER; else if (x==0 || y==0 || x==_sizeX-1 || y==_sizeY-1) piece.type = BORDER; else piece.type = NORMAL; } } void assignCheck(PieceLocation piece, int p, int x, int y) { if (piece.type != HINT) { boolean checkLeft = (y==0); boolean checkTop = (x==0); boolean checkRight = (y==(_sizeY-1)); boolean checkBottom = (x==(_sizeX-1)); if (!checkLeft) checkLeft = (_rowScanVector[p-1].type==HINT); if (!checkRight) checkRight = (_rowScanVector[p+1].type==HINT); if (!checkBottom) checkBottom = (_rowScanVector[p+_sizeY].type==HINT); if (!checkTop) checkTop = (_rowScanVector[p-_sizeY].type==HINT); switch (piece.direction) { case TO_LEFT: { if (checkLeft && checkBottom) piece.check = CHECK_ALL; else if (checkLeft) piece.check = CHECK_LTR; else if (checkBottom) piece.check = CHECK_TRB; else piece.check = CHECK_TR; break; } case TO_TOP: { if (checkTop && checkRight) piece.check = CHECK_ALL; else if (checkTop) piece.check = CHECK_LTB; else if (checkRight) piece.check = CHECK_RBL; else piece.check = CHECK_BL; break; } case TO_RIGHT_BOTTOM: { if (checkRight && checkBottom) piece.check = CHECK_ALL; else if (checkRight) piece.check = CHECK_LTR; else if (checkBottom) piece.check = CHECK_LTB; else piece.check = CHECK_LT; break; } case TO_ALL: { piece.check = CHECK_ALL; break; } } } else piece.check = CHECK_ALL; } void assignTypes(PieceLocation[] pieces) { for (int p=0; p<_numPieces; p++) { int x = p / _sizeY; int y = p % _sizeY; assignType(pieces[p], p, x, y); assignCheck(pieces[p], p, x, y); } } @SuppressWarnings({"SuspiciousNameCombination"}) void rotateSolutionVector() { PieceLocation[] scanVector = new PieceLocation[_numPieces]; int p; for (p=0; p<_numPieces; p++) { int x = p / _sizeY; int y = p % _sizeY; // 90 degree clockwise int dx = _sizeY-y-1; int dy = x; int dp = _sizeX * dx + dy; PieceLocation piece = _rowScanVector[p]; scanVector[dp] = new PieceLocation(piece.right,piece.bottom,piece.left, piece.top, dp); scanVector[dp].type = piece.type; _hintAdjustment[x][y] = initHintFactor(x,y); } for (p=0; p<_numPieces; p++) _rowScanVector[p] = scanVector[p]; adjustHintFactors(); } @SuppressWarnings({"SuspiciousNameCombination"}) void mirrorSolutionVector() { PieceLocation[] scanVector = new PieceLocation[_numPieces]; int p; for (p=0; p<_numPieces; p++) { int x = p / _sizeY; int y = p % _sizeY; // mirror along NW-SE diagonal int dx = y; int dy = x; int dp = _sizeX * dx + dy; PieceLocation piece = _rowScanVector[p]; scanVector[dp] = new PieceLocation(piece.left,piece.bottom,piece.right, piece.top, dp); scanVector[dp].type = piece.type; _hintAdjustment[x][y] = initHintFactor(x,y); } for (p=0; p<_numPieces; p++) _rowScanVector[p] = scanVector[p]; adjustHintFactors(); // mirror all piece rotations for (PieceRotation pr : _allPieceRotations) { int top = pr.top; pr.top = pr.left; pr.left = top; int right = pr.right; pr.right = pr.bottom; pr.bottom = right; } } void createSolutionVector() { _rowScanVector = new PieceLocation[_numPieces]; int numEdgesAtLine = 1+2*_sizeY; for (int p=0; p<_numPieces; p++) { int x = p / _sizeY; int y = p % _sizeY; _rowScanVector[p] = new PieceLocation( _boardEdges[x*numEdgesAtLine+y], _boardEdges[x*numEdgesAtLine+y+_sizeY+1], _boardEdges[x*numEdgesAtLine+numEdgesAtLine+y], _boardEdges[x*numEdgesAtLine+y+_sizeY], p); } } void createPieceRotations(int[] pieces, IntegerRef pos) { for (int i = 0; i < _numPieces; i++) { int a = pieces[pos.getValue()]; pos.plusplus(); int b = pieces[pos.getValue()]; pos.plusplus(); int c = pieces[pos.getValue()]; pos.plusplus(); int d = pieces[pos.getValue()]; pos.plusplus(); PieceRotation pieceRotation1 = new PieceRotation((a+1),(b+1),(c+1),(d+1),new BooleanRef(false)); PieceRotation pieceRotation2 = new PieceRotation((b+1),(c+1),(d+1),(a+1),pieceRotation1.isUsed); PieceRotation pieceRotation3 = new PieceRotation((c+1),(d+1),(a+1),(b+1),pieceRotation1.isUsed); PieceRotation pieceRotation4 = new PieceRotation((d+1),(a+1),(b+1),(c+1),pieceRotation1.isUsed); _allPieceRotations.add(pieceRotation1); _allPieceRotations.add(pieceRotation2); _allPieceRotations.add(pieceRotation3); _allPieceRotations.add(pieceRotation4); } } void readPieces(int[] pieces, int numRotations) { IntegerRef pos = new IntegerRef(); if (null!=pieces) { if (_useHints) readEdgesHint(pieces, pos); else readEdgesNoHint(pieces, pos); createSolutionVector(); createPieceRotations(pieces, pos); if (_useHints) setHintPieces(); //shuffleVector(_allPieceRotations); for (int i = 0; i < numRotations % 4; i++) rotateSolutionVector(); boolean isMirror = numRotations >= 4; if (isMirror) mirrorSolutionVector(); assignTypes(_rowScanVector); computePieceMatches(); } } void dumpMatches(PieceLocation nextPiece) { List matches = getMatches(nextPiece); System.out.print( String.format("\n%d Matches", matches.size()) ); for (PieceRotation p : matches) { System.out.print(String.format("\nMatch %d %d %d %d u=%d h=%d", p.top, p.right, p.bottom, p.left, p.isUsed(), p.type == HINT)); } System.out.print("\n"); System.out.flush(); } void solve() throws IOException { _hintStrategy = hintStrategy2(); // _hintStrategy = hintStrategy(); // _hintStrategy = simpleStrategy(); // _hintStrategy = lineScan(); // _hintStrategy = rowScan(); // _hintStrategy = Arrays.asList(_rowScanVector); setStartTime(); _maxDepth = 0; // solveTest(1); solve(1, 0); } void pieceToStrategy(List scanVector, IntegerRef svp, int x, int y, int dir) { if (!isUsed(x,y)) { int p = y + _sizeY*x; PieceLocation piece = _rowScanVector[p]; scanVector.add(svp.getValue(), (new PieceLocation(piece.top,piece.right,piece.bottom, piece.left, p))); scanVector.get(svp.getValue()).type = piece.type; scanVector.get(svp.getValue()).direction = dir; assignCheck(scanVector.get(svp.getValue()), p, x, y); svp.plusplus(); setUsed(x,y); } } List lineScan() { List scanVector = new ArrayList(_numPieces); IntegerRef svp = new IntegerRef(); for (int y = 0; y < _sizeY; y++) { for (int x = 0; x < _sizeX; x++) pieceToStrategy(scanVector, svp, x, y, TO_RIGHT_BOTTOM); } return scanVector; } List rowScan() { List scanVector = new ArrayList(_numPieces); IntegerRef svp = new IntegerRef(); for (int x = 0; x < _sizeX; x++) { for (int y = 0; y < _sizeY; y++) pieceToStrategy(scanVector, svp, x, y, TO_RIGHT_BOTTOM); } return scanVector; } List simpleStrategy() { List scanVector = new ArrayList(_numPieces); IntegerRef svp = new IntegerRef(); for (int d = 0; d < _sizeX; d++) { for (int x = 0; x < d; x++) pieceToStrategy(scanVector, svp, x, d, TO_RIGHT_BOTTOM); for (int y = 0; y <= d; y++) pieceToStrategy(scanVector, svp, d, y, TO_RIGHT_BOTTOM); } return scanVector; } void fillHints(List scanVector, IntegerRef svp) { for (int x = 0; x < _sizeX; x++) { for (int y = 0; y < _sizeY; y++) if (isHint(x,y)) pieceToStrategy(scanVector, svp, x, y, TO_RIGHT_BOTTOM); } } List hintStrategy() { List scanVector = new ArrayList(_numPieces); IntegerRef svp = new IntegerRef(); fillHints(scanVector, svp); for (int d = 0; d < _sizeX; d++) { if (isHint(d,d)) { for (int x = d-1; x >= 0; x--) pieceToStrategy(scanVector, svp, x, d, TO_TOP); for (int y = d-1; y >= 0; y--) pieceToStrategy(scanVector, svp, d, y, TO_LEFT); } else { for (int x = 0; x < d; x++) pieceToStrategy(scanVector, svp, x, d, TO_RIGHT_BOTTOM); for (int y = 0; y <= d; y++) pieceToStrategy(scanVector, svp, d, y, TO_RIGHT_BOTTOM); } } storeStrategy(scanVector); return scanVector; } List hintStrategy2() { List scanVector = new ArrayList(_numPieces); IntegerRef svp = new IntegerRef(); fillHints(scanVector, svp); for (int d = 0; d < _sizeX; d++) { if (d < _sizeX-2) { for (int i = 0; i < d; i++) { int x,y; if (isHint(i,d+2)) { for (x = 0; x <= i; x++) pieceToStrategy(scanVector, svp, x, d, TO_RIGHT_BOTTOM); pieceToStrategy(scanVector, svp, i+1, d, TO_ALL); pieceToStrategy(scanVector, svp, i, d+1, TO_ALL); for (x = i-1; x >= 0 ; x--) pieceToStrategy(scanVector, svp, x, d+1, TO_TOP); } if (isHint(d+2,i)) { for (y = 0; y <= i; y++) pieceToStrategy(scanVector, svp, d, y, TO_RIGHT_BOTTOM); pieceToStrategy(scanVector, svp, d, i+1, TO_ALL); pieceToStrategy(scanVector, svp, d+1, i, TO_ALL); for (y = i-1; y >= 0; y--) pieceToStrategy(scanVector, svp, d+1, y, TO_LEFT); } } } if (isHint(d,d)) { for (int x = d-1; x >= 0; x--) pieceToStrategy(scanVector, svp, x, d, TO_TOP); for (int y = d-1; y >= 0; y--) pieceToStrategy(scanVector, svp, d, y, TO_LEFT); } else { for (int x = 0; x < d; x++) pieceToStrategy(scanVector, svp, x, d, TO_RIGHT_BOTTOM); for (int y = 0; y <= d; y++) pieceToStrategy(scanVector, svp, d, y, TO_RIGHT_BOTTOM); } } storeStrategy(scanVector); return scanVector; } PieceLocation getPiece(int x, int y) { int p = y + _sizeY*x; return _rowScanVector[p]; } boolean isHint(int x, int y) { return getPiece(x,y).type == HINT; } boolean isUsed(int x, int y) { return getPiece(x,y).isUsed; } void setUsed(int x, int y) { getPiece(x,y).isUsed = true; } void doStatistics(PieceLocation nextPiece, int depth) { if( STATS ) { int x = nextPiece.pos / _sizeY; int y = nextPiece.pos % _sizeY; _nodeCounts[depth]++; _xyCount[x][y]++; _xPlaced[depth] = x; _yPlaced[depth] = y; } } void solve(int depth, int hintStrategyLoc) throws IOException { if (depth>_numPieces) { _numSolutions++; storeBoard(); if( DUMP_SOLUTION_FOUND ) { printStats(); } return; } if( DUMP_MIN_DEPTH ) { if (depth > _maxDepth) { _maxDepth = depth; System.out.print( String.format("\nSolver %d Max Depth = %d", _solverId, depth) ); printStats(); } } PieceLocation nextPiece = _hintStrategy.get(hintStrategyLoc); List matches = getMatchesFast(nextPiece); switch (nextPiece.direction) { case TO_RIGHT_BOTTOM: { int oldRight = nextPiece.right(); int oldBottom = nextPiece.bottom(); for (PieceRotation p : matches) { if (!p.isUsed()) { _numPiecesPlaced++; if (STATS) { doStatistics(nextPiece, depth); } nextPiece.setRight(p.right); nextPiece.setBottom(p.bottom); p.setUsed(true); solve(depth + 1, hintStrategyLoc + 1); p.setUsed(false); } if (STOP_AFTER_FIRST_CORNER_PIECE) { if (depth == 1) return; } } nextPiece.setRight(oldRight); nextPiece.setBottom(oldBottom); break; } case TO_LEFT: { int oldBottom = nextPiece.bottom(); int oldLeft = nextPiece.left(); for (PieceRotation p : matches) { if (!(p.isUsed())) { _numPiecesPlaced++; if (STATS) { doStatistics(nextPiece, depth); } nextPiece.setBottom(p.bottom); nextPiece.setLeft(p.left); p.setUsed(true); solve(depth + 1, hintStrategyLoc + 1); p.setUsed(false); } if (STOP_AFTER_FIRST_CORNER_PIECE) { if (depth == 1) return; } } nextPiece.setBottom(oldBottom); nextPiece.setLeft(oldLeft); break; } case TO_TOP: { int oldTop = nextPiece.top(); int oldRight = nextPiece.right(); for (PieceRotation p : matches) { if (!(p.isUsed())) { _numPiecesPlaced++; if (STATS) { doStatistics(nextPiece, depth); } nextPiece.setTop(p.top); nextPiece.setRight(p.right); p.setUsed(true); solve(depth + 1, hintStrategyLoc + 1); p.setUsed(false); } if (STOP_AFTER_FIRST_CORNER_PIECE) { if (depth == 1) return; } } nextPiece.setTop(oldTop); nextPiece.setRight(oldRight); break; } case TO_ALL: { int oldTop = nextPiece.top(); int oldRight = nextPiece.right(); int oldBottom = nextPiece.bottom(); int oldLeft = nextPiece.left(); for (PieceRotation p : matches) { if (!(p.isUsed())) { _numPiecesPlaced++; if (STATS) { doStatistics(nextPiece, depth); } nextPiece.setTop(p.top); nextPiece.setRight(p.right); nextPiece.setBottom(p.bottom); nextPiece.setLeft(p.left); p.setUsed(true); solve(depth + 1, hintStrategyLoc + 1); p.setUsed(false); } if (STOP_AFTER_FIRST_CORNER_PIECE) { if (depth == 1) return; } } nextPiece.setTop(oldTop); nextPiece.setRight(oldRight); nextPiece.setBottom(oldBottom); nextPiece.setLeft(oldLeft); break; } } } void solveTest(int depth) throws IOException { if( DUMP_MIN_DEPTH ) { if (depth > _maxDepth) { _maxDepth = depth; System.out.print( String.format("\nSolver %d Max Depth = %d", _solverId, depth)); printStats(); } } int pos = getNextPieceToAdvance(); PieceLocation nextPiece = _rowScanVector[pos]; List matches = getMatches(nextPiece); int oldLeft = nextPiece.left(); int oldTop = nextPiece.top(); int oldRight = nextPiece.right(); int oldBottom = nextPiece.bottom(); for (PieceRotation p : matches) { if (!(p.isUsed()) && p.type == nextPiece.type) { _numPiecesPlaced++; if (STATS) { int x = pos / _sizeY; int y = pos % _sizeY; _nodeCounts[depth]++; _xyCount[x][y]++; _xPlaced[depth] = x; _yPlaced[depth] = y; } if (depth == _numPieces) { _numSolutions++; storeBoard(); if (DUMP_SOLUTION_FOUND) { printStats(); } return; } else { nextPiece.setLeft(p.left); nextPiece.setTop(p.top); nextPiece.setRight(p.right); nextPiece.setBottom(p.bottom); p.setUsed(true); nextPiece.isUsed = true; solveTest(depth + 1); p.setUsed(false); nextPiece.isUsed = false; if (STOP_AFTER_FIRST_CORNER_PIECE) { if (!_useHints && depth == 1) return; } } } } nextPiece.setLeft(oldLeft); nextPiece.setTop(oldTop); nextPiece.setRight(oldRight); nextPiece.setBottom(oldBottom); } int computeMatchCount(PieceLocation piece, int x, int y) { //return getMatchCount(piece); int count = getMatchCount(piece); if (count == 0) return -(1<<24); else return count + _hintAdjustment[x][y]; } int getNextPieceToAdvance() { int bestP = 0; int bestCount = 1<<24; for (int x = 0; x < _sizeX; x++) { for (int y = 0; y < _sizeY; y++) { int p = y + _sizeY*x; PieceLocation piece = _rowScanVector[p]; if (!piece.isUsed) { int matchCount = computeMatchCount(piece, x, y); if (matchCount < bestCount) { bestCount = matchCount; bestP = p; } } } } // System.out.print( String.format("\n bestCount = %d bestP = %d",bestCount,bestP) ); // System.out.flush(); return bestP; } public static class IntegerRef { private int value; public IntegerRef() { this(0); } public IntegerRef(int value) { this.value = value; } public int plusplus() { return ++value; } public void setValue(int newValue) { value = newValue; } public int getValue() { return value; } public int hashCode() { return value; } public boolean equals(Object anObject) { IntegerRef integerRef = (IntegerRef) anObject; return this.value == integerRef.value; } public String toString() { return Integer.toString(value); } } public static class BooleanRef { private boolean value; public BooleanRef() { this(false); } public BooleanRef(boolean value) { this.value = value; } public void setValue(boolean newValue) { value = newValue; } public boolean getValue() { return value; } public int hashCode() { return value ? 1231 : 1237; } public boolean equals(Object anObject) { BooleanRef integerRef = (BooleanRef) anObject; return this.value == integerRef.value; } public String toString() { return Boolean.toString(value); } } }