アナログ時計

久しぶりの記事投稿になります。

息子の受験も無事・・(ではなく、波乱に富んだものとなりましたが^^; )、一段落がつきましたので、勉強をしつつまたこちらに記録を残していきたいと思います。

〜・〜・〜・〜・〜・

9月の発表では、アナログ時計をつくることにしました。

授業ではデジタル時計をやったので、それを針と目盛りでどのように画像にするのかがポイントです。

メモリを360度に配置するというのは意外に難しくて、canvasという機能を使おうとしたのですが、enchant.jsでそれをやろうとしてもそのままではできないことがわかり、・・というような経緯がありました。その辺りのことも含めて、今回は簡単に紙にメモをしておいて発表しました(前回の発表があらら・・状態だったので)のでそのメモも。

アナログ時計のソースコード

発表のメモ

 

スロット(2)

画面タッチでスロットスタート。
2秒で止まって判定します。

「スロット」の授業をお休みしたので、そのときのプリントを先生がくださいました。・・ら、動画で見た書き方と全然違うじゃないですか(^○^)

こちらは「時計を作る」のときにも使ったsetIntervalを使ってスロットを回転させて、何秒後かに一回だけ実行されるというsetTimeoutの中でsetIntarvalを止めるclearIntervalを使って、3秒後にスロットを止めて当たりかどうかを判定する、というやり方でした。回転中にクリックするとおかしくなるので、回転中はタッチできないようにしました。ハズレのときの音もつけていましたが、繰り返すとどうしてもエラーになってしまうので外しました。

スロット(2)のソースコード

スロット

この時の授業はお休みしたので動画を見ながらなぞって作ったものです。

息子がかわいらしい音をつけるところまで作ったので、そこから少し改良してボタンでスタート・ストップ、揃ったらクリア画面が出て、またボタンを押すと回せるようにしました。ゲームは何度も繰り返して遊びたいのです!これも当たったら終わりでも良かったのですが、また回せるように改良しようとしたら意外に難しくて苦労しました。この「何度も遊べるようにする」ところでいつも苦労しますね。

スロットのソースコード

コメント以外で//消してあるところは、試行錯誤の時にうまくいかなかったものです。消してしまうとまた同じ間違いを書いてしまうので、これは出来なかったよということがわかるように残してあります。すぐ忘れてしまうので・・。こうして作ったものも、どうやったのか1ヶ月もすると忘れてしまっているので、こうして記録しています。

・改良したところ

ボタンを設置

場合分けをするためにcounterを作って、ハズレが出ても当たりが出ても再度スロットを回せるようにしました。当たりが出ると背景が変わり文字がでるので、再度回し始めるときに文字を消して背景を戻すために工夫が必要でした。

0:最初かハズレの判定が出た時(ボタンを押してスロットルをスタートすることができる) 
1:スロットが回っている間(ボタンを押してもスロットはスタートできない)
2:当たりの判定が出たとき(再度ボタンを押すと背景が戻り、スロットが回る)

として動作を制御しました。

一つのボタンでやろうとするとこのように面倒なことになります。

二重のfor文を使ってビンゴカードを作る

今回の授業は、for文を使って、ビンゴカードを自動作成しようというものでした。

二重のfor文

ポイントは、二重のfor文です。「5回の繰り返し」を5回繰り返すことで、5×5の25個の数字を並べます。

// 二重のfor文(c0,c1,c2,c3,c4を5回繰り返す)
for(var r=0; r<5; r++){
    console.log("r" + r);//r0~r4
    for(var c=0; c<5; c++){
        console.log(" c" + c);
        // 座標に応用
        var x = 32 * r;// 授業とはrとcが逆(列と行を逆にしたいから)
        var y = 32 * c;
        console.log(x + ", " + y);
        // ラベル
        var label = new Label();
        label.x = x;
        label.y = y;
        label.text = "[" + r +","+ c +"]";// こちらも逆にする(これで[列、行]の並びになる)
        scene.addChild(label);
         label.text = getRandom(1, 75);
    }
}

c0からc4をr0からr4まで5回繰り返すということです。(授業でやったものとはrとcを逆にしました。列でまとめたかったからです)

c0~c4が5列に並ぶという形になります。

ラベルのところでテキストを「“[” + r +”,”+ c +”]”」とすることで、

[00][10][20][30][40]

[01][11][21][31][41]

[02][12][22][32][42]

[03][13][23][33][43]

[04][14][24][34][44]

となりました。(rが列、cが行となっています)

あとは label.text = getRandom(1, 75); で、それぞれの表示を1〜75の数字をランダムに出るようにすれば、ビンゴカードの出来上がりです。

