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;
}
}
}