ガジェット通信

見たことのないものを見に行こう

【自動採点】怪盗JAVAンの挑戦~盗まれたコードを取り戻せ【コード穴埋め】解答と解説

DATE:
  • ガジェット通信を≫

怪盗JAVAンの挑戦~盗まれたコードを取り戻せ

本問題は、穴空きコードの、【1】【2】の部分を補完するというものでした。

それでは以下、問題とその解答を見ていきましょう。

問題のオープニング

ちまたを騒がせる怪盗Javaンが、あなたの街に現れた!

怪盗Javaンは、Javaで書かれたコードから、特定の文字列を盗んで去って行く。

あなたはコード探偵として、盗まれたコードを推理して取り返すのだ!

怪盗Javaン「我が名は、怪盗アルセーヌ・JAVAン。ふはははは、今回は2つも文字列を盗んだぞ。盗んだ部分は【1】【2】のようになっていて、同じ数字の場所は同じ文字列を指しているぞ!」

富豪「盗まれたコードは、世にも珍しいフラクタル図形の模様を生成する宝石コードです。過去に撮影した出力結果を、推理の参考にしてください。」

コード探偵「ふむふむ。そうか! 盗まれたコードは、○○と△△だ!」

出力結果

import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
public static void main(String[] args) {
int n = 3, w = 80, h = 40;
List lst = new ArrayList();
lst.add(new Rectangle(0, 0, w, h));
// n回、図形を展開する
IntStream.【1】(0, n).【2】(i ->
IntStream.【1】(0, lst.size()).【2】(j -> {
lst.addAll(getGrph(lst.get(0)));
lst.remove(0);
})
);
System.out.println(toAA(w, h, lst));
}
// 図形取得
public static List getGrph(Rectangle r) {
List lst = new ArrayList();
IntStream.【1】(0, 4).【2】(i ->
lst.add(new Rectangle(
r.x + i % 2 * r.width * 3 / 5,
r.y + i / 2 * r.height * 3 / 5,
r.width – r.width * 3 / 5,
r.height – r.height * 3 / 5
))
);
return lst;
}
// アスキーアート化
public static String toAA(int w, int h, List lst) {
int[] arr = new int[w * h];
// 図形の内部を1で埋める
lst.【2】(r ->
IntStream.【1】(r.y, r.y + r.height).【2】(y ->
IntStream.【1】(r.x, r.x + r.width).【2】(x ->
arr[x + y * w] = 1
)
)
);
// 文字列化
String res = Arrays.stream(arr)
.mapToObj(String::valueOf)
.collect(Collectors.joining())
.replaceAll(“(.{” + w + “})”, “$1n”);
return res;
}
}

解答

それでは【1】【2】の答えを示して、解説をしていきます。

【1】range
【2】forEach

今回の問題は、Java8風にプログラムを書けるかというものです。ここでは、Stream APIを使えるかを尋ねています。

答えが入る部分が何度も出てきますが、その中から典型的な部分を抜き出してみます。

// n回、図形を展開する
IntStream.【1】(0, n).【2】(i ->
IntStream.【1】(0, lst.size()).【2】(j -> {
lst.addAll(getGrph(lst.get(0)));
lst.remove(0);
})
);

【1】【2】の答えを当てはめると、以下のようになります。

// n回、図形を展開する
IntStream.range(0, n).forEach(i ->
IntStream.range(0, lst.size()).forEach(j -> {
lst.addAll(getGrph(lst.get(0)));
lst.remove(0);
})
);

「IntStream」→「.range()」→「.forEach()」と繋げることで、for文の代わりの処理を行っています。

参考:IntStream (Java Platform SE 8 )

「IntStream」のstaticメソッド「static IntStream range(int startInclusive, int endExclusive)」は、「startInclusive(この値は含む)」から、「endExclusive(この値は含まない)」の範囲で、1ずつインクリメントした値を順番に含む「IntStream」を返します。

この「range」の処理は、通常のfor文で書くならば「for (int i = startInclusive; i

こうして作成した、IntStreamに対して、「.forEach()」を行うことになります。

「IntStream」の非staticメソッド「void forEach(IntConsumer action)」は、ストリームの各要素に対してアクションを実行するメソッドです。この操作は、ストリームの順番は考慮しません。順番をきちんと考慮したい場合は、「forEachOrdered」というメソッドが用意されています。

ここでは「IntStream」→「.range()」→「.forEach()」と繋げることで、整数の範囲を決めて1つずつ処理を行っています。

CodeIQ運営事務局より

柳井さん、ありがとうございました!
現在、柳井さんの最新問題が出題中です。
ぜひ挑戦してみてくださいね!

カテゴリー : デジタル・IT タグ :
CodeIQ MAGAZINEの記事一覧をみる ▶
  • 誤字を発見した方はこちらからご連絡ください。
  • ガジェット通信編集部への情報提供はこちらから
  • 記事内の筆者見解は明示のない限りガジェット通信を代表するものではありません。

TOP