・・しかし、これだとそれぞれの数のランダムなので、数が重複する場合があります。(それはそれで二つ空けられるラッキーナンバーということにすればいいのかもしれませんが、一般的なビンゴゲームにも一応ルールがあって、その中には数は重複しないというのがあります)

数が重複しないようにシャッフルを使う

そこで、数が重複しないように作るにはどうしたらいいかということで、その方法も教えてくださいました。

ここでダステンフェルドのシャッフルを使います。

// 配列を使ってダブらないビンゴカードにする
// 配列を作る
var nums = [];
for (var i=0; i<25; i++){
    nums.push(i);//numsの中にiがプッシュされていく。今iは0~24の25個の数字
}
console.log(nums);
// ダステンフェルドの手法でシャッフルする
for(var i=nums.length-1; 0<i; i--){// iが24から1まで24回繰り返す
    var rdm = getRandom(0, i);// rdm:自分の数以下からランダムに選んだ数字一つ
    var tmp = nums[i];// 新しくtmpを用意してnum[i]を入れておく
    nums[i] = nums[rdm];// nums[i]に選ばれたランダムな数を入れる
    nums[rdm] = tmp;// nums[rdm]にtmp(muns[i])を入れる。これで交換完了
}
console.log("nums", nums);

0から24までの数をシャッフルしています。

どうなっているのかわかりにくいのでそれぞれconsole.logで見てみました。

// ダステンフェルドの手法でシャッフルする
for(var i=nums.length-1; 0<i; i--){// iが24から1まで24回繰り返す
    console.log("i:", i, "," , "muns[i]:", nums[i]);
    var rdm = getRandom(0, i);// rdm:自分の数以下からランダムに選んだ数字一つ
    console.log("rdm:" , rdm , "," , "nums[rdm]:" , nums[rdm]);
    var tmp = nums[i];// 新しくtmpを用意してnum[i]を入れておく
    console.log("tmp(=nums[i]):" , tmp);
    nums[i] = nums[rdm];// nums[i]に選ばれたランダムな数を入れる
    console.log("muns[i](=nums[rdm]):" , nums[i]);
    nums[rdm] = tmp;// nums[rdm]にtmp(muns[i])を入れる。これで交換完了
    console.log("nums[rdm](=tmp):" , nums[rdm]);
    console.log(nums);
    //全部consoleで見てみる
}
console.log("nums", nums);

すると、このような動きになっていました。

for文の繰り返しの中でその都度配列の順番が変わって上書きされるので、最初はnums[22]は22だったのが、入れ替わったことで途中でnums[22]は24に変わっています。

一度交換の相手になったランダムで選ばれた「数字」は、後ろから順番に入っていって固定され(iは減少していくから)二度と交換されることはありません。そうでないと精度的に正しいシャッフルとなりません。

ラベルで表示する

あとは、ランダムに並べ替えられた数字にindexを用意して、num[0]~num[24]までがラベルのテキストに入るように書き換えて、ランダムに並んだ数字を表示できました。

// インデックス
var index = 0;
//label.text = "[" + r +","+ c +"]";// こちらも逆にする(これで[列、行]の並びになる)
label.text = nums[index];// 初期値は0
index++;// ラベルのテキストがnums[0]からnums[24]になる

一般的なルールのビンゴカードを作る

つぎに、これを応用して、日本でのビンゴの一般的なルールにしたがったものを作ってみたいと思ってやってみました。

wikipediaのビンゴより

ルールには無数にバリエーションがあるが、ここでは日本で一般的に行われている代表的なものを示す。一般的にビンゴカードはタテ・ヨコ5マスずつ、計25個のマス目が書かれている。その内、中央を除く24マスには1から75までの番号のうち24個の番号が書かれており、中央はフリースポットとして最初から有効な番号として扱われる。1枚のカードの中で同じ番号が重複することはない。

カードに書かれる番号は、通常はまったくのランダムで配置されているわけではなく、一番左の列は1-15の中から5個選ばれている。同様に、左から2列目は16-30、中央列は31-45、右から2列目は46-60、一番右の列は61-75から5個ずつ(中央列のみフリースポットがあるので4個)選ばれている

全くのランダムではなく、15づつの数の固まりから5個ずつ選ぶようになっているようですね。

ちょっとややこしそうですが、for文をたくさん使ってやってみました。

1〜15まで、16から30まで、31から45まで、46から60まで、61から75までの数からそれぞれ5つずつランダムに選ぶ必要があるので、それぞれシャッフルした15個の中から5つを選んでそれを左の列から並べるというやり方で作りました。

まず、nを始めの数とする変数として15個の数のシャッフルを作る関数 Nums15(n) を作ります。ここでやっていることは、要素15個の配列をシャッフルして、その最初から5つの目までの数を取り出してnumsselという配列に入れていくという処理です。既にシャッフルされた数なので、そこから5つの数を取り出せば、ランダムで重複しない数となります。

    // 目的の配列を用意
    var numssel = [];

    //nをはじめの数とする15個の数字のシャッフルを作る関数
    function Nums15(n){
        var nums15 = [];// 15個の配列の入れ物を用意
        for (var i=n; i<n+15; i++){
            nums15.push(i);// n~n+15までの数を[]に入れる
        }
        // シャッフル
        for (var i=nums15.length-1; 0<i; i--){
            var rdm = getRandom(0, i);
            var tmp = nums15[i];
            nums15[i] = nums15[rdm];
            nums15[rdm] = tmp;
        }
        // 出来たランダムな配列nums15から5つの数字を取り出してnumsselという配列に入れていく。
        for(var i=0; i<5; i++){
            numssel.push(nums15[i]);// 最初から5つをnumsselに入れていく
        }
    }

あとは、そのかたまりの始めの数は1,16,31,46,61なので、その関数をつぎのようなfor文で実行します。

// 実行する。ここでnumsselが最終的に5*5で25個となる
for(var i=1; i<76; i+=15){ 
    Nums15(i);
}

すると、ランダムに選ばれた5つの数を5回入れていくので、numsselには、1~15から5つ、16~30から5つ、31~45から5つ、46~60から5つ、61~75から5つ、合計25個の数が選ばれて入ります。

ただし、真ん中はFreeにしたいので、真ん中はmussel[12]なので

numssel[12] = "free";

とします。

あとは、授業でやったときとおなじように、この配列musselにindexを使ってラベルに対応させて表示させれば、左の列からルールのようにならんだビンゴカードができました。

forをたくさん使ったので、すごくforの練習になりました。functionも使ったので、途中、頭がこんがらがって死にそうになりました。関数は作ってもその実行は別の場所でやる感じなので、コードでは後ろに書いてあっても処理としては戻るような感じになって、あっちこっちで訳がわからなくなりそうでしたが、これも慣れなのでしょうか・・頭の中でforループの処理を同時にシミュレーションできないと書けないと思うので、これがサラッとできちゃうプログラマさんてすごいね。でもfunctionmとforを使うと本当に短く書くことが出来て、達成感がありました。あと今見て思ったんですが「配列の配列」ってあるんかな、当然あるでしょうね。(私は汚いコードでも動けばいいという^^;だめよねそれじゃ)

文字の基準が中心で揃っていなっていないのが気になります・・そのうちこれを使って、何かゲームが作れたら作ってみたいと思います・・(授業で話しが出た独りビンゴなんかいいと思うけどなー)

完成したもの

時計を作ってみよう(javaScript)

1.時計の表示

今回の授業は、デジタル時計を作るというものでした。

「一秒ごとに何かが起きるというjavascriptの機能を使う」と先生は説明されました。(子供向けにこのような説明の仕方をされるところが面白いですね)

まず、一定時間ごとに処理をするというsetIntervalを使った関数を作ります。

// 1秒毎に処理をする
setInterval(function(){
    console.log("Hello!!");
},1000);

時間はミリ秒で指定します。ここでは1秒ごとに処理をしたいので、1秒=1000ミリ秒で指定します。

console.logで確かめると、一秒ごとにHello,Hello,と表示されるので、処理されていることが確かめられました。

時計の処理の関数を作って、この中に入れます。(console.logをshowClock();に書き換える)

function showClock(){
    console.log("時計の処理!!")
    // 日付オブジェクト
    var dObj = new Date();
    // 時間を取得する
    var hours = dObj.getHours();//日付から時間をgetする
    console.log(hours);
    var minutes = dObj.getMinutes();//日付から分をgetする
    console.log(minutes);
    var seconds = dObj.getSeconds();//日付から秒をgetする
    console.log(seconds);
}

new Date();で、今現在の日付のデータを取得し、その中に含まれている時間、分、秒を取り出しています。それぞれconsole.logで

10
11
05

のように表示されます。これではわかりにくいので、横並びに表示されるようにします。

    // デジタル時計
    var str = hours + minutes + seconds;//数値として加算されてしまうので間違い
    console.log(str);
    var str = hours + ":" + minutes + ":" + seconds;
    console.log(str);
    var str = hours + "時" + minutes + "分" + seconds + "秒";
    console.log(str);

単に+でつなぐと、数値として扱われるために、加算されて一つの数値となってしまいます。

そこで、間に文字列を挟むことで、

10:11:05

