導入
忘年会のシーズンが始まります。忘年会といえばビンゴ。賞品が当たるかどうかは別として、
今回はビンゴマシンを作ることを通して、
展開
ビンゴマシンを作ろう
ビンゴゲームとは
おそらく知らない人は少ないと思いますが、
ビンゴゲームとは
- 5行5列の正方形マス目にランダムな番号の書かれたカードを用います。
- 参加者はこのカードを一人一枚持ち、
司会の読み上げる数字が自分のカードにあれば、 カード上の数字にチェックを入れます。 - カード上のチェックが縦・
横・ 斜めいずれかの方向で5つ連続すればあがりです。その際 「ビンゴ!」 とコールします。 - チェックが4つ並んだ時点で
「リーチ!」 とコールする必要があります。
このビンゴゲームで、
Processingでビンゴマシンを作り終えたました
このビンゴマシンをProcessingで開発しました。シンプルながら、
このsketchを実行すると、
BingoMachine.pde
の実行結果
このコードをリファクタリングしていきましょう。意図的に臭いを発生させていますので、
テストを作成する
このコードは正しい実行結果を残しますから、
- ビンゴ数列は、
1から75までの数がランダムに、 一つずつもれなくだぶりなく並んだ数列であること。 - これを順に取り出せること。
現在のビンゴマシンの機能はこれだけですから、ArrayList
のオブジェクトbingosuuretsu
の要素が適切かをチェックするコードが必要です。
現在のsketchは、
この作業は、
メソッドの抽出
(Extract Method) 長すぎて読みにくいコードから、
処理のかたまりを切り分けてメソッドにする。
Extract Method
本来は上述の定義のように、
このような流れで変更し、
テストモードと実行モードを切り替えるフラグTEST_
を定義し、
ビンゴ数列を発生するメソッドはcreateBingoPermutation
で、ArrayList
のオブジェクトへの参照を受け取り、
ビンゴ数列をチェックするテストメソッドがtestBingoPermutation
です。ArrayList
のオブジェクトへの参照を受け取り、
テストは問題があればコンソールにメッセージを表示します。 本来はその他のメッセージをコンソールに表示しないところですが、
コードを見渡す
ここで、
BingoMachine.pde
の全ソースコード//ビンゴマシン
//テストモード
boolean TEST_MODE = true;
int tugi = 0;
//ビンゴ数列を格納するオブジェクト
ArrayList <Integer> bingosuuretsu = new ArrayList<Integer>();
void setup(){
if (TEST_MODE == true) {
runTest();
} else {
runBingoMachineApp();
}
}
void draw(){
if (TEST_MODE == true) {
//Test code
} else {
println("["+tugi+"] : " + bingosuuretsu.get(tugi));
background(204);
textSize(32);
fill(0, 102, 153);
text(bingosuuretsu.get(tugi), 10, 60);
}
}
void mousePressed() {
if (TEST_MODE == true) {
//Test code
} else {
if(tugi<74) tugi++;
}
}
void runBingoMachineApp(){
println("Bingo Machine booting up...");
noLoop();
println("This is Bingo Machine!");
createBingoPermutation(bingosuuretsu);
println("ループスタート");
loop();
}
void createBingoPermutation(ArrayList v){
println("createBingoPermutation called.");
ArrayList <Integer> temp = new ArrayList<Integer>();
for(int i = 1; i <= 75; i++){
temp.add(i);
}
while( temp.size() > 0 ){
int i = (int) (Math.random() * 100 + 1) % temp.size();
v.add(
temp.get(i)
);
temp.remove(i);
println("ビンゴ数列["+(v.size()-1)+"] = " + v.get( v.size()-1 ) );
}
println("createBingoPermutation finished.");
}
void runTest(){
println("runTest called.");
createBingoPermutation(bingosuuretsu);
assert testBingoPermutation(bingosuuretsu) == true : "ビンゴ数列にもれかだぶりがあります" ;
println("runTest finished.");
}
boolean testBingoPermutation(ArrayList v){
println("testBingoPermutation called.");
//ビンゴ数列のチェック
ArrayList <Boolean> tesuto = new ArrayList<Boolean>();
for( int i = 0; i < 75; i++ ){
tesuto.add(false);
}
for( int i = 0; i < 75; i++ ){
println("["+(i+1)+"] = " +v.get(i));
if ( tesuto.get( (int)v.get(i) -1 ) == true ){
return false;
} else {
tesuto.set((int)v.get(i)-1,true);
}
}
println("testBingoPermutation finished.");
return true;
}
・悪臭源:名称が不適切
一つ目の悪臭源は、
ファウラーのカタログでは、
メソッド名の変更
(Rename Method) メソッドが実行内容を正しく表していないので、
正しい名称に変更する。
Rename Method
まず、 次に宣言されているオブジェクトも残念です。 オブジェクト名をローマ字で宣言するのは止めましょう。 英語で宣言してあるから安心とは言えません。次のメソッドはすこし意味がずれています。 ビンゴ数列を作るメソッドの名称が マジックナンバーとは、 シンボリック定数によるマジックナンバーの置き換え マジックナンバーをシンボリック定数に置き換えることで、 Replace Magic Number with Symbolic Constant 例えば、 16進数リテラルで指定する場合、 この他、 取り上げた悪臭源である、 これまで述べていませんが、 sketch それぞれの項目で、 以下にリファクタリングを施したsketchを示します。読者の皆さんの取り組みと異なるところもあるでしょう。リファクタリング前後で振る舞いに違いがなく、
int tugi = 0;
tugi
とありますが、//ビンゴ数列を格納するオブジェクト
ArrayList <Integer> bingosuuretsu = new ArrayList<Integer>();
createBingoPermutation(bingosuuretsu);
・
draw
メソッドにはディスプレイウインドウ上に表示する各種要素の座標が必要になります。これを生の数値、void draw(){
if (TEST_
draw
メソッドで指定される背景色の値は、204
とせずDEFAULT_
としましょう。また、32
は、BINGO_
としましょう。もっと短く適当な名称があればそれで構いません。fill
メソッドで使用しているフォント色は、fill(0,102,153);
fill(0xFF006699);
FF
の桁はアルファ値static final int FONT_
static final
で定義しましょう。おっと、TEST_
もboolean型の定数なので、リファクタリング実行の手順
演習
演習1
BingoMachine.
をリファクタリングしてください。施すリファクタリングはまとめ
学習の確認
参考文献
演習解答