[[TopPage]] > 最終課題に向けて > 演習4-2 オセロの基礎2

* オセロの基礎2 [#rc5dd636]

** コマを置ける条件 [#z3f06a7b]

- オセロのコマを置ける条件についてまとめてみます.

+ 自分のターンである
+ 置く場所にコマがない
+ &color(red){置く場所から隣8方向のどこかに相手のコマがある};
+ &color(red){置くと,必ず相手のコマが1コ以上裏返る};

- 1は[[演習4-1>演習4-1 オセロの基礎1]]で,できました.
- 2も,押したボタンがboardIconかどうかを判断するだけなので,すぐできますね.
- 以降の3,4のプログラムは人それぞれです.
-- 難しいと思う人は,ここでその一例をご紹介します.
-- できそうな部分で参考をやめて,自分で書いていくのが良いですよ.

** 課題4・隣8方向の判定 [#n4f1df21]

- それでは,3の条件を追加してみましょう.
-- 押されたボタンがboardIconだと分かった後に,theArrayIndexをint型に変換します.
-- 変換した変数(下記ではindex)を使って,以下のように書いてください.
 if(judgeButton(index)){
   //置ける
   CLICK送信の処理
 } else {
   //置けない
   System.out.println("そこには配置できません");
 }

- judgeButtonは,これから新しく作る関数の名前です.
-- この関数の返り値はBoolean型です.置けたらtrue,置けないならfalseを返す関数です.

- では,mouseMovedの下に,新しい関数を追加します.
 public boolean judgeButton(int index){
   boolean flag = false;
   
   //色々な条件からflagをtrueにするか判断する
   
   return flag;
 }

- flagをtrueにする手順は,こうでしょうか.
++ 隣8方向に相手のコマがあるか,ひとつずつ見ていく
++ ひとつでもあれば,flagをtrueにする
- ここで,隣8方向の参照のしかたを下図に示します.

#ref(direction.png,nolink,center,75%)~
CENTER:図1. 隣8方向の求め方

- indexをx,y成分に分解できれば,buttonArray[y][x]の情報が参照できます.
- indexをx,y成分に分解できれば,buttonArray[y][x]を得るためのyとxの情報が参照できます.
-- このy,xをそれぞれ±1することで,まわりのボタンの情報も取ることができますね.
-- 効率の良いプログラムを作成するには,%%%iとjの二重for文で%%%自分(i=0,j=0)以外のコマを見ていく手順が良さそうです.
-- for文の中で,buttonArray[y+i][x+j]のアイコンがyourIconならばflagをtrueにします.

- あとは,端っこのボタンの処理です.端は8方向の範囲が場外に出るため,クリックするとエラーが出ると思います.
-- そこで,for文の中で増加するiとjの最小値または最大値を変えてあげればOKです.


** 課題5・ひっくり返す判定 [#x140b7ee]

- どのタイミングでひっくり返すかは人それぞれですが,ここでは置けるかどうかの判定ついでに一緒にやっちゃいます.

- 課題4の「アイコンがyourIconなら」という条件式に「flipButton()の返り値が0以上なら」を追加してください.
-- この2つがいずれも真の場合,flagをtrueにします.

- flipButtonは今から作る新しい関数です.仮引数にindex,j,iの3つを与えましょう.
-- 返り値はint型です.この関数は,ひっくり返したコマの個数を返します.
-- flipButtonの中身では,flagのような返り値用の変数flipNum = 0;も用意しておきます.

#br

- さて,相手のコマが何個ひっくり返るかを見るには,%%%同じ方向に何個連鎖(連続)して%%%ひっくり返るかを調べなければなりません.
-- flipButtonには,基準となるボタンの位置(index)と,ひっくり返る可能性のある方向成分(j,i)を渡します.
-- これらの情報があれば,''どこからどの方向に調べていくか''が分かりますね.

#ref(flipothello.png,nolink,center)~
CENTER:図2. 隣8方向の先の求め方

- 隣2マス以上に離れたボタンを調べるには,最初のj,iの値を使います.
-- (1, 0)→(2, 0)→(3, 0)…
-- (-1,-1)→(-2, -2)→(-3, -3)…
-- 上記を見ると,どの方向も,%%%最初のj,iを足し続ける%%%ことで遠いボタンの位置を把握できそうです.

#br

- 実引数のj,i値を,別の変数(dx, dy)を用意して代入してください.
-- 増分値dx,dyに固定値j,iを足し続けるようなループ文を作ります.

- ループの中身は,以下の処理の繰り返しになっていればOKです.

++ &color(red){x+dx,y+dyの位置が場外なら,flipNumを0にしてループを抜ける(判定中断)};
++ この位置のアイコンを取得する
++ アイコンの種類を見る
+++ &color(red){boardIconなら,flipNumを0にしてループを抜ける(判定中断)};
+++ &color(red){myIconなら,ループを抜ける(連鎖ストップ)};
+++ &color(red){yourIconなら,flipNumを1増やす(連鎖が続く)};
++ dx,dyそれぞれにj,iを足す

- こう書けば,ループを抜けた後のflipNumが,その方向でひっくり返すコマの個数になります.

#br

- 実際のひっくり返す処理は,上記のループから抜けた後(flipNumが1個以上あると確定した後)に書きましょう.
-- flipButton内に書く場合は,fliNumが1以上の時にこう書きます.
 //dx,dyを初期値にリセット
 dx = j;
 dy = i;
 
 for(int k = 0; k < flipNum; k++, dx+=j, dy+=i){
   //ボタンの位置情報を作る
   int msgx = x + dx;
   int msgy = y + dy;
   
   //サーバに情報を送る
   String msg = "FLIP"+" "+msgx+" "+msgy+" "+myColor;
   out.println(msg);
   out.flush();
 }
-- judgeButton内に書く場合は,上記のdx,dyを初期化の形に変更すればOKです.

** 課題6・置けなくなったの判定 [#v4015e20]

- オセロの公式ルールでは,自分のターンで必ず相手のコマをひっくり返します.
-- どこに置いてもひっくり返せない場合に,ターンのパスができます.パスに回数制限はありません.
-- 今回では,%%%自動でパスを発生させる,いつでもパスができるボタンを作る%%%,という方法がありますね.

#br

- ゲームの終了条件は,全てにコマが埋まるか,%%%両者とも置けなくなった%%%場合です.
-- ということはやはり,「これ以上コマを置けなくなった」判定が必要ですね.
-- CLICKをするたびに各boardIconのボタンの状況を探りましょう.
-- 両者とも置けなくなった時点で,各色のコマ数を数えて勝敗を決めます.

** おわりに [#kb41a157]

- 以上が最低限の提出できる''自動オセロ''プログラミングです.
-- 提出作品とする場合は,必ず%%%画像を自分で用意したものにしてください%%%.
-- ここから新機能を追加したり,ここで得た知識からほかのゲームの作成を目指せば,高得点につながります(たぶん).
-- そのほか,詳細の[[最終課題>提出課題]]ページをよく読んで,余裕のある課題作りを心掛けましょう!

#br

&size(16){[[&ref(http://yoslab.net/netprog/next.gif,nolink); 最終課題へ>提出課題]]};


トップ   一覧 単語検索 最終更新     最終更新のRSS