あるいは

10時11分05秒

と表示させることができました。

2.日付の表示

次は日付です。

    // 年月日を取得する
    var year = dObj.getYear() + 1900;
    console.log(year);
    var month = dObj.getMonth() + 1;
    console.log(month);
    var date = dObj.getDate();
    console.log(date);

これもさっきと同じように、dObjから年、月、日のデータをそれぞれ取り出します。

ここで注意が必要なのは、getYearでは1900マイナスの年が取り出されるので(1900年台に始まったコンピュータの世界で、下2桁で処理をしていた為と考えられるそうです)、1900をプラスしたのが現在の年になること(代わりにgetFullYearとすると2018で出すことができるようになっている)、月は1月から配列として扱うのが都合がよいので(月は国によって呼び方が異なるから。日本では1月、2月だが、January、 February・・だったり)、1月は0というデータとして与えられるから1を加えること、日付はそのまま(多分これはどこの国でも1日、2日だから)となることです。

これを横並びで表示させるには、時計のときと同じように

    // デジタル日付
    var str2 = year + "年" + month + "月" + date + "日";
    console.log(str2)

となります。

2018年8月25日

と表示されました。

3.曜日の表示

最後に曜日です。

    // 曜日
    var arr = ["日", "月", "火", "水", "木", "金", "土"];
    var day = dObj.getDay();//日付から曜日をゲットする
    console.log(day);
    console.log(arr[day] + "曜日")

まず、曜日の配列を作ります。次に日付のデータから曜日をゲットします。曜日は、日曜日を0として土曜日まで、0,1,2,3,4,5,6という数字で与えられます。今日は土曜日なので6と出ました。

そこで、曜日の配列から、その数値を添字としたものを取り出せば、

土曜日

と今日の曜日が表示させることができました。

4.【感想】

この日の授業は盛りだくさんの、ぼーっとしている暇のないとても濃い授業でした。どうして年は1900を引かれた値になっているのだろうかとか、コンピュータの起源と歴史にまつわる話が出てきたり、なぜ月のデータは0から始まっているのか、考えてみたら日本では1月2月・・だけど英語圏や他の国では違うよね、日本でも睦月、如月・・と呼んでいたとか、いろいろ興味深い話題もいろいろ出てきました。

それにしても、この日の授業はゲームのように画像が動いたりするのでもなく、ただコンソール画面に表示される数字や文字を見ながら、「おぉー!」とか「わー!」とか盛り上がっているという、なんとまあプログラマーさん(の卵たち)でしょうかと思いました。(知らない人が見たら一体何が面白いの何を喜んでいるのという感じでしょう。)みんな打ち込むのもすごく速くなっているし。

先生方、よくここまで子どもたちを育てられましたね・・と少し感動を覚えた私でした。

2018_8_4_配列と繰り返し処理を使った平均値の計算と複数の配列とランダムを使った自動作文

ソースコードまとめ

Coding泪橋(仮)_No001
平均値を理解する

// 処理1
// 目的:変数と計算を理解する
// 問題:Consoleには何が書き出されるか
var a = 10;
var b = 20;
var c = 30;
var total = a + b + c;
console.log(total);
var avg = total / 3;
console.log(avg);

答え total:60,  avg:20

// 処理2
// 目的:配列と添字を理解する
// Consoleには何が書き出されるか
var arr= [80, 60, 10];
var total = arr[0] + arr[1] + arr[2];
console.log(total);
var avg = total/ 3;
console.log(avg);

答え total:150,  avg:50

// 処理3
// 目的:配列と繰り返し処理を理解する
// 問題:Consoleには何が書き出されるか
var arr = [20, 70, 50];
var total = 0;
for (var i=0; i<arr.length; i++){
    total += arr[i];
}
console.log(total);
var avg = total / arr.length;
console.log(avg);

答え total:140,  avg:46.666666666666664

(繰り返し処理を使って平均値を出す方法。処理2のやり方では数字が多くなると大変だがこれだと簡単)

Coding泪橋(仮)_No002
ランダムを理解する

// 処理1
// 目的:配列を添字を理解する
// 問題:Consoleには何が書き出されるか
var arr = ["プリン", "ヨーグルト", "シュークリーム"];
var str = "おやつに" + arr[0] + "を食べたいぜよ!!";
console.log(str);

答え おやつにプリンを食べたいぜよ!!

// 処理2
// 目的:ランダムを理解し、整数に変換する事ができる
// 問題:Consoleには何が書き出されるか
var rdm = Math.random() * 3;//Math.randam()とは、0以上1未満のランダムな数
console.log(rdm);
var num = Math.floor(rdm);//Math.floorとは小数点以下切り捨て
console.log(num);
var str = "おやつに" + arr[num] + "を食べたいぜよ!!";
console.log(str);

