[[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]の情報が参照できます. -- この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); 最終課題へ>提出課題]]};