diff --git a/kkanazawa/src/Katori.java b/kkanazawa/src/Katori.java new file mode 100644 index 0000000000000000000000000000000000000000..1f79e59222ba9ad729da3888313930d0e95135e2 --- /dev/null +++ b/kkanazawa/src/Katori.java @@ -0,0 +1,261 @@ +package paiza.src; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +/** + * + * + */ +public class Katori { + + public static void main(final String[] args) { + Scanner scanner = new Scanner(System.in); + final int sideLength = scanner.nextInt(); // 入力値の行,列の数 + + // もととなる二次元配列を入力から受け取る + final int[][] coil = KatoriIO.inputCoil(scanner, sideLength); + scanner.close(); + + // 入力値の二次元配列の周りを-1で埋める + final int[][] paddedCoil = CalcKatori.paddingCoil(coil, sideLength); + + // 二次元配列を渦巻き状に読み取り一次元リストに保存 + final List decodedKatori = CalcKatori.decodeKatori(sideLength, paddedCoil); + + // 渦巻き状に読み取ったリストから1/4, 2/4, 3/4, すべて燃えきる,までにかかる時間を計算 + final List fourTimes = CalcKatori.getQuartileSums(decodedKatori); + + // 計算結果の表示 + KatoriIO.outputTimes(fourTimes); + } + +} + + +/** + * 入出力を行うクラス + * + */ +final class KatoriIO { + /** + * 蚊取り線香のブロックごとに燃える時間を二次元配列として入力する + * + * @param scanner + * @param sideLength 文字リストの行数、列数 + */ + public static int[][] inputCoil(final Scanner scanner, final int sideLength) { + int[][] coil = new int[sideLength][sideLength]; + for (int row = 0; row < sideLength; row++) { + for (int column = 0; column < sideLength; column++) { + coil[row][column] = scanner.nextInt(); + } + } + return coil; + } + + /** + * 蚊取り線香が1/4, 2/4, 3/4, すべて燃えきる,までにかかる時間を表示する + * + */ + public static void outputTimes(List fourTimes) { + for (Integer time : fourTimes) { + System.out.println(time); + } + + } +} + + +final class CalcKatori { + // 二次元配列を囲う値 + final static int BARRIER_NUM = -1; + + /** + * 二次元配列の周りを"-1"で埋める + * + * @param originCipher もととなる文字リスト + */ + public static int[][] paddingCoil(final int[][] originCoil, final int sideLength) { + + int[][] paddedCoil = new int[sideLength + 2][sideLength + 2]; + + for (int[] o : paddedCoil) { + Arrays.fill(o, BARRIER_NUM); + } + // 元リストを"-1"しかない文字リストの中央にコピーする + for (int row = 0; row < sideLength; row++) { + System.arraycopy(originCoil[row], 0, paddedCoil[row + 1], 1, sideLength); + } + return paddedCoil; + } + + /** + * 周りを"-1"で埋めた文字リストの解読 "-1"にぶつかったら方向転換するイメージでうずまき状に要素を移動する 移動した順に二次元配列の要素を1次元の別のリストに移していく + * 読み取った二次元配列の要素は"-1"に置き換える + * + * @param sideLength 文字列リストの行数、列数 + * @param coil 二次元配列 + */ + public static List decodeKatori(final int sideLength, final int[][] coil) { + + // "-1"でかこっているため、始まりのインデックスは行、列ともに1から + var pointer = new IndexPointer(1, 1, Direction.RIGHT); + + // 現在移し終えた要素のカウンタ + int brockCounter = 0; + // この配列に要素を移して最終的にはうずまきの順番に値が並ぶ + List brockTimes = new ArrayList<>(); + + // 初期位置から初めて-1にぶつかるまでの解読処理 + while (coil[pointer.getRowIndex()][pointer.getColumnIndex()] != BARRIER_NUM) { + brockTimes.add(coil[pointer.getRowIndex()][pointer.getColumnIndex()]); + coil[pointer.getRowIndex()][pointer.getColumnIndex()] = BARRIER_NUM; + brockCounter++; + pointer.getDirection().shift(pointer); + } + + // 初めて-1にぶつかってから解読し終わるまでの処理 + while (brockCounter < sideLength * sideLength) { + // -1の要素に移動した際、カーソルの位置を戻す処理 + pointer.getDirection().modify(pointer); + // -1にぶつかるまで一方向に要素を読み取り続ける + while (coil[pointer.getRowIndex()][pointer.getColumnIndex()] != BARRIER_NUM) { + brockTimes.add(coil[pointer.getRowIndex()][pointer.getColumnIndex()]); + coil[pointer.getRowIndex()][pointer.getColumnIndex()] = BARRIER_NUM; + brockCounter++; + // カーソルを現在進んでいる方向に移動させる + pointer.getDirection().shift(pointer); + } + } + + return brockTimes; + + } + + + // 読み取った値を全体の四分位ごとに和をとり、リストに格納 + public static List getQuartileSums(List brockTimes) { + List fourTimes = new ArrayList<>(); + fourTimes.add(brockTimes.subList(0, brockTimes.size() / 4).stream().reduce(Integer::sum).get()); + fourTimes.add(brockTimes.subList(0, brockTimes.size() / 2).stream().reduce(Integer::sum).get()); + fourTimes + .add(brockTimes.subList(0, brockTimes.size() * 3 / 4).stream().reduce(Integer::sum).get()); + fourTimes.add(brockTimes.subList(0, brockTimes.size()).stream().reduce(Integer::sum).get()); + return fourTimes; + } +} + + +/** + * 要素を読み取る方向 + */ +enum Direction { + // modify + // -1の要素に移動した際、カーソルの位置を戻す処理 + // 時計周りに移動方向を変える + + //shift + // カーソルを現在進む方向に移動させる + RIGHT { + @Override + void shift(IndexPointer pointer) { + pointer.setColumnIndex(pointer.getColumnIndex() + 1); + } + + @Override + void modify(IndexPointer pointer) { + pointer.setRowIndex(pointer.getRowIndex() + 1); + pointer.setColumnIndex(pointer.getColumnIndex() - 1); + pointer.setDirection(Direction.DOWN); + } + }, + DOWN { + @Override + void shift(IndexPointer pointer) { + pointer.setRowIndex(pointer.getRowIndex() + 1); + } + + @Override + void modify(IndexPointer pointer) { + pointer.setRowIndex(pointer.getRowIndex() - 1); + pointer.setColumnIndex(pointer.getColumnIndex() - 1); + pointer.setDirection(Direction.LEFT); + } + }, + LEFT { + @Override + void shift(IndexPointer pointer) { + pointer.setColumnIndex(pointer.getColumnIndex() - 1); + } + + @Override + void modify(IndexPointer pointer) { + pointer.setRowIndex(pointer.getRowIndex() - 1); + pointer.setColumnIndex(pointer.getColumnIndex() + 1); + pointer.setDirection(Direction.UP); + } + }, + UP { + @Override + void shift(IndexPointer pointer) { + pointer.setRowIndex(pointer.getRowIndex() - 1); + } + + @Override + void modify(IndexPointer pointer) { + pointer.setRowIndex(pointer.getRowIndex() + 1); + pointer.setColumnIndex(pointer.getColumnIndex() + 1); + pointer.setDirection(Direction.RIGHT); + } + }; + + abstract void shift(IndexPointer pointer); + + abstract void modify(IndexPointer pointer); +} + + +/** + * 現在読み取っている位置を示すポインターのクラス + * + */ +final class IndexPointer { + + private int rowIndex;// 現在の行の位置 + private int columnIndex;// 現在の列の位置 + private Direction direction; + + public IndexPointer(final int rowIndex, final int columnIndex, final Direction direction) { + this.rowIndex = rowIndex; + this.columnIndex = columnIndex; + this.direction = direction; + } + + public Direction getDirection() { + return direction; + } + + public int getRowIndex() { + return rowIndex; + } + + public int getColumnIndex() { + return columnIndex; + } + + public void setRowIndex(final int rowIndex) { + this.rowIndex = rowIndex; + } + + public void setColumnIndex(final int columnIndex) { + this.columnIndex = columnIndex; + } + + public void setDirection(final Direction direction) { + this.direction = direction; + } + +} diff --git a/kkanazawa/test/KatoriTest.java b/kkanazawa/test/KatoriTest.java new file mode 100644 index 0000000000000000000000000000000000000000..48ae7c6d2b47b9f413ae707c6508a16990198640 --- /dev/null +++ b/kkanazawa/test/KatoriTest.java @@ -0,0 +1,216 @@ +package paiza.src; + +import static org.junit.Assert.*; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import org.junit.Before; +import org.junit.Test; + +public class KatoriTest { + + //二次元配列の周りを囲う値 + final static int BARRIER_NUM = -1; + //二次元配列の行数、列数 + final static int SIDE_LENGTH = 4; + + public static class KatoriIOTest { + + + @Test + public void OutputTimesに12_39_57_82_を格納したリストを渡すと各要素が改行を入れて出力される() { + String expected = 12 + + System.lineSeparator() + + + 39 + + System.lineSeparator() + + + 57 + + System.lineSeparator() + + + 82 + +System.lineSeparator(); + + List fourTimes = new ArrayList<>(); + fourTimes.add(12); + fourTimes.add(39); + fourTimes.add(57); + fourTimes.add(82); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + System.setOut(new PrintStream(out)); + KatoriIO.outputTimes(fourTimes); + + assertEquals(expected,out.toString()); + } + } + + public static class CalckatoriTest { + int[][] coil; + int[][] paddingCoil; + List decodedKatori; + List times; + + @Before + public void setUp() { + coil = new int[][] { + { + 3, 4, 3, 2 + }, { + 7, 9, 3, 7 + }, { + 1, 9, 4, 6 + }, { + 3, 7, 8, 6 + } + }; + + paddingCoil = new int[][] { + { + -1, -1, -1, -1, -1, -1 + }, { + -1, 3, 4, 3, 2, -1 + }, { + -1, 7, 9, 3, 7, -1 + }, { + -1, 1, 9, 4, 6, -1 + }, { + -1, 3, 7, 8, 6, -1 + }, { + -1, -1, -1, -1, -1, -1 + } + }; + + decodedKatori = new ArrayList<>(); + decodedKatori.add(3); + decodedKatori.add(4); + decodedKatori.add(3); + decodedKatori.add(2); + decodedKatori.add(7); + decodedKatori.add(6); + decodedKatori.add(6); + decodedKatori.add(8); + decodedKatori.add(7); + decodedKatori.add(3); + decodedKatori.add(1); + decodedKatori.add(7); + decodedKatori.add(9); + decodedKatori.add(3); + decodedKatori.add(4); + decodedKatori.add(9); + + times = new ArrayList<>(); + times.add(12); + times.add(39); + times.add(57); + times.add(82); + } + + + + @Test + public void PaddingCoilに4行4列の二次元配列coilを渡すとその二次元配列の周りをBARRIER_NUMで囲った二次元配列を返す() { + int[][] result = CalcKatori.paddingCoil(coil, SIDE_LENGTH); + for (int row = 0; row < SIDE_LENGTH + 2; row++) { + for (int column = 0; column < SIDE_LENGTH + 2; column++) { + assertEquals(paddingCoil[row][column], result[row][column]); + } + } + } + + @Test + public void decodedKatoriに二次元配列paddingCoilを渡すとうずまき状に要素を読み取ったリスト返す() { + List result = CalcKatori.decodeKatori(SIDE_LENGTH, paddingCoil); + assertEquals(decodedKatori, result); + } + + @Test + public void getQuartileSumsに1次元リストdecodedKatoriを渡すと四分位ごとに和をとった値のリストを返す() { + List result = CalcKatori.getQuartileSums(decodedKatori); + assertEquals(times, result); + } + + + //modifyingのテスト + @Test + public void modifyにDOWN_行1_列5をコンストラクタ設定したIndexPointerを渡すとLEFT_行0_列4に変更する() { + IndexPointer actual = new IndexPointer(1, 5, Direction.DOWN); + IndexPointer expect = new IndexPointer(0, 4, Direction.LEFT); + actual.getDirection().modify(actual); + assertEquals(expect.getRowIndex(), actual.getRowIndex()); + assertEquals(expect.getColumnIndex(), actual.getColumnIndex()); + assertEquals(expect.getDirection(), actual.getDirection()); + } + @Test + public void modifyにLEFT_行1_列5をコンストラクタ設定したIndexPointerを渡すとUP_行0_列6に変更する() { + IndexPointer actual = new IndexPointer(1, 5, Direction.LEFT); + IndexPointer expect = new IndexPointer(0, 6, Direction.UP); + actual.getDirection().modify(actual); + assertEquals(expect.getRowIndex(), actual.getRowIndex()); + assertEquals(expect.getColumnIndex(), actual.getColumnIndex()); + assertEquals(expect.getDirection(), actual.getDirection()); + } + @Test + public void modifyにUP_行1_列5をコンストラクタ設定したIndexPointerを渡すとRIGHT_行2_列6に変更する() { + IndexPointer actual = new IndexPointer(1, 5, Direction.UP); + IndexPointer expect = new IndexPointer(2, 6, Direction.RIGHT); + actual.getDirection().modify(actual); + assertEquals(expect.getRowIndex(), actual.getRowIndex()); + assertEquals(expect.getColumnIndex(), actual.getColumnIndex()); + assertEquals(expect.getDirection(), actual.getDirection()); + } + + + //shiftingのテスト + @Test + public void shiftにRIGHT_行1_列5をコンストラクタ設定したIndexPointerを渡すとRIGHT_行1_列6に変更する() { + IndexPointer actual = new IndexPointer(1, 5, Direction.RIGHT); + IndexPointer expect = new IndexPointer(1, 6, Direction.RIGHT); + actual.getDirection().shift(actual); + assertEquals(expect.getRowIndex(), actual.getRowIndex()); + assertEquals(expect.getColumnIndex(), actual.getColumnIndex()); + assertEquals(expect.getDirection(), actual.getDirection()); + } + @Test + public void shiftigにDOWN_行1_列5をコンストラクタ設定したIndexPointerを渡すとDOWN_行2_列5に変更する() { + IndexPointer actual = new IndexPointer(1, 5, Direction.DOWN); + IndexPointer expect = new IndexPointer(2, 5, Direction.DOWN); + actual.getDirection().shift(actual); + assertEquals(expect.getRowIndex(), actual.getRowIndex()); + assertEquals(expect.getColumnIndex(), actual.getColumnIndex()); + assertEquals(expect.getDirection(), actual.getDirection()); + } + @Test + public void shiftigにLEFT_行1_列5をコンストラクタ設定したIndexPointerを渡すとLEFT_行1_列4に変更する() { + IndexPointer actual = new IndexPointer(1, 5, Direction.LEFT); + IndexPointer expect = new IndexPointer(1, 4, Direction.LEFT); + actual.getDirection().shift(actual); + assertEquals(expect.getRowIndex(), actual.getRowIndex()); + assertEquals(expect.getColumnIndex(), actual.getColumnIndex()); + assertEquals(expect.getDirection(), actual.getDirection()); + } + @Test + public void shiftigにUP_行1_列5をコンストラクタ設定したIndexPointerを渡すとUP_行0_列5に変更する() { + IndexPointer actual = new IndexPointer(1, 5, Direction.UP); + IndexPointer expect = new IndexPointer(0, 5, Direction.UP); + actual.getDirection().shift(actual); + assertEquals(expect.getRowIndex(), actual.getRowIndex()); + assertEquals(expect.getColumnIndex(), actual.getColumnIndex()); + assertEquals(expect.getDirection(), actual.getDirection()); + } + } + + public static class IndexPointerTest { + + @Test + public void コンストラクタで設定した値がゲッターで取得できる() { + IndexPointer pointer = new IndexPointer(1, 5, Direction.RIGHT); + assertEquals(1, pointer.getRowIndex()); + assertEquals(5, pointer.getColumnIndex()); + assertEquals(Direction.RIGHT, pointer.getDirection()); + + } + + + } +}