答え rdm:(0以上3未満のランダムな小数),  num:(0,1,2のいずれか), str:おやつに◯◯◯が食べたいぜよ!!(◯◯◯はランダムに変化)

// 処理3
// 目的:複数のランダム値、配列を用意して自動作文を作る
// 問題:Consoleには何が書き出されるか
var arr1 = ["神様", "俺様", "貴様", "何様"];
var num1 = Math.floor(Math.random() * 4);
var arr2 = ["学校", "ファミレス", "火星", "ハワイ"];
var num2 = Math.floor(Math.random() * 4);
var arr3 = ["勉強", "注文", "探検", "旅行"];
var num3 = Math.floor(Math.random() * 4);
var str = arr1[num1] + "が" + arr2[num2] + "で" + arr3[num3] + "した";
console.log(str);

答え (ランダムな作文)

グループの中の最上位置の判定とスクロール

下書きしたまま放置の記事が結構ありますが、あんまりきちんとと堅苦しくなると続けられなくなるので、思いつくまま軽い感じでいきたいと思います。

今日の授業は最近の中でも面白く感じたので、記録として書いておきます。

今チャレンジしているゲームですが、実は息子は、今回のテーマの初回の授業を受けた後から、偶然にも、先生がモデルにされたサリータワーと全く同じようなものを作りたいと作り始めていました。左右に移動するもの(授業ではヘリ)から物(授業ではブロック)を落として、積み上げるというものです。

前回の授業では、ブロックが積み上げられたら、ヘリにぶつかってしまうので、そうならないようにヘリを上昇させるにはどうしたらいいでしょうね、というところで終わりました。

息子は続きを作るべく、そこに挑んでみましたが、これは難しいのです。なぜなら、「ブロックが上のほうまで積まれてきたら」というのが問題なのですが、これを判定しようにも、ブロックは一番上の位置から落としているのです。落とす時点で既に一番上にあるのですから、「ブロックの位置から・・」とやろうとすると、落とす時点でもう積んでいる。だから「積まれたブロックの一番上のものから・・」とやろうとするなら、いつ判定するのか、どうやって判定するのかということになります。この時点で、私はもう面倒くさそうと思ってしまい、授業では擬似的な方法で簡単にそれっぽく見せる方法を採られるのではないかと思っていました。

そこで、今日の授業です。授業で示された方法は、「ブロックを落としてから2秒後(連続して落としていても最後に落としたものから2秒後)に、落としたブロックをすべて調べて一番上にあるものの高さを取り、それとヘリの高さを比較して一定以上近ければ離す」というものでした。

先生は「如何に誤魔化すか」と言われましたが、私は結構な正攻法じゃないかと思ってさすが先生と思いました。

    // タッチするとブロックが落ちる(と同時にreadyAlt()が発動)
    scene.on(Event.TOUCH_START, function(e){
        dropBlock();
        // (1) タッチしたタイミングで処理を開始しよう
        readyAlt();    
    });

    function dropBlock(){
        var block1 = new PhyBoxSprite(31, 31, enchant.box2d.DYNAMIC_SPRITE);
        block1.image = core.assets["images/do_daruma.png"];
        block1.x = heli.centerX;
        block1.y = heli.centerY;
        group.addChild(block1);
    }

    // (2) 処理を遅れさせよう(readyAlt()の中身)
    function readyAlt(){
       scene.tl.clear();// これを入れることで、落とす度にリセットされ、最後に落としたものからのカウントになる
       scene.tl.delay(32);// 32フレーム経ってからceckAlt();が発動
       scene.tl.then(function(){
          checkAlt(); 
       });
    }

    // (3) ブロックを調べる処理(checkAlt()の中身)
    function checkAlt(){
        console.log("高さを調べる");
        // (4-1) グループで最も高い位置にあるブロックを調べる
        //for(初期化; 条件; 後処理;){処理}
        var borderY = 480;// 画面の一番下。これよりブロックは下へ行くことがないので、これをブロックの最上位の位置の初期値とする。
(これとブロックの位置と比較して、それより上の位置なら最上位として更新するという仕組み)
        for(var i=0; i<group.childNodes.length; i++){ // ブロックの数だけ繰り返す(ブロック全部調べる)
            console.log(i);
            var y = group.childNodes[i].y;// ブロックのi番目のy座標が取得される。
            console.log(y);
            //高い位置にあれば更新
            if(y < borderY){
                borderY = y;// 繰り返すことで最終的には一番高いyがborderYとなる。
            }
        }
        console.log("最も高い位置にあるのは:" + borderY);
        // (4-2) 高い位置から一定の距離を保つ
        var padding = 130;// ヘリと一番上のブロックの距離
        if(borderY < heli.y + padding){
              heli.y = borderY - padding;
        }
    }
    
    // (5) スクロールさせる
    scene.setScrollRange(heli,80,0);// ヘリが上に上がっていくと見えなくなるのでスクロールさせる

