diff --git a/kkanazawa/src/DonutsCounter.java b/kkanazawa/src/DonutsCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..b70357026fdae24210a9f033b646a68a654083c6 --- /dev/null +++ b/kkanazawa/src/DonutsCounter.java @@ -0,0 +1,142 @@ +package paiza.src; + +import java.util.Scanner; + +/** + * 二次元の入力に含まれているドーナツを検出し、その数を表示する. + * + * @author 金澤継心 + */ +public class DonutsCounter { + + /** + * 入力値の行数と列数を入力した後、入力値に含まれているドーナツを検出し、その数を表示する. + * + */ + public static void main(final String[] args) { + + DonutsFeature feature = new DonutsFeature(); // ドーナツを構成する要素のクラスオブジェクト + + Scanner sc = new Scanner(System.in); + final int lineAmount = sc.nextInt(); // 入力値の行の数 + final int columnAmount = sc.nextInt(); // 入力値の列の数 + String[] pictureRow = new String[lineAmount]; // 入力値を保存する配列 + + for (int i = 0; i < lineAmount; i++) { + pictureRow[i] = sc.next(); + } + sc.close(); + + System.out.println(returnDonutsAmount(lineAmount, columnAmount, pictureRow, feature)); + + } + + /** + * 受け取った配列に含まれているドーナツを検出し、その数を返す + * + * @param lineAmount 配列の要素数 二次元の行の数に相当 + * @param columnAmount 配列の要素一つあたりの文字数 二次元の列の数に相当 + * @param pictureRow 文字列の配列 + * @param ドーナツを構成する要素のクラスオブジェクト + */ + public static int returnDonutsAmount(final int lineAmount, final int columnAmount, + final String[] pictureRow, final DonutsFeature feature) { + + int donutsAmount = 0; // 検出したドーナツの数 + + // まず上の行から順にドーナツの構成要素1が含まれているか検索 + // ドーナツは3行必要なので、繰り返し数は(行の総数-2) + for (int i = 0; i < lineAmount - 2; i++) { + int searchIndex = 0;// これから検索する列の先頭インデックス + + // ドーナツは3列必要なので、(検索するインデックス+2)が列の総数を超えたらその行の検索終了 + while (columnAmount >= searchIndex + 2) { + // 構成要素1があるインデックスを返す + // 構成要素がなければ-1を返す + int featureIndex = pictureRow[i].indexOf(feature.getFeature1(), searchIndex); + + // 構成要素1が現在の行で見つからなければ次の行の検索に移行 + if (featureIndex == -1) { + break; + } + // 1つ下の行、または2つ下の行で構成要素が見られなかったら次の列からの検索に移行 + if (!isDetectionDonuts(i, pictureRow, featureIndex, feature)) { + searchIndex++; + continue; + } + // 全ての構成要素が見られた場合、ドーナツの検出としてカウント + donutsAmount++; + searchIndex = featureIndex + 1; + } + } + return donutsAmount; + } + + /** + * 1つ下の行で2列目の構成要素と合致、かつ2つ下の行での3列目の構成要素と合致」の真偽値を返す + * + * @param lineAmount 配列の要素数 二次元の行の数に相当 + * @param columnAmount 配列の要素一つあたりの文字数 二次元の列の数に相当 + * @param pictureRow 文字列の配列 + * @param ドーナツを構成する要素のクラスオブジェクト + */ + public static boolean isDetectionDonuts(final int lineIndex, final String[] pictureRow, + final int columnIndex, final DonutsFeature feature) { + // 1つ下の行のうち、構成要素1がヒットした列と同じ範囲の部分文字列を取得 + String secondLine = pictureRow[lineIndex + 1].substring(columnIndex, columnIndex + 3); + // 2つ下の行のうち、構成要素1がヒットした列と同じ範囲の部分文字列を取得 + String thirdLine = pictureRow[lineIndex + 2].substring(columnIndex, columnIndex + 3); + + return (feature.isFitFeature2(secondLine) && feature.isFitFeature3(thirdLine)); + } +} + + +/** + * ドーナツを構成する要素のクラス ドーナツの構成要素を3つの列に分けている. + * + * + */ +class DonutsFeature { + private String feature1 = "###"; // ドーナツの構成要素1列目 + private String feature2 = "#.#"; // ドーナツの構成要素2列目 + private String feature3 = "###"; // ドーナツの構成要素3列目 + + public String getFeature1() { + return feature1; + } + + public void setFeature1(final String feature1) { + this.feature1 = feature1; + } + + public String getFeature2() { + return feature2; + } + + public void setFeature2(final String feature2) { + this.feature2 = feature2; + } + + public String getFeature3() { + return feature3; + } + + public void setFeature3(final String feature3) { + this.feature3 = feature3; + } + + // 引数の文字列が構成要素と合致していればtrue, 合致していなければfalse + public boolean isFitFeature1(final String str) { + return str.equals(this.feature1); + } + + public boolean isFitFeature2(final String str) { + return str.equals(this.feature2); + } + + public boolean isFitFeature3(final String str) { + return str.equals(this.feature3); + } + +}