オセロ(その12)
さあ、ラストいきましょう。
コメントで人口無能と呼ばれたAIの登場です。
単純に配列を左端から 1列ずつ見ていって
board[x][y] = 0, かつ checkPiece(x, y, true)で置き、
もしも置けたら、turnChange関数に返すという流れのためこう呼ばれます。
たしかに思考しない思考ルーチンですが、
こんなことよくもまあ思いつくものだなあと感心です。
これを、そのまま書けばこんな感じになります。
しかしこれを 特殊な流れで行えば
歯ごたえのある対戦相手になるのではないでしょうか?
例えば、4隅(外枠)から探索していくならば結構強くなるのでは?
本当に今、急ごしらえで作ってみるとこんな感じです。
いろんなところがダブってて申し訳ありません。
あと、どうやらバグがありますね。
後日、ちゃんと考えます。
長かったですが、これにて完成です。
動画とは関数の並びが違ったり記述の内容も変えてしまいましたが
if文、for文、while文程度の知識があれば理解できるのではないでしょうか?
関数同士が複雑に絡み合うスパゲッティプログラムと
紀平さんもおっしゃっていますが、それにしても
これを1時間で作ってしまうというのは、ものスゴイ話ですよね。
テトリスに続いてFlashと、新しい動画もできているようです。
ああ、C++を勉強してからテトリスの解説か……。
でも、やっぱりプログラミングって面白いですね。
また、勉強して解説してみますので、どうぞよろしくお願いします。
ここで動画53:26~1:00:00までです。
お疲れ様でした。
コメントで人口無能と呼ばれたAIの登場です。
単純に配列を左端から 1列ずつ見ていって
board[x][y] = 0, かつ checkPiece(x, y, true)で置き、
もしも置けたら、turnChange関数に返すという流れのためこう呼ばれます。
たしかに思考しない思考ルーチンですが、
こんなことよくもまあ思いつくものだなあと感心です。
これを、そのまま書けばこんな感じになります。
![]() | ![]() ![]() ![]() ![]() ![]() ![]() | ![]() |
| メモ帳画像 (クリックで拡大) | ブラウザ画像 (クリックで拡大) |
しかしこれを 特殊な流れで行えば
歯ごたえのある対戦相手になるのではないでしょうか?
例えば、4隅(外枠)から探索していくならば結構強くなるのでは?
本当に今、急ごしらえで作ってみるとこんな感じです。
いろんなところがダブってて申し訳ありません。
あと、どうやらバグがありますね。
後日、ちゃんと考えます。
長かったですが、これにて完成です。
動画とは関数の並びが違ったり記述の内容も変えてしまいましたが
if文、for文、while文程度の知識があれば理解できるのではないでしょうか?
関数同士が複雑に絡み合うスパゲッティプログラムと
紀平さんもおっしゃっていますが、それにしても
これを1時間で作ってしまうというのは、ものスゴイ話ですよね。
テトリスに続いてFlashと、新しい動画もできているようです。
ああ、C++を勉強してからテトリスの解説か……。
でも、やっぱりプログラミングって面白いですね。
また、勉強して解説してみますので、どうぞよろしくお願いします。
ここで動画53:26~1:00:00までです。
お疲れ様でした。
オセロ(その11)
GAME OVERになって終了したので
白が何個、黒が何個で、どっちの勝ちかを判断します。
まずは turnChange関数の中で、カウント用の変数 b, w を宣言します。
紀平さんはこの変数を自分でアレンジしておきながら
忘れてバグを頻発させていましたが、
あるあるです。
というか、それらのバグをものすごい勢いで
発見していく様のほうが圧巻でした。
で、 1回パスが起きた後の for文でカウントさせます。
最後にそのメッセージを表示すれば終了です。
このプログラムなんですが、無駄なカウントが多い気がします。
ソースコードはあっさりしていますが、b, w のカウントに無駄があります
3項演算子がわかりにくかったので if文で書いてみました。
では、アラートでなく<div id = "board"></div>に
メッセージを入れて表示してみましょう。
紀平さんはここでいきなりinnerHTMLプロパティを使います。
私は面食らいましたが、JavaScriptでは当たり前の命令のようです。
まあ、オブジェクト指向なのでVBAみたいに知らないと使えない命令があるんですね。
アラートがあるほうが便利なので残しました。
これで人対人のオセロが完成になります。
前回と併せてここで動画30:42~53:26までです。
で、続きは次回へ。
白が何個、黒が何個で、どっちの勝ちかを判断します。
まずは turnChange関数の中で、カウント用の変数 b, w を宣言します。
紀平さんはこの変数を自分でアレンジしておきながら
忘れてバグを頻発させていましたが、
あるあるです。
というか、それらのバグをものすごい勢いで
発見していく様のほうが圧巻でした。
で、 1回パスが起きた後の for文でカウントさせます。
最後にそのメッセージを表示すれば終了です。
このプログラムなんですが、無駄なカウントが多い気がします。
ソースコードはあっさりしていますが、b, w のカウントに無駄があります
![]() | ![]() ![]() ![]() ![]() ![]() ![]() | ![]() |
| メモ帳画像 (クリックで拡大) | ブラウザ画像 (クリックで拡大) |
3項演算子がわかりにくかったので if文で書いてみました。
では、アラートでなく<div id = "board"></div>に
メッセージを入れて表示してみましょう。
紀平さんはここでいきなりinnerHTMLプロパティを使います。
私は面食らいましたが、JavaScriptでは当たり前の命令のようです。
まあ、オブジェクト指向なのでVBAみたいに知らないと使えない命令があるんですね。
![]() | ![]() ![]() ![]() ![]() ![]() ![]() | ![]() |
| メモ帳画像 (クリックで拡大) | ブラウザ画像 (クリックで拡大) |
アラートがあるほうが便利なので残しました。
これで人対人のオセロが完成になります。
前回と併せてここで動画30:42~53:26までです。
で、続きは次回へ。
オセロ(その10)
もう遊べることは遊べるのですが、
コマを置けない場合の「パス」ができません。
紀平さんはそのことに気づかれていましたが
私ならこの時点で完成にして満足していますね。
では、「パス」して、ターンを交代する turnChange関数を作ります。
これは、onclick関数中で動かしていくことにしましょう。
まず、 turnChange関数中に showBoard関数 と
turn = 3 - turn の働きを持たせて、
onclick関数に突っ込みます。
ひとまず、これで動かすことができますが、問題(?)があります。
このプログラムは全体の出発点が onload関数です。
しかし、turnChange関数は onclick関数の中だけしか記述されていません。
つまり、ボードが表示され、クリックされないとパスできないのです。
初期状態でいきなりパスすることはゲームの流れ上ありえませんが、
デバッグやらなんやらの都合上、困ることが多い気がします。
そこで、グローバル変数turnを初期値を決めずに宣言しておき、
onload関数の頭ですぐに 変数turn を 2(白)にします。
さらに、turnChange関数の頭に turn = 3 - turn をセット。
初期配置を決めたらいきなりturnChange関数を呼び出して
そこで初めてボードを表示するという手段をとります。
紀平さんはお気に召していませんがまあアリではないかなと思います。
それより私は、この後の turnChange関数の肥大ぶりが気にかかります。
では turnChange関数の中身に話を戻して、
コマを置ける猶予が全ボード中に存在するかを調べます。
つまり、board[x][y] を8×8で調査していって
1. それがboard[][] = 0 (何もおかれていないブロック)であり、かつ
2. checkPiece(x, y, false) (置いたら隣のどれかがひっくり返せる)
という条件のブロックがあれば
showBoard関数に値をリターンして
続行(ふたたびonclick待ち)という流れ。
上記のこれは置けた場合の動きです。
この流れが働かないという場合は、置ける場所がないのです。
よって、パスと表示させて新たに turn = 3 - turn させます。
さらに、置ける猶予があるかどうかをチェックして
(for文で全配列を回して checkPiece() && board[][] == 0)
置ければ問題ないが、猶予がなくパスが 2連続で起きたら終了する。
それが以下のソースになります。
勝敗判定と新たな<メッセージ>の処理は次にまわすことにして。
アラート表示によるパスの仕組みができあがりました。
今回は私が説明しやすいようにオリジナルです。
で、続きは次回へ。
コマを置けない場合の「パス」ができません。
紀平さんはそのことに気づかれていましたが
私ならこの時点で完成にして満足していますね。
では、「パス」して、ターンを交代する turnChange関数を作ります。
これは、onclick関数中で動かしていくことにしましょう。
まず、 turnChange関数中に showBoard関数 と
turn = 3 - turn の働きを持たせて、
onclick関数に突っ込みます。
ひとまず、これで動かすことができますが、問題(?)があります。
このプログラムは全体の出発点が onload関数です。
しかし、turnChange関数は onclick関数の中だけしか記述されていません。
つまり、ボードが表示され、クリックされないとパスできないのです。
初期状態でいきなりパスすることはゲームの流れ上ありえませんが、
デバッグやらなんやらの都合上、困ることが多い気がします。
そこで、グローバル変数turnを初期値を決めずに宣言しておき、
onload関数の頭ですぐに 変数turn を 2(白)にします。
さらに、turnChange関数の頭に turn = 3 - turn をセット。
初期配置を決めたらいきなりturnChange関数を呼び出して
そこで初めてボードを表示するという手段をとります。
紀平さんはお気に召していませんがまあアリではないかなと思います。
それより私は、この後の turnChange関数の肥大ぶりが気にかかります。
では turnChange関数の中身に話を戻して、
コマを置ける猶予が全ボード中に存在するかを調べます。
つまり、board[x][y] を8×8で調査していって
1. それがboard[][] = 0 (何もおかれていないブロック)であり、かつ
2. checkPiece(x, y, false) (置いたら隣のどれかがひっくり返せる)
という条件のブロックがあれば
showBoard関数に値をリターンして
続行(ふたたびonclick待ち)という流れ。
上記のこれは置けた場合の動きです。
この流れが働かないという場合は、置ける場所がないのです。
よって、パスと表示させて新たに turn = 3 - turn させます。
さらに、置ける猶予があるかどうかをチェックして
(for文で全配列を回して checkPiece() && board[][] == 0)
置ければ問題ないが、猶予がなくパスが 2連続で起きたら終了する。
それが以下のソースになります。
![]() | ![]() ![]() ![]() ![]() ![]() ![]() | ![]() |
| メモ帳画像 (クリックで拡大) | ブラウザ画像 (クリックで拡大) |
勝敗判定と新たな<メッセージ>の処理は次にまわすことにして。
アラート表示によるパスの仕組みができあがりました。
今回は私が説明しやすいようにオリジナルです。
で、続きは次回へ。
オセロ(その9)
マスにコマが置けるようになりましたら、
挟んだコマをひっくり返しましょう。
ひとまず、いま置かれたブロックを中心にして
周囲に別の色が置かれたブロックがあるかどうかをチェックします。
これが checkOkeru関数、じゃなかった checkPiece関数なわけですね。
変数名やら関数名が yokujituとか seitoCountとかよくある話です。
後日見て意味や働きががわかるように自作関数には日本語と英語が混ざります。
まあ、そうは言っても、私の場合は間違いなく英語の勉強をしたほうがいいですけどね。
関数中の引数 flip には onclick関数で true を代入。
で、ひっくり返せる枚数 ret に 0以外が返ってくれば動きます。
if (checkPiece(_x, _y, true)) { }; っていうのはそういうことですよね。
わかりにくい部分ですが頑張りましょう。
クリックされると checkPiece関数を呼び出して flip に true が代入されます。
結果、裏返せる枚数(全部の n の数)である ret がリターンされますが
それが 0 じゃなければ(返せるコマがあれば)動きます。
いっぽう、変数に turn(1:黒, 2:白) を用意します。
そして、9個の配列[dx][dy]を使って検索するわけです。
中心(置いたブロック)はスルーさせます。
そして、将来的には x += dx, y += dy と見ていくことで
特定のブロックから放射状にブロックをチェックしていけるようになります。
ようするに、x += dx は x = x + dxで,
y += dy は y = y + dy なので、
《[-1][-1]方向なら》
[x+(-1)][y+(-1)] --> [(x-1)+(-1)][(y-1)+(-1)] --> ……、
と左斜め上方向へ。
《[ 0][+1]方向なら》
[x+( 0)][y+(+1)] --> [(x+0)+( 0)][(y+1)+(+1)] --> ……、
と垂直に下方向へ。
1) 方向を決める。
2) その方向を探索する。
3) ひっくり返せるならその枚数をretに。
4) 別の方向に変える。→ 2)へ
と検索していけるというわけです。
こうして配列の値が 1か 2かを見ていくんですね。
(シューティングゲームの弾の動きを勉強するともっと色々できそうな予感です)
で、置いたブロックに隣接するかたちで違うブロックが置かれていて、
かつ検索の結果、最終的に置いたブロックと同じ色のブロックが出てくれば
最初に置こうと思った場所に Okeruという考え方です。
これを onclick関数に組み込むことでチェックできます
(実際にはひっくり返すまでやります)
置いて裏返ってターン交代までいけました。
今回作られたcheckPiece関数の flip が false なら
そこにはコマが置ける猶予があるということを覚えておきましょう。
ここで動画21:08~30:42までです。
で、続きは次回へ。
挟んだコマをひっくり返しましょう。
ひとまず、いま置かれたブロックを中心にして
周囲に別の色が置かれたブロックがあるかどうかをチェックします。
これが checkOkeru関数、じゃなかった checkPiece関数なわけですね。
変数名やら関数名が yokujituとか seitoCountとかよくある話です。
後日見て意味や働きががわかるように自作関数には日本語と英語が混ざります。
まあ、そうは言っても、私の場合は間違いなく英語の勉強をしたほうがいいですけどね。
関数中の引数 flip には onclick関数で true を代入。
で、ひっくり返せる枚数 ret に 0以外が返ってくれば動きます。
if (checkPiece(_x, _y, true)) { }; っていうのはそういうことですよね。
わかりにくい部分ですが頑張りましょう。
クリックされると checkPiece関数を呼び出して flip に true が代入されます。
結果、裏返せる枚数(全部の n の数)である ret がリターンされますが
それが 0 じゃなければ(返せるコマがあれば)動きます。
いっぽう、変数に turn(1:黒, 2:白) を用意します。
そして、9個の配列[dx][dy]を使って検索するわけです。
| [-1][-1], | [-1][ 0], | [-1][+1], |
| [ 0][-1], | [ 0][ 0], | [ 0][+1], |
| [+1][-1], | [+1][ 0], | [+1][+1]; |
中心(置いたブロック)はスルーさせます。
そして、将来的には x += dx, y += dy と見ていくことで
特定のブロックから放射状にブロックをチェックしていけるようになります。
ようするに、x += dx は x = x + dxで,
y += dy は y = y + dy なので、
《[-1][-1]方向なら》
[x+(-1)][y+(-1)] --> [(x-1)+(-1)][(y-1)+(-1)] --> ……、
と左斜め上方向へ。
《[ 0][+1]方向なら》
[x+( 0)][y+(+1)] --> [(x+0)+( 0)][(y+1)+(+1)] --> ……、
と垂直に下方向へ。
1) 方向を決める。
2) その方向を探索する。
3) ひっくり返せるならその枚数をretに。
4) 別の方向に変える。→ 2)へ
| [-1-1][-1-1], | [-1-1][ 0+0], | [-1-1][+1+1], | ||
| [-1][-1], | [-1][ 0], | [-1][+1], | ||
| [ 0+0][-1-1], | [ 0][-1], | [ 0][ 0], | [ 0][+1], | [ 0+0][+1+1], |
| [+1][-1], | [+1][ 0], | [+1][+1], | ||
| [+1+1][-1-1], | [+1+1][ 0+0], | [+1+1][+1+1]; |
と検索していけるというわけです。
こうして配列の値が 1か 2かを見ていくんですね。
(シューティングゲームの弾の動きを勉強するともっと色々できそうな予感です)
で、置いたブロックに隣接するかたちで違うブロックが置かれていて、
かつ検索の結果、最終的に置いたブロックと同じ色のブロックが出てくれば
最初に置こうと思った場所に Okeruという考え方です。
これを onclick関数に組み込むことでチェックできます
(実際にはひっくり返すまでやります)
![]() | ![]() ![]() ![]() ![]() ![]() ![]() | ![]() |
| メモ帳画像 (クリックで拡大) | ブラウザ画像 (クリックで拡大) |
置いて裏返ってターン交代までいけました。
今回作られたcheckPiece関数の flip が false なら
そこにはコマが置ける猶予があるということを覚えておきましょう。
ここで動画21:08~30:42までです。
で、続きは次回へ。
オセロ(その8)
元となる盤を眺めておりますと、
クリックしたい衝動に駆られるのが人の性です。
では、「何も置かれていない」ブロックをクリックしたら
したところを「黒が置かれた」ブロックに変わるようにします。
で、紀平さんはしばし考えてから
「クロージャを使って解決しましょう」とつぶやきます。
ああ、私にはさっぱり理解できないクロージャさんの登場です。
なんか関数を使って書いたら変数に値が保持されるような
そんなもやっと適当な知識しかないクロージャの登場です。
ここまでもそうですが、ここからだいぶ私の妄想で解説します。
あ、今さら言うのも何ですが、ここまでもほとんど私の妄想で解説しています。
まず、紀平さんは当たり前のように showBoard関数の for文の途中に
onclick関数を作りますが、私は「あーそこに作ればいいのか」と
導入部から感心しました。
そして、え~と、_x と _yが値を保持するのはわかりますが、
配列のboard[_x][_y]までもが値を保持しているように見えますよね。
まったくクロージャがわからない私には魔法のようです。
クロージャはshowBoard関数に値を返しているだけで
var board = []が関数の外で宣言されているから
変えた値が残るだけなのでしょうか?
わかる方がいたら教えていただきたいです。
ただ、onclick関数によってクリックされた場所の配列の値が 1(黒)に変更されて、
それがshowBoard関数によって表示されている様はわかりますよね。
ここで動画19:06~21:08までです。
今回はこんな感じで逃げます。続きは次回。
クリックしたい衝動に駆られるのが人の性です。
では、「何も置かれていない」ブロックをクリックしたら
したところを「黒が置かれた」ブロックに変わるようにします。
で、紀平さんはしばし考えてから
「クロージャを使って解決しましょう」とつぶやきます。
ああ、私にはさっぱり理解できないクロージャさんの登場です。
なんか関数を使って書いたら変数に値が保持されるような
そんなもやっと適当な知識しかないクロージャの登場です。
ここまでもそうですが、ここからだいぶ私の妄想で解説します。
あ、今さら言うのも何ですが、ここまでもほとんど私の妄想で解説しています。
![]() | ![]() ![]() ![]() ![]() ![]() ![]() | ![]() |
| メモ帳画像 (クリックで拡大) | ブラウザ画像 (クリックで拡大) |
まず、紀平さんは当たり前のように showBoard関数の for文の途中に
onclick関数を作りますが、私は「あーそこに作ればいいのか」と
導入部から感心しました。
そして、え~と、_x と _yが値を保持するのはわかりますが、
配列のboard[_x][_y]までもが値を保持しているように見えますよね。
まったくクロージャがわからない私には魔法のようです。
クロージャはshowBoard関数に値を返しているだけで
var board = []が関数の外で宣言されているから
変えた値が残るだけなのでしょうか?
わかる方がいたら教えていただきたいです。
ただ、onclick関数によってクリックされた場所の配列の値が 1(黒)に変更されて、
それがshowBoard関数によって表示されている様はわかりますよね。
ここで動画19:06~21:08までです。
今回はこんな感じで逃げます。続きは次回。

















