import java.awt.Point; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; public final class Dominos { public static void main(String[] args) { List.of( tableauOne, tableauTwo ).forEach( tableau -> { List patterns = findPatterns(tableau); System.out.println("Layouts found: " + patterns.size() + System.lineSeparator()); printLayout(patterns.getFirst()); } ); } private static List findPatterns(int[][] tableau) { final int nRows = tableau.length; final int nCols = tableau[0].length; final int dominoCount = ( nRows * nCols ) / 2; int[][] emptyTableau = IntStream.range(0, nRows) .mapToObj( i -> IntStream.range(0, nCols).map( j -> EMPTY ).toArray() ).toArray(int[][]::new); List patterns = new ArrayList(); patterns.addLast( new Pattern(emptyTableau, new ArrayList(), new ArrayList()) ); while ( true ) { List nextPatterns = new ArrayList(); for ( Pattern pattern : patterns ) { int[][] nextTableau = pattern.tableau; List dominoes = pattern.dominoes; List points = pattern.points; final int index = IntStream.range(0, nRows * nCols) .filter( i -> nextTableau[i / nCols][i % nCols] == EMPTY ).findFirst().orElse(EMPTY); if ( index == EMPTY ) { continue; } int row = index / nCols; int col = index % nCols; if ( row + 1 < nRows && nextTableau[row + 1][col] == EMPTY ) { Domino domino = new Domino(tableau[row][col], tableau[row + 1][col]); if ( ! dominoes.contains(domino) ) { int[][] finalTableau = new int[nextTableau.length][]; for ( int i = 0; i < nextTableau.length; i++ ) { finalTableau[i] = new int[nextTableau[i].length]; System.arraycopy(nextTableau[i], 0, finalTableau[i], 0, nextTableau[i].length); } finalTableau[row][col] = tableau[row][col]; finalTableau[row + 1][col] = tableau[row + 1][col]; List nextDominoes = new ArrayList(dominoes); nextDominoes.addLast(domino); List nextPoints = new ArrayList(points); nextPoints.addAll(List.of( new Point(row, col), new Point(row + 1, col) )); nextPatterns.addLast( new Pattern(finalTableau, nextDominoes, nextPoints) ); } } if ( col + 1 < nCols && nextTableau[row][col + 1] == EMPTY ) { Domino domino = new Domino(tableau[row][col], tableau[row][col + 1]); if ( ! dominoes.contains(domino) ) { nextTableau[row][col] = tableau[row][col]; nextTableau[row][col + 1] = tableau[row][col + 1]; dominoes.add(domino); points.addAll(List.of( new Point(row, col), new Point(row, col + 1) )); nextPatterns.addLast( new Pattern(nextTableau, dominoes, points) ); } } } if ( nextPatterns.isEmpty() ) { break; } patterns = nextPatterns; if ( patterns.getFirst().dominoes.size() == dominoCount ) { break; } } return patterns; } private static void printLayout(Pattern pattern) { List> output = IntStream.range(0, 2 * pattern.tableau.length) .mapToObj( i -> new ArrayList(Collections.nCopies(2 * pattern.tableau[0].length - 1, " ")) ) .collect(Collectors.toList()); for ( int i = 0; i < pattern.points.size() - 1; i += 2 ) { final int x1 = pattern.points.get(i).x; final int y1 = pattern.points.get(i).y; final int x2 = pattern.points.get(i + 1).x; final int y2 = pattern.points.get(i + 1).y; final int n1 = pattern.tableau[x1][y1]; final int n2 = pattern.tableau[x2][y2]; output.get(2 * x1).set(2 * y1, String.valueOf(n1)); output.get(2 * x2).set(2 * y2, String.valueOf(n2)); if ( x1 == x2 ) { output.get(2 * x1).set(2 * y1 + 1, "+"); } else if ( y1 == y2 ) { output.get(2 * x1 + 1).set(2 * y1, "+"); } } output.forEach( i -> System.out.println(i.stream().collect(Collectors.joining())) ); } private static class Domino { public Domino(int aOne, int aTwo) { one = Math.min(aOne, aTwo); two = Math.max(aOne, aTwo); } @Override public int hashCode() { return 2 * one + 3 * two; } @Override public boolean equals(Object other) { return switch ( other ) { case Domino domino -> one == domino.one && two == domino.two; case Object object -> false; }; } private int one, two; } private static final int EMPTY = -1; private static record Pattern(int[][] tableau, List dominoes, List points) {} private static final int[][] tableauOne = { { 0, 5, 1, 3, 2, 2, 3, 1 }, { 0, 5, 5, 0, 5, 2, 4, 6 }, { 4, 3, 0, 3, 6, 6, 2, 0 }, { 0, 6, 2, 3, 5, 1, 2, 6 }, { 1, 1, 3, 0, 0, 2, 4, 5 }, { 2, 1, 4, 3, 3, 4, 6, 6 }, { 6, 4, 5, 1, 5, 4, 1, 4 } }; private static final int[][] tableauTwo = { { 6, 4, 2, 2, 0, 6, 5, 0 }, { 1, 6, 2, 3, 4, 1, 4, 3 }, { 2, 1, 0, 2, 3, 5, 5, 1 }, { 1, 3, 5, 0, 5, 6, 1, 0 }, { 4, 2, 6, 0, 4, 0, 1, 1 }, { 4, 4, 2, 0, 5, 3, 6, 3 }, { 6, 6, 5, 2, 5, 3, 3, 4 } }; }