どうやって一番上のブロックのy座標を取り出すのかというと、まずブロックはy座標480より下に行くことはないので、borderYの初期値を480としておきます。そして、1個めのブロックのy座標と比較して、これより上ならそのy座標の値をborderYに書き換え、さらに2個めのブロックも同様・・とブロックの個数分つまり全部で繰り返せば、最終的にborderYが一番高いブロックのy座標の値に書き換えられているという訳です。プログラミングではこうやってやるんだーと感心、納得。

こうして順序立てて教えていただくと、想像したより難しくなかったですし、考え方ややり方はほかにも色々応用できそうです。

シャッフルを紙とペンでやってみる

前回の、「フィッシャ–イェーツのシャッフルを視覚化してみる」の続きです。

フィッシャー-イェーツのシャッフル

紙とペンで、実際やってみるとよくわかります。一番簡単な、3つの数字、123の並びをシャッフルしてみます。このやり方に従ってすべての場合を出したときに、6通りが均等になっていれば、確率的に正しいことがわかります。

簡単なのですぐできます。

ダステンフェルトの手法(正しいやり方)

これをプログラミング的に書いたダステンフェルトのやり方もやってみましょう。

            (↑この部分、3つとも j=2 ではなくて、j=1 の間違いです。書き間違えてる!!)

ダステンフェルトの手法(間違ったやり方)

前の記事フィッシャ–イェーツのシャッフルを視覚化してみるの中の、赤いやり方の処理と青いやり方の処理をごちゃまぜにした間違ったやり方です。当初、ウィキペディアの説明が間違っているのではないかと思ってやってみたのですが、それは私の勘違いで、そちらの説明は合っていました。前の記事も訂正しておきました。でもこれはこれで間違いの例なので載せておきます。数字でやるなら数字で、順番でやるなら順番で、統一しないといけないということです。

結果、4通りとなってしまいました。

これは、1順目で、2以外の数字が二番目にくる結果が1通りあるので、それに対して2順目で2通りあり、合計1×2通りが狂うからです。

ということで、やはり間違いであることがわかりました。

ところで、このダステンフェルトの手法

要素数が n の配列 a をシャッフルする(添字は0からn-1):
  in - 1 から 1 まで減少させながら、以下を実行する
       j に 0 以上 i 以下のランダムな整数を代入する
       a[j] と a[i]を交換する

は、フィッシャー−イェーツをコンピュータ向けに改良したものとあって、内容がプログラミングの書き方(forループ)そのものです。

だからもし、プログラミングを習っていなかったら、これが何を言おうとしているのか、多分わからなかったと思います。そんなところからも、またすごく面白みを感じたのでした。

【追記】

