演習4-2 オセロの基礎2
をテンプレートにして作成
開始行:
[[TopPage]] > 最終課題に向けて > 演習4-2 オセロの基礎2
* オセロの基礎2 [#rc5dd636]
** コマを置ける条件 [#z3f06a7b]
- オセロのコマを置ける条件についてまとめてみます.
+ 自分のターンである
+ 置く場所にコマがない
+ &color(red){置くと,必ず相手のコマが1コ以上裏返る};
- 条件1は[[演習4-1>演習4-1 オセロの基礎1]]で,できました...
- 条件2も,押したボタンがboardIconかどうかを判断するだけ...
-- いまのプログラムは,自分の番のときに,相手のコマを自分...
-- ここで書き換えてみましょう.
-- 書き換える場所は,もちろん,mouseClickedのところです.
-- いまは,自分の番のときだけプログラムが実行されるように...
-- Icon theIcon = theButton.getIcon();の結果をみて,theIc...
-- 書き換えたら,動作確認してください.
--- 自分の番のときに,相手のコマを自分の色に出来なくなり...
- 条件3のプログラムは,色々なアルゴリズムが考えられると思...
-- 難しいと思う人は,ここでその一例をご紹介します.
-- できそうな部分で参考をやめて,自分で書いていくのが良い...
--- かなり詳細な説明になっていますので,プログラムに自信...
** 課題4・隣8方向の判定 [#n4f1df21]
- 押されたボタンがboardIconだと分かった後に,そのボタンの...
-- theArrayIndexは文字(String)なので,数字への変換が必...
-- theArrayIndexを数字にしたものをtemp(という変数,int型...
- 次に,temp(theArrayIndexを数字にしたもの)をy成分とx成...
-- %8や/8を使う方法でy成分とx成分になりますね(演習4-1...
-- xとyという変数も新しく作ります.
- xとyを用いて,以下のように書いてください.
if(judgeButton(y, x)){
//置ける
<<PLACE命令の送信>>
} else {
//置けない
System.out.println("そこには配置できません");
}
- <<PLACE命令の送信>>はすでに書いている部分が入ります.
- judgeButtonは,これから新しく作る関数の名前です.
|&size(14){関数 ''judgeButton''};|
|裏返りの発生するボタンであるかどうかを判定する|
|%%%引数1%%% y ボタンのy位置(0-7)&br;%%%引数2%%% x ボタ...
|%%%返り値%%% 判定(TF)|
-- この関数の返り値はBoolean型です.指定した位置について...
- では,mouseMovedの下に,新しい関数を追加します.
public boolean judgeButton(int y, int x){
boolean flag = false;
//色々な条件からflagをtrueにするか判断する
return flag;
}
- それでは,judgeButtonの中身を書いていきましょう.
- flagをtrueにする手順は複雑ですが,まずはこのような条件...
-- flagというのは「旗」ですね.コンピュータのプログラムで...
--- flagは,ある条件を満たしたかどうかを,あとで確認する...
--- 使い方としては最初,旗を下げておく(flag = false)に...
--- プログラムの別の部分で,flagがtrueかfalseかを見ること...
++ 隣8方向に相手のコマがあるか,ひとつずつ見ていく
++ ひとつでもあれば,flagをtrueにする
- ここで,隣8方向の参照のしかたを下図に示します.
#ref(direction_2.png,nolink,center,75%)~
CENTER:図1. 隣8方向の求め方
- buttonArray[y][x]を用いると,クリックされたボタンの情報...
-- このy,xをそれぞれ±1することで,周りのボタンの情報も取...
- 効率の良いプログラムを作成するには,指定の位置を(0,0)と...
-- iとjの''二重for文''から,%%%自分(j=0,i=0)以外の%%%まわ...
--- まず,iとjの二重for文を書いてみて下さい.
--- iとjの範囲は分かりますか?図1をみてください.iもjも,...
-- for文の中で,buttonArray[y+j][x+i]のアイコンがyourIcon...
--- そのfor文の中で,buttonArray[y+j][x+i]のアイコンを調...
--- iconが何かはgetIconを使うと分かりますね.
--- ここでは,iconが,yourIconの場合には,コマをおける(f...
- この段階で,メッセージを出しながらデバッグ(テスト)を...
-- 相手のコマがまわりのどこかにある時に,自分のコマが置け...
--- まだ,オセロのひっくり返るなどの判断はできていません...
-- まったくひっくり返らないや正しく判定しない場合には,メ...
--- 例えば,judgeButtonのfor文の中で,iconが正しくとれて...
--- 下記はメッセージを出す例です.theIconなどの変数は自分...
System.out.println("y+j="+(y+j)+", x+i="+(x+i));~
System.out.println("theIcon="+theIcon+", yourIcon="+your...
--- よくある間違いとしては,xとyが逆だったというものです.
--- その場合,それっぽい動きはするのですが,隣接していな...
- なお,端っこのボタンにコマを置こうとすると,エラーが発...
-- 8方向の範囲に場外を含むことで,配列が-1や8を参照してし...
-- この問題は,あとで対応するとします.
** 課題5・ひっくり返す判定 [#x140b7ee]
- いよいよ,挟まれた相手のコマをひっくり返す判定に移りま...
- 課題4の「アイコンがyourIconなら」という条件を,「flipB...
-- flipButtons()とは書いていますが,()の中にはちゃんと''...
-- flipButtonsは,「ある条件」でひっくり返るかどうかを調...
- flipButtonsは今から作る新しい関数です.仮引数にy,x,j,i...
|&size(14){関数 ''flipButtons''};|
|一方向にあるコマ群を裏返す命令を送る|
|%%%引数1%%% y ボタンのy位置(0-7)&br;%%%引数2%%% x ボタ...
|%%%返り値%%% 裏返ったコマの数|
-- 返り値はint型です.この関数は,指定した位置と方向につ...
-- flipButtonsの中身では,flagのような返り値用の変数flipN...
-- では,judgeButtonの下に,新しい関数flipButtonsを追加し...
-- 書き方は,ほぼjudgeButtonと同じですが,戻り値が数字(i...
--- flipButtonsは関数です.その関数の中のみで利用している...
--- 変数スコープ[演習1-6 関数の定義と変数のスコープ]を再...
#br
- さて,相手のコマが何個ひっくり返るかを見るには,%%%同じ...
-- flipButtonsには,基準となるボタンの絶対位置(y,x)と,...
-- これらの情報があれば,''どこからどの方向に調べていくか...
#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
- それでは,変数dy,dxを用意して,固定値j,iを足し続けるよ...
-- y+dyの値が,調べたいボタンの絶対位置になるようにします.
- というわけで,少し変わったfor文の書き方をしてみます.ど...
for(int dy=j, dx=i; ; dy+=j, dx+=i) {
...
}
- わかりました?
-- for文は,「初期化式; 継続条件式; 再初期化式」の順に書...
-- 「2つの変数について初期化できる点」「これらの式は省略...
-- ただし,このままでは永遠に継続してしまうので,どこかで...
-- さらに,このfor文をにらんでみると「 dy+=j, dx+=i」があ...
--- もし,jとiが0だったら,どうなりますか?この対応も必...
- このfor文の中身は,以下のようになっていればOKです.
++ &color(red){y+dy,x+dxの位置が場外なら,この関数は0を返...
++ この位置のアイコンを取得する
++ アイコンの種類を見る
+++ &color(red){boardIconなら,この関数は0を返す(判定終了...
+++ &color(red){myIconなら,この関数はflipNumを返す(連鎖...
+++ &color(red){yourIconなら,flipNumを1増やす(連鎖が続く...
- ちょっと説明します.
-- 1方向に突き進んでいき,連続して相手のコマがある限りは...
-- その道中,自分のコマにぶつかったら,「return flipNum」...
-- ただし,その道中にboardIconがあったり,自分のコマが見...
#br
- ここまでうまくできると,オセロのルール通りに置けるとこ...
- まだひっくり返す処理は書いていませんので,正しくおける...
- ''うまくいかない場合''
-- JudgeButtonと同様に,flipButtonsの中で,メッセージを出...
-- エラーが「java.lang.ArrayIndexOutOfBoundsException」が...
--- 例えば,buttonArray[y+dy][x+dx]を使っている場合,y+dy...
-- 無限ループのエラーになる場合は,xとyの参照を間違えてい...
- flipButtonsはひっくり返す数を調べていましたが,ひっくり...
- 実際のひっくり返す命令は,%%%flipNumが1以上%%%の時に,...
- さらに,このfor文をにらんでみると「 dy+=j, dx+=i」があ...
-- もし,jとiが0だったら,どうなりますか?この対応も必要...
for(int dy=j, dx=i, k=0; k<flipNum; k++, dy+=j, dx+=i){
//ボタンの位置情報を作る
int msgy = y + dy;
int msgx = x + dx;
int theArrayIndex = msgy*8 + msgx;
//サーバに情報を送る
String msg = "FLIP"+" "+theArrayIndex+" "+myColor;
out.println(msg);
out.flush();
}
-- judgeButton,flipButtons内のどちらかに追記しましょう....
--- judgeButtonの中に書く場合には,flipButtonsを呼び出し...
//--- flipButtonsのの中に書く場合には,連鎖ストップ時(re...
- あとは,FLIP命令の受信部分を,PLACEのように書くだけです.
-- 受信部分は,run()の部分ですね.
-- FLIPとPLACEは送り方は同じで,FLIPとPLACEの部分がことな...
--- もし,PLACE部分にmyTurn = 1 - myTurnがあった場合FLIP...
- ここまでできると,ひっくり返る処理ができていますので,...
** 課題6・ゲームの終了と勝敗判定 [#v4015e20]
- オセロの公式ルールでは,自分のターンで必ず相手のコマを...
-- どこに置いてもひっくり返せない場合に,ターンのパスがで...
-- ゲームの終了条件は,全てにコマが埋まるか,%%%両者とも...
- %%%自動でパスを発生させるか,いつでもパスができるボタン...
-- 実際には,「自動でパス」はちょっぴり難しいので,まずは...
--- 「いつでもパスができるボタン」が簡単にできたら,「自...
--- 「これ以上コマを置けなくなった」(パスの自動判定)の...
--- 自動パスは,judgeButton,flipButtonsと同じようなもの...
--- 自動パスのためには,全滅の手順を知っているとデバッグ...
--- [[全滅の手順:http://uguisu.skr.jp/othello/lose_min.ht...
- 勝敗判定について
-- 両者とも置けなくなった時点で,各色のコマ数を数えて勝敗...
-- これも実質は,自動パスができないと難しいので,ここでは...
-- 「boardIconの数が0になったとき」と「パスボタンが連続で...
--- 「お互いにパスが連続したら勝敗の判定に移る」というル...
--- 連続なので,パスの数をカウントする変数を使います.
--- 一度でもおけたら,カウントしょを初期化(=0)します.
-- 「全てのコマが埋まったらすぐに勝敗判定に移る」機能は付...
** おわりに [#kb41a157]
- ここまでできたら,とりあえず提出できる''自動オセロ''と...
-- 提出作品とする場合は,必ず%%%画像を自分で用意したもの...
-- ここから新機能を追加したり,ここで得た知識からほかのゲ...
-- そのほか,詳細の[[最終課題]]ページをよく読んで,余裕の...
- 残された追加機能は下記でしょうか?
-- 初期化機能(もう一回,最初からオセロを始めるための機能...
#br
&size(16){[[&ref(http://yoslab.net/netprog/next.gif,nolin...
終了行:
[[TopPage]] > 最終課題に向けて > 演習4-2 オセロの基礎2
* オセロの基礎2 [#rc5dd636]
** コマを置ける条件 [#z3f06a7b]
- オセロのコマを置ける条件についてまとめてみます.
+ 自分のターンである
+ 置く場所にコマがない
+ &color(red){置くと,必ず相手のコマが1コ以上裏返る};
- 条件1は[[演習4-1>演習4-1 オセロの基礎1]]で,できました...
- 条件2も,押したボタンがboardIconかどうかを判断するだけ...
-- いまのプログラムは,自分の番のときに,相手のコマを自分...
-- ここで書き換えてみましょう.
-- 書き換える場所は,もちろん,mouseClickedのところです.
-- いまは,自分の番のときだけプログラムが実行されるように...
-- Icon theIcon = theButton.getIcon();の結果をみて,theIc...
-- 書き換えたら,動作確認してください.
--- 自分の番のときに,相手のコマを自分の色に出来なくなり...
- 条件3のプログラムは,色々なアルゴリズムが考えられると思...
-- 難しいと思う人は,ここでその一例をご紹介します.
-- できそうな部分で参考をやめて,自分で書いていくのが良い...
--- かなり詳細な説明になっていますので,プログラムに自信...
** 課題4・隣8方向の判定 [#n4f1df21]
- 押されたボタンがboardIconだと分かった後に,そのボタンの...
-- theArrayIndexは文字(String)なので,数字への変換が必...
-- theArrayIndexを数字にしたものをtemp(という変数,int型...
- 次に,temp(theArrayIndexを数字にしたもの)をy成分とx成...
-- %8や/8を使う方法でy成分とx成分になりますね(演習4-1...
-- xとyという変数も新しく作ります.
- xとyを用いて,以下のように書いてください.
if(judgeButton(y, x)){
//置ける
<<PLACE命令の送信>>
} else {
//置けない
System.out.println("そこには配置できません");
}
- <<PLACE命令の送信>>はすでに書いている部分が入ります.
- judgeButtonは,これから新しく作る関数の名前です.
|&size(14){関数 ''judgeButton''};|
|裏返りの発生するボタンであるかどうかを判定する|
|%%%引数1%%% y ボタンのy位置(0-7)&br;%%%引数2%%% x ボタ...
|%%%返り値%%% 判定(TF)|
-- この関数の返り値はBoolean型です.指定した位置について...
- では,mouseMovedの下に,新しい関数を追加します.
public boolean judgeButton(int y, int x){
boolean flag = false;
//色々な条件からflagをtrueにするか判断する
return flag;
}
- それでは,judgeButtonの中身を書いていきましょう.
- flagをtrueにする手順は複雑ですが,まずはこのような条件...
-- flagというのは「旗」ですね.コンピュータのプログラムで...
--- flagは,ある条件を満たしたかどうかを,あとで確認する...
--- 使い方としては最初,旗を下げておく(flag = false)に...
--- プログラムの別の部分で,flagがtrueかfalseかを見ること...
++ 隣8方向に相手のコマがあるか,ひとつずつ見ていく
++ ひとつでもあれば,flagをtrueにする
- ここで,隣8方向の参照のしかたを下図に示します.
#ref(direction_2.png,nolink,center,75%)~
CENTER:図1. 隣8方向の求め方
- buttonArray[y][x]を用いると,クリックされたボタンの情報...
-- このy,xをそれぞれ±1することで,周りのボタンの情報も取...
- 効率の良いプログラムを作成するには,指定の位置を(0,0)と...
-- iとjの''二重for文''から,%%%自分(j=0,i=0)以外の%%%まわ...
--- まず,iとjの二重for文を書いてみて下さい.
--- iとjの範囲は分かりますか?図1をみてください.iもjも,...
-- for文の中で,buttonArray[y+j][x+i]のアイコンがyourIcon...
--- そのfor文の中で,buttonArray[y+j][x+i]のアイコンを調...
--- iconが何かはgetIconを使うと分かりますね.
--- ここでは,iconが,yourIconの場合には,コマをおける(f...
- この段階で,メッセージを出しながらデバッグ(テスト)を...
-- 相手のコマがまわりのどこかにある時に,自分のコマが置け...
--- まだ,オセロのひっくり返るなどの判断はできていません...
-- まったくひっくり返らないや正しく判定しない場合には,メ...
--- 例えば,judgeButtonのfor文の中で,iconが正しくとれて...
--- 下記はメッセージを出す例です.theIconなどの変数は自分...
System.out.println("y+j="+(y+j)+", x+i="+(x+i));~
System.out.println("theIcon="+theIcon+", yourIcon="+your...
--- よくある間違いとしては,xとyが逆だったというものです.
--- その場合,それっぽい動きはするのですが,隣接していな...
- なお,端っこのボタンにコマを置こうとすると,エラーが発...
-- 8方向の範囲に場外を含むことで,配列が-1や8を参照してし...
-- この問題は,あとで対応するとします.
** 課題5・ひっくり返す判定 [#x140b7ee]
- いよいよ,挟まれた相手のコマをひっくり返す判定に移りま...
- 課題4の「アイコンがyourIconなら」という条件を,「flipB...
-- flipButtons()とは書いていますが,()の中にはちゃんと''...
-- flipButtonsは,「ある条件」でひっくり返るかどうかを調...
- flipButtonsは今から作る新しい関数です.仮引数にy,x,j,i...
|&size(14){関数 ''flipButtons''};|
|一方向にあるコマ群を裏返す命令を送る|
|%%%引数1%%% y ボタンのy位置(0-7)&br;%%%引数2%%% x ボタ...
|%%%返り値%%% 裏返ったコマの数|
-- 返り値はint型です.この関数は,指定した位置と方向につ...
-- flipButtonsの中身では,flagのような返り値用の変数flipN...
-- では,judgeButtonの下に,新しい関数flipButtonsを追加し...
-- 書き方は,ほぼjudgeButtonと同じですが,戻り値が数字(i...
--- flipButtonsは関数です.その関数の中のみで利用している...
--- 変数スコープ[演習1-6 関数の定義と変数のスコープ]を再...
#br
- さて,相手のコマが何個ひっくり返るかを見るには,%%%同じ...
-- flipButtonsには,基準となるボタンの絶対位置(y,x)と,...
-- これらの情報があれば,''どこからどの方向に調べていくか...
#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
- それでは,変数dy,dxを用意して,固定値j,iを足し続けるよ...
-- y+dyの値が,調べたいボタンの絶対位置になるようにします.
- というわけで,少し変わったfor文の書き方をしてみます.ど...
for(int dy=j, dx=i; ; dy+=j, dx+=i) {
...
}
- わかりました?
-- for文は,「初期化式; 継続条件式; 再初期化式」の順に書...
-- 「2つの変数について初期化できる点」「これらの式は省略...
-- ただし,このままでは永遠に継続してしまうので,どこかで...
-- さらに,このfor文をにらんでみると「 dy+=j, dx+=i」があ...
--- もし,jとiが0だったら,どうなりますか?この対応も必...
- このfor文の中身は,以下のようになっていればOKです.
++ &color(red){y+dy,x+dxの位置が場外なら,この関数は0を返...
++ この位置のアイコンを取得する
++ アイコンの種類を見る
+++ &color(red){boardIconなら,この関数は0を返す(判定終了...
+++ &color(red){myIconなら,この関数はflipNumを返す(連鎖...
+++ &color(red){yourIconなら,flipNumを1増やす(連鎖が続く...
- ちょっと説明します.
-- 1方向に突き進んでいき,連続して相手のコマがある限りは...
-- その道中,自分のコマにぶつかったら,「return flipNum」...
-- ただし,その道中にboardIconがあったり,自分のコマが見...
#br
- ここまでうまくできると,オセロのルール通りに置けるとこ...
- まだひっくり返す処理は書いていませんので,正しくおける...
- ''うまくいかない場合''
-- JudgeButtonと同様に,flipButtonsの中で,メッセージを出...
-- エラーが「java.lang.ArrayIndexOutOfBoundsException」が...
--- 例えば,buttonArray[y+dy][x+dx]を使っている場合,y+dy...
-- 無限ループのエラーになる場合は,xとyの参照を間違えてい...
- flipButtonsはひっくり返す数を調べていましたが,ひっくり...
- 実際のひっくり返す命令は,%%%flipNumが1以上%%%の時に,...
- さらに,このfor文をにらんでみると「 dy+=j, dx+=i」があ...
-- もし,jとiが0だったら,どうなりますか?この対応も必要...
for(int dy=j, dx=i, k=0; k<flipNum; k++, dy+=j, dx+=i){
//ボタンの位置情報を作る
int msgy = y + dy;
int msgx = x + dx;
int theArrayIndex = msgy*8 + msgx;
//サーバに情報を送る
String msg = "FLIP"+" "+theArrayIndex+" "+myColor;
out.println(msg);
out.flush();
}
-- judgeButton,flipButtons内のどちらかに追記しましょう....
--- judgeButtonの中に書く場合には,flipButtonsを呼び出し...
//--- flipButtonsのの中に書く場合には,連鎖ストップ時(re...
- あとは,FLIP命令の受信部分を,PLACEのように書くだけです.
-- 受信部分は,run()の部分ですね.
-- FLIPとPLACEは送り方は同じで,FLIPとPLACEの部分がことな...
--- もし,PLACE部分にmyTurn = 1 - myTurnがあった場合FLIP...
- ここまでできると,ひっくり返る処理ができていますので,...
** 課題6・ゲームの終了と勝敗判定 [#v4015e20]
- オセロの公式ルールでは,自分のターンで必ず相手のコマを...
-- どこに置いてもひっくり返せない場合に,ターンのパスがで...
-- ゲームの終了条件は,全てにコマが埋まるか,%%%両者とも...
- %%%自動でパスを発生させるか,いつでもパスができるボタン...
-- 実際には,「自動でパス」はちょっぴり難しいので,まずは...
--- 「いつでもパスができるボタン」が簡単にできたら,「自...
--- 「これ以上コマを置けなくなった」(パスの自動判定)の...
--- 自動パスは,judgeButton,flipButtonsと同じようなもの...
--- 自動パスのためには,全滅の手順を知っているとデバッグ...
--- [[全滅の手順:http://uguisu.skr.jp/othello/lose_min.ht...
- 勝敗判定について
-- 両者とも置けなくなった時点で,各色のコマ数を数えて勝敗...
-- これも実質は,自動パスができないと難しいので,ここでは...
-- 「boardIconの数が0になったとき」と「パスボタンが連続で...
--- 「お互いにパスが連続したら勝敗の判定に移る」というル...
--- 連続なので,パスの数をカウントする変数を使います.
--- 一度でもおけたら,カウントしょを初期化(=0)します.
-- 「全てのコマが埋まったらすぐに勝敗判定に移る」機能は付...
** おわりに [#kb41a157]
- ここまでできたら,とりあえず提出できる''自動オセロ''と...
-- 提出作品とする場合は,必ず%%%画像を自分で用意したもの...
-- ここから新機能を追加したり,ここで得た知識からほかのゲ...
-- そのほか,詳細の[[最終課題]]ページをよく読んで,余裕の...
- 残された追加機能は下記でしょうか?
-- 初期化機能(もう一回,最初からオセロを始めるための機能...
#br
&size(16){[[&ref(http://yoslab.net/netprog/next.gif,nolin...
ページ名: