package backtracking; // résoudre le problème de Scott (pavage avec les pentaminos) // avec Dancing Links import java.util.HashSet; import java.util.LinkedList; import java.util.Set; // les 8 isométries du carré enum Iso { Id, Rot180, Hrefl, Vrefl, Rot90, Rot270, D1refl, D2refl } class Tile { final String name; final boolean[][] pattern; final int width, height; public Tile(String name, boolean[][] pattern) { super(); this.name = name; this.pattern = pattern; this.width = pattern.length; this.height = pattern[0].length; } @Override public boolean equals(Object obj) { Tile that = (Tile)obj; if (this.width != that.width || this.height != that.height) return false; for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) if (this.pattern[x][y] != that.pattern[x][y]) return false; return true ; } @Override public int hashCode() { int h = 31 * width + height; for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) h = 31 * h + (pattern[x][y] ? 17 : 42); return h; } Set<Tile> iso() { HashSet<Tile> s = new HashSet<>(); for (Iso iso: Iso.values()) { int w = width, h = height; switch (iso) { case Id: case Rot180: case Hrefl: case Vrefl: break; case Rot90: case Rot270: case D1refl: case D2refl: h = width; w = height; break; } boolean[][] pat = new boolean[w][h]; for (int x = 0; x < w; x++) for (int y = 0; y < h; y++) switch (iso) { case Id: pat[x][y] = pattern[x][y]; break; case Rot180: pat[x][y] = pattern[w-1-x][h-1-y]; break; case Hrefl: pat[x][y] = pattern[x][h-1-y]; break; case Vrefl: pat[x][y] = pattern[w-1-x][y]; break; case Rot90: pat[x][y] = pattern[h-1-y][x]; break; case Rot270: pat[x][y] = pattern[y][w-1-x]; break; case D1refl: pat[x][y] = pattern[y][x]; break; case D2refl: pat[x][y] = pattern[h-1-y][w-1-x]; break; } s.add(new Tile(name, pat)); } return s; } } public class ScottDLX { private DLXNode[][] grid = new DLXNode[8][8]; private final Tile[] tiles = new Tile[] { new Tile("I", new boolean[][] { { true ,true ,true ,true ,true } }), new Tile("V", new boolean[][] { { true ,true ,true }, { true ,false,false }, { true ,false,false } }), new Tile("Z", new boolean[][] { { false,true ,true }, { false,true ,false }, { true ,true ,false } }), new Tile("P", new boolean[][] { { true ,true ,true }, { true ,true ,false } }), new Tile("N", new boolean[][] { { true ,true ,true ,false }, { false,false,true ,true } }), new Tile("W", new boolean[][] { { false,true ,true }, { true ,true ,false }, { true ,false,false } }), new Tile("Y", new boolean[][] { { true ,true ,true ,true }, { false,true ,false,false } }), new Tile("T", new boolean[][] { { true ,true ,true }, { false,true ,false }, { false,true ,false } }), new Tile("F", new boolean[][] { { false,true ,true }, { true ,true ,false }, { false,true ,false } }), new Tile("U", new boolean[][] { { true ,true ,true }, { true ,false,true } }), new Tile("L", new boolean[][] { { true ,true ,true ,true }, { true ,false,false,false} }), new Tile("X", new boolean[][] { { false,true ,false }, { true ,true ,true }, { false,true ,false } }), }; private DLXNode[] col = new DLXNode[12]; ScottDLX() { LinkedList<DLXNode> cols = new LinkedList<>(); for (int i = 0; i < 12; i++) { DLXNode n = new DLXNode(tiles[i].name); cols.add(n); col[i] = n; } for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) { if ((i == 3 || i == 4) && (j == 3 || j == 4)) continue; cols.add(grid[i][j] = new DLXNode(i + ":" + j)); } System.out.println(cols.size() + " colonnes"); DancingLinks dl = new DancingLinks(cols); int rows = 0; for (int k = 0; k < 12; k++) { Tile t0 = tiles[k]; System.err.print("pièce " + t0.name + ": "); Set<Tile> s = t0.iso(); System.err.print(s.size() + " symétries"); DLXNode c = col[k]; int rows0 = rows; for (Tile t: s) { for (int i = 0; i < 8-t.width+1; i++) L:for (int j = 0; j < 8-t.height+1; j++) { LinkedList<DLXNode> row = new LinkedList<>(); row.add(c); for (int x = 0; x < t.width; x++) for (int y = 0; y < t.height; y++) if (t.pattern[x][y]) { if (grid[i+x][j+y] == null) continue L; row.add(grid[i+x][j+y]); } dl.addRow(row); rows++; } } System.err.println(", " + (rows - rows0) + " placements"); } System.out.println(rows + " lignes"); System.out.println(dl.count() + " solutions"); } public static void main(String[] args) { double start = System.currentTimeMillis(); new ScottDLX(); System.err.println((System.currentTimeMillis() - start)/1000 + " s"); } }