diff --git a/knoda/src/B066_ColorPuzzle.java b/knoda/src/B066_ColorPuzzle.java new file mode 100644 index 0000000000000000000000000000000000000000..4a0433b60a6a5f5a609ceb272345cf9db0ac2157 --- /dev/null +++ b/knoda/src/B066_ColorPuzzle.java @@ -0,0 +1,180 @@ +package hellojunit; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class B066_ColorPuzzle { + + public static void main(String[] args) { + final Scanner scan = new Scanner(System.in); + final int pieceNum = scan.nextInt(); + final int puzzleSize = scan.nextInt(); + final int pieceSize = scan.nextInt(); + + // パズルの完成形を入力する + final char[][] puzzle = new char[puzzleSize][puzzleSize]; + for (int i = 0; i < puzzleSize; i++) { + final String puzzleRow = scan.next(); + for (int j = 0; j < puzzleSize; j++) { + puzzle[i][j] = puzzleRow.charAt(j); + } + } + + // すべてのピースを入力する + final char[][][] pieceArray = new char[pieceNum][pieceSize][pieceSize]; + for (int pieceNo = 0; pieceNo < pieceNum; pieceNo++) { + for (int i = 0; i < pieceSize; i++) { + final String pieceRow = scan.next(); + for (int j = 0; j < pieceSize; j++) { + pieceArray[pieceNo][i][j] = pieceRow.charAt(j); + } + } + } + + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + // すべてのピースの配置情報を取得し、出力する + final List> pieceInfoList = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + for (final List pieceInfo : pieceInfoList) { + for (int i = 0; i < pieceInfo.size(); i++) { + if (i != pieceInfo.size() - 1) { + System.out.print(pieceInfo.get(i) + " "); + } else { + System.out.println(pieceInfo.get(i)); + } + } + } + scan.close(); + } +} + +class ColorPuzzle { + private final int pieceNum; + private final int puzzleSize; + private final int pieceSize; + private final int MAX_ANGLE_COUNT = 3; // ピースが回転する最大の数 + private final int NOT_MATCH = -1; // ピースがパズルの一部と等しくないときに返す値 + private final int NOT_FOUND = -1; // パズルに使用しないピースの情報 + + public ColorPuzzle(final int pieceNum, final int puzzleSize, final int pieceSize) { + this.pieceNum = pieceNum; + this.puzzleSize = puzzleSize; + this.pieceSize = pieceSize; + } + + /** + * すべてのピースの配置情報を取得するメソッド + * @param puzzle + * @param pieceArray + * @return pieceInfoList : すべてのピースの配置情報を格納したリスト + */ + public List> getPieceInfoList(final char[][] puzzle, final char[][][] pieceArray) { + List> pieceInfoList = new ArrayList>(); + for (int pieceNo = 0; pieceNo < pieceNum; pieceNo++) { + pieceInfoList = getFitPuzzle(puzzle, pieceArray, pieceNo, pieceInfoList); + } + return pieceInfoList; + } + + /** + * あるピースの配置情報を取得するメソッド + * @param puzzle + * @param pieceArray + * @param pieceNo : ピースの番号 + * @param pieceInfoList + * @return pieceInfoList + */ + private List> getFitPuzzle(final char[][] puzzle, final char[][][] pieceArray, + final int pieceNo, final List> pieceInfoList) { + boolean isFit = false; + final List pieceInfo = new ArrayList(); + for (int fitSpaceRow = 0; fitSpaceRow < puzzleSize / pieceSize; fitSpaceRow++) { + for (int fitSpaceColumn = 0; fitSpaceColumn < puzzleSize / pieceSize; fitSpaceColumn++) { + final char[][] piece = pieceArray[pieceNo]; + final int angleCount = getRotateCount(puzzle, piece, fitSpaceRow, fitSpaceColumn); + if (angleCount != NOT_MATCH) { + pieceInfo.add(fitSpaceRow * pieceSize + 1); // ピースの左上のマスのx座標 + pieceInfo.add(fitSpaceColumn * pieceSize + 1); // ピースの左上のマスのy座標 + pieceInfo.add(angleCount); // ピースを回転した回数 + pieceInfoList.add(pieceInfo); + isFit = true; + break; + } + } + if (isFit) { + break; + } + } + if (!isFit) { + pieceInfo.add(NOT_FOUND); // パズルに使用しないピースの情報 + pieceInfoList.add(pieceInfo); + } + return pieceInfoList; + } + + /** + * ピースが回転した回数を取得するメソッド + * @param puzzle + * @param piece + * @param fitSpaceRow : ピースを配置する大まかな場所(x座標) + * @param fitSpaceColumn : ピースを配置する大まかな場所(y座標) + * @return + */ + private int getRotateCount(final char[][] puzzle, char[][] piece, + final int fitSpaceRow, final int fitSpaceColumn) { + for (int count = 0; count <= MAX_ANGLE_COUNT; count++) { + if (isMatch(puzzle, piece, fitSpaceRow, fitSpaceColumn)) { + return count; + } else { + piece = getAfterRotatePiece(piece); + } + } + return NOT_MATCH; + } + + /** + * ピースがパズルの一部と等しいか判定するメソッド + * @param puzzle + * @param piece + * @param fitSpaceRow + * @param fitSpaceColumn + * @return 等しい : true, 等しくない : false + */ + private boolean isMatch(final char[][] puzzle, final char[][] piece, + final int fitSpaceRow, final int fitSpaceColumn) { + final char[][] targetPiece = new char[pieceSize][pieceSize]; + int m = 0; + for (int i = pieceSize * fitSpaceRow; i < pieceSize * fitSpaceRow + pieceSize; i++) { + int n = 0; + for (int j = pieceSize * fitSpaceColumn; j < pieceSize * fitSpaceColumn + pieceSize; j++) { + targetPiece[m][n] = puzzle[i][j]; + n++; + } + m++; + } + + for (int i = 0; i < pieceSize; i++) { + for (int j = 0; j < pieceSize; j++) { + if (targetPiece[i][j] != piece[i][j]) { + return false; + } + } + } + return true; + } + + /** + * ピースを時計回りに90°回転するメソッド + * @param piece + * @return afterRotatePiece : 回転後のピース + */ + private char[][] getAfterRotatePiece(final char[][] piece) { + final char[][] afterRotatePiece = new char[pieceSize][pieceSize]; + for (int i = 0; i < pieceSize; i++) { + for (int j = 0; j < pieceSize; j++) { + afterRotatePiece[i][j] = piece[pieceSize - 1 - j][i]; + } + } + return afterRotatePiece; + } +} diff --git a/knoda/test/B066_ColorPuzzleTest.java b/knoda/test/B066_ColorPuzzleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c233f87a879178a284946d6b87048c31d86f4666 --- /dev/null +++ b/knoda/test/B066_ColorPuzzleTest.java @@ -0,0 +1,289 @@ +package hellojunit; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +public class B066_ColorPuzzleTest { + + @Test + public void ピースが1つかつパズルのサイズが1x1かつピースのサイズが1x1のときにパズルが完成するテスト() { + final int pieceNum = 1; + final int puzzleSize = 1; + final int pieceSize = 1; + final char[][] puzzle = { + {'Y'} + }; + final char[][][] pieceArray = { + { + {'Y'} + } + }; + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + final List> actual = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + final List> expected = new ArrayList>(Arrays.asList( + new ArrayList(Arrays.asList(1, 1, 0)))); + assertThat(actual, is(expected)); + } + + @Test + public void ピースが1つかつパズルのサイズが1x1かつピースのサイズが1x1のときにパズルが完成しないテスト() { + final int pieceNum = 1; + final int puzzleSize = 1; + final int pieceSize = 1; + final char[][] puzzle = { + {'Y'} + }; + final char[][][] pieceArray = { + { + {'B'} + } + }; + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + final List> actual = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + final List> expected = new ArrayList>(Arrays.asList( + new ArrayList(Arrays.asList(-1)))); + assertThat(actual, is(expected)); + } + + @Test + public void ピースが1つかつパズルのサイズが100x100かつピースのサイズが100x100のときにパズルが完成するテスト() { + final int pieceNum = 1; + final int puzzleSize = 100; + final int pieceSize = 100; + final char[][] puzzle = new char[puzzleSize][puzzleSize]; + final char[][][] pieceArray = new char[pieceNum][pieceSize][pieceSize]; + + for (int i = 0; i < puzzleSize; i++) { + for (int j = 0; j < puzzleSize; j++) { + if (j < 50) { + puzzle[i][j] = 'Y'; + } else { + puzzle[i][j] = 'B'; + } + } + } + + for (int pieceNo = 0; pieceNo < pieceNum; pieceNo++) { + for (int i = 0; i < pieceSize; i++) { + for (int j = 0; j < pieceSize; j++) { + if (j < 50) { + pieceArray[pieceNo][i][j] = 'B'; + } else { + pieceArray[pieceNo][i][j] = 'Y'; + } + } + } + } + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + final List> actual = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + final List> expected = new ArrayList>(Arrays.asList( + new ArrayList(Arrays.asList(1, 1, 2)))); + assertThat(actual, is(expected)); + } + + @Test + public void ピースが1つかつパズルのサイズが100x100かつピースのサイズが100x100のときにパズルが完成しないテスト() { + final int pieceNum = 1; + final int puzzleSize = 100; + final int pieceSize = 100; + final char[][] puzzle = new char[puzzleSize][puzzleSize]; + final char[][][] pieceArray = new char[pieceNum][pieceSize][pieceSize]; + + for (int i = 0; i < puzzleSize; i++) { + for (int j = 0; j < puzzleSize; j++) { + if (j < 50) { + puzzle[i][j] = 'Y'; + } else { + puzzle[i][j] = 'B'; + } + } + } + + for (int pieceNo = 0; pieceNo < pieceNum; pieceNo++) { + for (int i = 0; i < pieceSize; i++) { + for (int j = 0; j < pieceSize; j++) { + pieceArray[pieceNo][i][j] = 'B'; + } + } + } + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + final List> actual = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + final List> expected = new ArrayList>(Arrays.asList( + new ArrayList(Arrays.asList(-1)))); + assertThat(actual, is(expected)); + } + + @Test + public void ピースが100かつパズルのサイズが100x100かつピースのサイズが100x100のときのテスト() { + final int pieceNum = 100; + final int puzzleSize = 100; + final int pieceSize = 100; + final char[][] puzzle = new char[puzzleSize][puzzleSize]; + final char[][][] pieceArray = new char[pieceNum][pieceSize][pieceSize]; + + for (int i = 0; i < puzzleSize; i++) { + for (int j = 0; j < puzzleSize; j++) { + if (i == 0 && j == puzzleSize - 1) { + puzzle[i][j] = 'Y'; + } else { + puzzle[i][j] = 'B'; + } + } + } + + for (int pieceNo = 0; pieceNo < pieceNum; pieceNo++) { + for (int i = 0; i < pieceSize; i++) { + for (int j = 0; j < pieceSize; j++) { + if (i == 0 && j == pieceNo) { + pieceArray[pieceNo][i][j] = 'Y'; + } else { + pieceArray[pieceNo][i][j] = 'B'; + } + } + } + } + + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + final List> actual = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + final List> expected = new ArrayList>(); + for (int pieceNo = 0; pieceNo < pieceNum; pieceNo++) { + if (pieceNo == 0) { + expected.add(new ArrayList(Arrays.asList(1, 1, 1))); + } else if (pieceNo == pieceNum - 1) { + expected.add(new ArrayList(Arrays.asList(1, 1, 0))); + } else { + expected.add(new ArrayList(Arrays.asList(-1))); + } + } + assertThat(actual, is(expected)); + } + + @Test + public void 基本テスト1() { + final int pieceNum = 4; + final int puzzleSize = 4; + final int pieceSize = 2; + final char[][] puzzle = { + {'Y', 'B', 'B', 'Y'}, + {'Y', 'Y', 'Y', 'B'}, + {'B', 'B', 'Y', 'B'}, + {'Y', 'B', 'Y', 'B'} + }; + final char[][][] pieceArray = { + { + {'B', 'Y'}, + {'B', 'B'} + }, + { + {'Y', 'B'}, + {'Y', 'B'} + }, + { + {'Y', 'B'}, + {'Y', 'Y'} + }, + { + {'B', 'Y'}, + {'Y', 'B'} + } + }; + + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + final List> actual = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + final List> expected = new ArrayList>(Arrays.asList( + new ArrayList(Arrays.asList(3, 1, 2)), + new ArrayList(Arrays.asList(3, 3, 0)), + new ArrayList(Arrays.asList(1, 1, 0)), + new ArrayList(Arrays.asList(1, 3, 0)))); + assertThat(actual, is(expected)); + } + + @Test + public void 基本テスト2() { + final int pieceNum = 10; + final int puzzleSize = 6; + final int pieceSize = 3; + final char[][] puzzle = { + {'Y', 'Y', 'Y', 'B', 'Y', 'B'}, + {'B', 'Y', 'Y', 'B', 'B', 'B'}, + {'B', 'Y', 'Y', 'B', 'B', 'B'}, + {'B', 'Y', 'Y', 'B', 'Y', 'B'}, + {'B', 'B', 'Y', 'Y', 'Y', 'Y'}, + {'Y', 'Y', 'Y', 'Y', 'Y', 'B'} + }; + final char[][][] pieceArray = { + { + {'Y', 'Y', 'B'}, + {'B', 'B', 'Y'}, + {'B', 'Y', 'B'} + }, + { + {'B', 'B', 'Y'}, + {'Y', 'B', 'B'}, + {'B', 'Y', 'B'} + }, + { + {'B', 'B', 'Y'}, + {'Y', 'B', 'B'}, + {'Y', 'Y', 'B'} + }, + { + {'B', 'B', 'B'}, + {'B', 'B', 'B'}, + {'B', 'Y', 'B'} + }, + { + {'B', 'Y', 'B'}, + {'B', 'Y', 'B'}, + {'Y', 'Y', 'B'} + }, + { + {'Y', 'Y', 'Y'}, + {'Y', 'Y', 'Y'}, + {'Y', 'B', 'Y'} + }, + { + {'Y', 'Y', 'Y'}, + {'Y', 'B', 'B'}, + {'Y', 'Y', 'B'} + }, + { + {'Y', 'Y', 'B'}, + {'Y', 'Y', 'B'}, + {'Y', 'Y', 'Y'} + }, + { + {'Y', 'Y', 'B'}, + {'Y', 'Y', 'Y'}, + {'B', 'Y', 'B'} + }, + { + {'B', 'B', 'B'}, + {'Y', 'Y', 'B'}, + {'B', 'Y', 'Y'} + } + }; + + final ColorPuzzle colorPuzzle = new ColorPuzzle(pieceNum, puzzleSize, pieceSize); + final List> actual = colorPuzzle.getPieceInfoList(puzzle, pieceArray); + final List> expected = new ArrayList>(Arrays.asList( + new ArrayList(Arrays.asList(-1)), + new ArrayList(Arrays.asList(-1)), + new ArrayList(Arrays.asList(-1)), + new ArrayList(Arrays.asList(1, 4, 2)), + new ArrayList(Arrays.asList(-1)), + new ArrayList(Arrays.asList(-1)), + new ArrayList(Arrays.asList(4, 1, 2)), + new ArrayList(Arrays.asList(1, 1, 2)), + new ArrayList(Arrays.asList(4, 4, 3)), + new ArrayList(Arrays.asList(-1)))); + assertThat(actual, is(expected)); + } + +}