15. 総合演習(2/2)

・総合演習の制作状況確認

・まとめと質疑

・授業評価アンケート

SNAP!による総合演習課題の作成例)

例1) 花の様な図形を描くブロック shape1 をブロック作成機能で作成し、ランダムな座標と色で描画する

例2) 花の様な図形を描くブロック shape1 の 花のサイズ と 花弁の形 をランダムに選択して描く

例3) クローンを使用せずに、順番に1個ずつ描画する。例2に加えて 花芯 の形もランダムに選択する。

その他)

前回の授業中に修正していたコードを SoundTest5.java としてこのページにアップロードしておいた。

Q&A

Q: 図形をある程度の間隔を置いてランダムに配置したい

A: 座標をランダム値に選択した後、広げたい間隔の分だけ乗算する。

例)

SNAP!で増殖しすぎる。

制御ブロック の stop すべて でプログラム動作を停止させる。→クローンが消滅する

音階のデータを音程の数値に変換する。

C1 D1 E1 → 48 50 52

オクターブ数+音程の数 で音程を与える計算式を組み込んだモニターを作成する。

コードを演奏するコードの例)

chord と code

※↓bug あり

n 秒待つ → n 拍待つ

メモ:

SwingのUI構築のサンプルを増やしたい。

文字列から全順列を生成、辞書を利用して、単語に分解可能かチェックする(文章のアナグラム化の問題)

SoundTest3,4,5あたりで、Arrays.asList( スコア1,2,3) で生成した楽譜を演奏するコードのサンプル。

SNAP!で再帰処理のサンプル。

アキストゼネコ占いのコード例)

Stream API の実験

ArrayList

List

Arrays

HashMap

Map

HashSet

Set

Stream

Collection

Collectors

Function

Iterator

package java8;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.HashMap;

import java.util.HashSet;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.Set;

import java.util.function.Function;

import java.util.stream.Collectors;

import java.util.stream.Stream;