あれから大学時代の古い記憶がかすかに蘇ってきて、何の科目か何の勉強かも思い出せないのですが、レポートをやるために本を調べていたときに、iとjの出てくる、こんなような説明の意味がさっぱりわからなくて半日以上考えたり調べたりしたけれどわからなくて諦めたことがあって(当時はまだパソコンもなかったし)、もしかするとこれだったのかな・・とふと思いました。上の「ダステンフェルドの手法」の文には、日本語的に致命的な欠陥があると思います。(笑

〜減少させながら、以下を「繰り返し」実行する

と書くのが正確なのではなかろうか٩(๑`^´๑)۶。繰り返し処理というのは普通の数学教育では一般的ではないので、プログラミングをやっている人にはパッと見ですぐわかることでも、やったことのない人には「減少させながら以下を実行する」とだけ書かれても意味不明だと思います。

AIを使ったゲームの発表

11月最後の授業日は、2017年10月〜11月に勉強したテーマ「AIに挑戦せよ」の作品の発表(報告)でした。

AIというと最近ですと将棋を思い出します。私は将棋はルールを知っているくらいでやるにしても幼稚園程度の将棋しか指せませんが、同世代の羽生永世七冠のファンで、将棋連盟のサイト棋戦のページや対局結果をときどき見ています。将棋の内容はわかりませんが、誰が勝ったと強いとか、対戦での行き詰まる様子や、棋士のすごさや個性が面白く、自分は将棋はできないのに将棋の世界を観るのを楽しんでいるというファンです。

その将棋で、プロ棋士の名人が将棋ソフトに負けてしまいました。動的な部分では、人間は機械には勝てないというのはずいぶん前から当たり前のことでしたが、そういう単なる一方通行の働き(早く走るとか動くとか)だけではなく、さまざまな選択肢の中から最善のものを考えて判断し選択するという知能の部分でも、コンピュータは人間に迫るかそれ以上の力を持ち始めたということなのでしょう。

さて、今回やってきたのは、「ゲームAI」といわれるものです。ゲームAIには主に3つのものがあり、

・メタAI・・ゲームそのものの難易度を変える(例:クリアする度に難しくなる)
・キャラクターAI・・キャラクターの知能
・ナビゲーションAI・・地形や状況の空間的な情報を抽出するAI(例:目的地に向かう経路)

この中でも、「キャラクターAI」といわれる、あたかもゲーム内のキャラクターが知能をもってるかのように、というか、プログラミングによって知能を持たせると言ったほうがいいのでしょうか、条件に応じて動きが変わるようにプログラミングをするというものです。

授業の流れとしては、以下のようなものでした。

・タイムラインで判定のタイミングを調整する。
・ファンクション(関数)で判定の中身を作り、先のタイムラインの中で判定をする。
・パラメーターを使う。hpとmode。(hpはhpの値によってキャラクターの動きを変える。modeは、modeの値によって、実行する処理を制御することができる。modeが切り替わったときに一度だけ実行させたりすることができる。)       

ブッタ様?

・パワーメーターの作り方。
・シューティングへの応用。
・ループキャンセル

これらを、ブッタ様にプラスの弾を撃ったりマイナスの弾を撃ったりすることによって、ブッタ様の状態が変化するというサンプルを基に作っていきました。

それで、まず作ったのはサンプルを基にした「ブッタ様大噴火」。次に、課題に沿って作った「おならして帰る」。そしてシューティングへの応用ということで、前に作ったシューティング「いきなりボス」を改造して、「AIマンドラゴラ」(解説)を作りました。

今回発表では、「AIマンドラゴラ」を発表しました。

また今回もみんなの個性爆発の作品揃いで、大変楽しいものばかりでした。ブッタ様を自分の好きなキャラクターに変えたり、戦国武将の隊列だったり(絵がかわいくて上手!。息子が渡した感想に書いた言葉「私にはとても描けません」(笑))、お友達との合作で、大量のトイレットペーパーをわかめで撃っていくという素晴らしい想定、得意のドット絵で書いたかっこいいボスキャラなど、どれも自由で素晴らしいものでした。

NHK教育で金曜日にやっている番組「ビットワールド」で、「アリですよ!」という、「おもしろい答えでマス子先生たちをおどろかせよう!!」というコーナーがあるのですが、このコーナーでは最後にいつもセイコー先生が「ではマス子先生採点を」と言い、それに対してマス子先生が「全部、満点で!」と答えるのがお決まりになっているのですが、それを思い出しました。

 

おまけ:本日のツボ

「にんじんおばけ」

マンドラゴラのつもりで描いた絵に対してそれを知られない先生がつけた名前。こどもたちにすごく嫌われそう・・実際のマンドラゴラはどっちかと言うとだいこん?

マンドラゴラ

 

たぶん、瞬間移動して弾に当たってそのまま死にました。」

ボスが出てきたと思った瞬間、ミサイルだけを発射して一瞬で消えてしまいました。ボスなのに一瞬で死ぬて。それについてものすごく冷静に言い放った姿にツボりました。

 

「観音様」

ゲームの説明で「観音様が・・」と言われたので、てっきり、オリジナルの観音様が出てくるのかと思ったら、ブッタ様のことでした。(本物のブッダとはは仏陀と書き、仏様(如来)のことを指し、そのうちの一人が地球上の唯一の仏陀であるお釈迦様。それ以外だと、知られたところでは、阿弥陀如来、大日如来、など、それぞれ名前がある。仏様の頭は覚りを表すパンチパーマのような「螺髪」。)

・・で、「観音様」と呼んでいるところが、なんとも味があって、別に間違いとかではなくて、ああこの人にとっては観音様に見えたんだと宗教観みたいなのが垣間見えて、観音様という言葉が自然に出てくるところがいいなあと思ったのでした。

 

なぜか上から弾が出てくるという・・流れ弾が。・・ここが戦場だと言うことを忘れてはならない

このあと「本当はもっと大きな落石みたいなのがよかったかな」とおっしゃってました。確かに、すごく小さな弾が、ブッタ様と一緒に降っているのです。目を凝らさないとわからない、そして、一瞬の油断も許されないという決め台詞・・ここは戦場だったのね、、、というところにツボりました。

初回の授業で驚いてそして気づいたこと

 

とりあえずCodeFriendsにバタバタと入会となって、一週間足らずで初回の授業日がやって来ました。

先生がどんな人かも、どんな雰囲気なのかも、何をやるのかもさっぱりわかりません。

そこで私は、いきなりびっくりしてしまうのです。びっくりしたというと、少し大げさかも知れませんが、意外なことがあって、そのことでいろいろ考えさせられた、というのが正確かも知れません。

それは、自己紹介のときのことです。先生から、名前の他に「呼び名、住んでいるところ、最寄りの駅、それから好きなゲームや好きなYouTuberを教えて」と言われたのです。

今からすると何が?という感じなのですが、「みんなの前で(堂々と)好きなゲームを発表する」ということが、今までにはないことで、学校では考えられないことですから、ちょっと驚いて新鮮だったのです。

私が学生の頃、TVゲームをやるとバカになるとか、犯罪を助長するとか言われてました。それはもう、ゲームは諸悪の根源のような言われ方だったような気がします。

今はそれほどまでに表立って言われていないにしても、「子どもは(TVゲームなんかしないで)外で元気に遊びましょう」は根強くあるのではないでしょうか。

要するに、「子どもからはなるべくゲームは遠ざけるべし」。全くやらないのは無理にしても、なるべくやらないのに越したことはない、こういう考えが教育現場とその周りには前提としてあるように思います。

だから、子どもが堂々と「ゲームが大好きです!昨日もゲームをやりました!」なんて学校で先生やみんなの前で言うことなんてないわけで、当然、好きなゲームを発表するなんて考えられないのです。友達同士で話をするのがせいぜいですが、それすら許されない雰囲気があるように思います。

息子が小学校のとき、こんなこともありました。学校で、友達とゲームの話をしていたところを先生に見られたようで、あの子はゲームの話ばかりしていると思われたのか(実際は息子はそこまでゲーム好きではありません。確かに好きですが、普通かそれ以下だと思います。周りを見れば、もっとゲームをやっている子、詳しい子達がいます)、あるとき先生から、「あの子はゲームで友達を作る子ですね、気を付けなければいけませんよ」と、いかにも感心しないという様子で言われたのでした。担任の先生ではなかったので、さほど気にしなかったのですが、今だに何を、どうして気を付けなければいけないのかよくわかりませんが・・。

でも、子ども達はゲームが好きです。私もゲームは好きだし。現代っ子ですから、友達と集まれば、ゲームをやります。多くのお友達がDSを持っています。据え置きのTVゲームも多くのご家庭にありますし、うちでも、お友達のお宅でもゲームで盛り上がっていることはよくありましたし、もちろんゲームとの関わりについては各ご家庭でルールがありますが、うちでは本当に楽しそうにお友達とTVゲームやDSをやって盛り上がっていたのです。

でも、それを、学校で”公に”言うことはありません。子どもは日記として日々の出来事や感想を連絡ノートに書いて先生に出していました。低学年のときは週末だけ、高学年からは毎日でした。学校であったこと、帰宅してから家でしたこと、友達と遊んだことなどを書くのですが、そこに、「友達とTVゲームをしました」と書いてはいけないというのが暗黙の了解としてあるのです。

実際、私は「今日何書いたらいいだろ〜」と悩む息子に対して、「○○君とゲームしたこと書いたら?」と言ったことがありますが、「そんなこと書けないよ〜」と返ってきて、「やっぱそうだよね^^;」となりました。ゲーム以外のことで遊んだことは、堂々と書ける(むしろ喜ばれる)のに、です。確か、低学年のときに一度ゲームで遊んだことを書いて、「ゲームしないで外で遊びましょう」と書かれたこともあったように思います。

学校とその周りでは、ゲームははっきり言って「悪者」なのです。これについてはまたいろいろ考えさせられることがあって、また書きたいと思いますが、子ども自身もそれをひしひしと感じていて、学校ではゲームのことは秘め事のようになっているのでしょう。

だから、「堂々と好きなゲームを言いましょう」なんて、普段ありえないことですから、私自身驚いてしまった。驚いたことに驚いて、考えてみたら、そういうことだったんだと気付いた、という訳です。

本当は、みんなゲームが好き。もちろん、ゲームは楽しい分、依存の危険もはらんでいるから注意も必要なんですが、それを抑圧されているから、ゲームのことを話せたり、共有できたりする場があって、しかもそれにしかめっ面をしないでノってくれる大人がいたら、嬉しいですよね!

それが時にCodeFriendsの教室だったり、先生だったりする訳です。(つづく)

I love TETRIS!