public class Akisuto {

public static void main(String[] args) {

// 相性診断をする二人の名前をひらがなで準備

String name1 = "こばしかずひで";

String name2 = "はせがわさとし";

// ひらがなをローマ字表記に変換する

List<String> name1R = Hira.toRomes(name1);

List<String> name2R = Hira.toRomes(name2);

name1R.forEach(System.out::println);

System.out.println("-");

name2R.forEach(System.out::println);

System.out.println("---");

// ローマ字表記を1文字ずつ分解する

List<String> name1RS = name1R.stream().flatMap(e -> Stream.of(e.split(""))).collect(Collectors.toList());

List<String> name2RS = name2R.stream().flatMap(e -> Stream.of(e.split(""))).collect(Collectors.toList());

name1RS.forEach(System.out::println);

System.out.println("-");

name2RS.forEach(System.out::println);

System.out.println("---");

// ローマ字から母音だけを抽出

List<String> name1V = name1RS.stream().filter(e -> "AIUEO".contains(e)).collect(Collectors.toList());

List<String> name2V = name2RS.stream().filter(e -> "AIUEO".contains(e)).collect(Collectors.toList());

name1V.forEach(System.out::println);

System.out.println("-");

name2V.forEach(System.out::println);

System.out.println("---");

// ローマ字表記から母音とNだけを抽出(ローマ字表記をその最後の1文字に変換)

List<String> name1RS2 = name1R.stream().map(e -> e.substring(e.length() - 1)).collect(Collectors.toList());

List<String> name2RS2 = name2R.stream().map(e -> e.substring(e.length() - 1)).collect(Collectors.toList());

name1RS2.forEach(System.out::println);

System.out.println("-");

name2RS2.forEach(System.out::println);

System.out.println("---");

//母音と「ん」を数値に変換

Function<String, Integer> vowel = new Function<String, Integer>() {

Map<String, Integer> vowel2int = new HashMap<String, Integer>() {

{

put("A", 1);

put("I", 2);

put("U", 3);

put("E", 4);

put("O", 5);

put("N", 1);

}

};

public Integer apply(String str) {

return vowel2int.get(str);

}

};

List<Integer> name1I = name1RS2.stream().map(vowel).collect(Collectors.toList());

List<Integer> name2I = name2RS2.stream().map(vowel).collect(Collectors.toList());

name1I.forEach(System.out::println);

System.out.println("-");

name2I.forEach(System.out::println);

System.out.println("---");

// 相手と共通の数値を全て除去

// 別バージョンとして、 共通の数字を同じ個数ずつ除去(個数が異なる場合は多い方が残る)に変更してもよい

Set<Integer> set1 = new HashSet<Integer>() {

{

name1I.forEach(this::add);

}

};

Set<Integer> set2 = new HashSet<Integer>() {

{

name2I.forEach(this::add);

}

};

set1.retainAll(set2); // set1とset2に共通の数値だけを残す

//共通要素の数字を表示

set1.forEach(System.out::println);

System.out.println("---");

// name1Iとname2Iからお互いに共通の数値を除去

List<Integer> name1IEx = name1I.stream().filter(e -> !name2I.contains(e)).collect(Collectors.toList());

List<Integer> name2IEx = name2I.stream().filter(e -> !name1I.contains(e)).collect(Collectors.toList());

// 共通の数値を除去する操作に CollectionクラスのremoveAllを利用する。操作対象のCollectionは変更される。

name1I.removeAll(name2I);

name2I.removeAll(set1);

name1I.forEach(System.out::println);

System.out.println("-");

name2I.forEach(System.out::println);

System.out.println("---");

// 残った数値を合計する。数値が残らない場合は0になる。

int name1IR = name1IEx.stream().mapToInt(e -> e.intValue()).sum();

int name2IR = name2IEx.stream().mapToInt(Integer::intValue).sum();

System.out.println(name1IR);

System.out.println("-");

System.out.println(name2IR);

System.out.println("---");

int name1IR2 = name1I.stream().reduce(0, Integer::sum);

int name2IR2 = name2I.stream().reduce(0, Integer::sum);

System.out.println(name1IR2);

System.out.println("-");

System.out.println(name2IR2);

System.out.println("---");

// 数値を あきすとぜねこ に変換する

Function<Integer, String> Akisuto = new Function<Integer, String>() {

List<String> akisuto = Arrays.asList("あ", "き", "す", "と", "ぜ", "ね", "こ");

public String apply(Integer n) {

if (n == 0) {

return "運";

} else {

return akisuto.get((n - 1) % 7);

}

}

};

String name1Result = Akisuto.apply(name1IR);

String name2Result = Akisuto.apply(name2IR);

System.out.println(name1Result);

System.out.println("-");

System.out.println(name2Result);

System.out.println("---");

// あきすとぜねこ を 相性 に変換

Map<String, String> res = new HashMap<String, String>() {

{

put("あ", "愛してる");

put("き", "嫌い");

put("す", "好き");

put("と", "友達");

put("ぜ", "絶交");

put("ね", "熱愛中");

put("こ", "恋人");

put("運", "運命の人");

}

};

System.out.printf("%s は %s を %s\n", name1, name2, res.get(name1Result));

System.out.printf("%s は %s を %s\n", name2, name1, res.get(name2Result));

// ここまでの処理を中間の表示なしに処理する

name1I.clear();

name1I.addAll(

Hira.toRomes(name1)

.stream()

.map(e -> e.substring(e.length() - 1))

.map(vowel)

.collect(Collectors.toList()));

name2I.clear();

name2I.addAll(

Hira.toRomes(name2)

.stream()

.map(e -> e.substring(e.length() - 1))

.map(vowel)

.collect(Collectors.toList()));

List<Integer> tmp = name1I.stream().collect(Collectors.toList());

name1I.removeAll(name2I);

name2I.removeAll(tmp);

name1Result = Akisuto.apply(name1I.stream().reduce(0, Integer::sum));

name2Result = Akisuto.apply(name2I.stream().reduce(0, Integer::sum));

System.out.printf("%s は %s を %s\n", name1, name2, res.get(name1Result));

System.out.printf("%s は %s を %s\n", name2, name1, res.get(name2Result));

// ここまでの処理を2人の名前の文字列について一括処理する

Iterator<List<Integer>> names = Stream.of(name1I, name2I).iterator();

Stream.of(name1, name2)

.forEach(n -> {

List<Integer> t = names.next();

t.clear();

t.addAll(

Hira.toRomes(n)

.stream()

.map(e -> e.substring(e.length() - 1))

.map(vowel)

.collect(Collectors.toList()));

});

tmp = name1I.stream().collect(Collectors.toList());

name1I.removeAll(name2I);

name2I.removeAll(tmp);

Iterator<String> name1s = Stream.of(name1, name2).iterator();

Iterator<String> name2s = Stream.of(name2, name1).iterator();

Stream.of(name1I, name2I)

.forEach(e -> {

String s = Akisuto.apply(e.stream().reduce(0, Integer::sum));

System.out.printf("%s は %s を %s\n", name1s.next(), name2s.next(), res.get(s));

});

}

// 1文字の平仮名を数値に変換する

// あきすとぜねこ の変換処理で平仮名から直接数値に変換する場合の例

static int h2i(String h) {

if ("あかがさざただなはばぱまやらわ".contains(h))

return 1;

if ("いきぎしじちぢにひびぴみり".contains(h))

return 2;

if ("うくぐすずつづぬふぶぷむゆる".contains(h))

return 3;

if ("えけげせぜてでねへべぺめれ".contains(h))

return 4;

if ("おこごそぞとどのほぼぽもよろを".contains(h))

return 5;

return 1; // ん は 1

}

// 平仮名の文字列をヘボン式ローマ字表記のListに変換するコード

static class Hira {

// 1文字の平仮名をローマ字に変換する変換表を作成

static String hira = "あかがさざただなはばぱまやらわ" +

"いきぎしじちぢにひびぴみり" +

"うくぐすずつづぬふぶぷむゆる" +

"えけげせぜてでねへべぺめれ" +

"おこごそぞとどのほぼぽもよろを" +

"ん";

static String[] hiras = hira.split(""); // 一文字ずつに分解

static String[] romes = {

"A", "KA", "GA", "SA", "ZA", "TA", "DA", "NA", "HA", "BA", "PA", "MA", "YA", "RA", "WA",

"I", "KI", "GI", "SHI", "JI", "CHI", "JI", "NI", "HI", "BI", "PI", "MI", "RI",

"U", "KU", "GU", "SU", "ZU", "TSU", "ZU", "NU", "FU", "BU", "PU", "MU", "YU", "RU",

"E", "KE", "GE", "SE", "ZE", "TE", "DE", "NE", "HE", "BE", "PE", "ME", "RE",

"O", "KO", "GO", "SO", "ZO", "TO", "DO", "NO", "HO", "BO", "PO", "MO", "YO", "RO", "WO",

"N"

};

// 平仮名とローマ字の対応をHashに登録

static Map<String, String> hira2rome = new HashMap<>();

static {

for (int i = 0; i < hiras.length; i++) {

hira2rome.put(hiras[i], romes[i]);

}

}

// 2文字の平仮名をローマ字に変換する変換表を作成

// 拗音に対応する

static String[] hiraYous = {

"きゃ", "きゅ", "きょ",

"ぎゃ", "ぎゅ", "ぎょ",

"しゃ", "しゅ", "しょ",

"じゃ", "じゅ", "じょ",

"ちゃ", "ちゅ", "ちょ",

"ぢゃ", "ぢゅ", "ぢょ",

"にゃ", "にゅ", "にょ",

"ひゃ", "ひゅ", "ひょ",

"びゃ", "びゅ", "びょ",

"ぴゃ", "ぴゅ", "ぴょ",

"みゃ", "みゅ", "みょ",

"りゃ", "りゅ", "りょ"

};

static String[] youRomes = {

"KYA", "KYU", "KYO",

"GYA", "GYU", "GYO",

"SHA", "SHU", "SHO",

"JA", "JU", "JO",

"CHA", "CHU", "CHO",

"JA", "JU", "JO",

"NYA", "NYU", "NYO",

"HYA", "HYU", "HYO",

"BYA", "BYU", "BYO",

"PYA", "PYU", "PYO",

"MYA", "MYU", "MYO",

"RYA", "RYU", "RYO"

};

// 平仮名とローマ字の対応をHashに登録

static Map<String, String> hiraYou2rome = new HashMap<>();

static {

for (int i = 0; i < hiraYous.length; i++) {

hiraYou2rome.put(hiraYous[i], youRomes[i]);

}

}

// 文字列の平仮名をヘボン式のローマ字に変換する

// 平仮名以外の文字は変換せずに消去する

// 変換結果は1音単位のローマ字文字列のリストになる

// 促音「っ」は消去する

// 促音の次の文字は重ねない

// かゃ の様に変換不能な表記も消去する

static List<String> toRomes(String strs) {

List<String> romes = new ArrayList<>(); // 変換結果の保存用

String[] chars = strs.split(""); // 1文字単位に分解

int len = chars.length;

int i = 0; // 変換対象の位置

// charsの文字列を先頭から順に変換する

while (i < len) {

// 変換対象の次の文字が ゃゅょ の場合と

// そうでない場合を分ける

if (i + 1 < len && "ゃゅょ".contains(chars[i + 1])) {

String tmp = hiraYou2rome.get(chars[i] + chars[i + 1]); // 2文字を変換

if (tmp != null) { // 変換先が存在するとき

romes.add(tmp); // 変換結果に追加

}

i += 2; // 2文字処理を進める

} else {

String tmp = hira2rome.get(chars[i]); // 1文字を変換

if (tmp != null) { // 変換先が存在するとき

romes.add(tmp); // 変換結果に追加

}

i++; // 1文字処理を進める

}

}

return romes;

}

}

}