インタラクティブ・ゲーム制作 <プログラミングコース> 第9回 対戦版オセロの完成 (闇魔術入門) 授業のリスケジュール • 最終回に海外出張が 入る可能性大 – SIGGRAPH2013 – 補講はちょっと 難しい…… • 土曜日? • ニコ生? • コードレビューの 代わりにKinect体験 • Boostか数学で悩む 9. 対戦版オセロ完成 10.Kinect体験 11.Boost or 数学 12.AIレクチャー 13.オセロAI対決 14.(休講) 今日の内容 • 対戦ツールとしての機能を完成させる – 挟んで部分がひっくり返れば対戦はできる – 後は置けない判定&決着判定 • C++の闇魔術をちょこっと体験する – 演算子再定義(オペレータオーバーロード) 本日のメインディッシュ 置ける場所とひっくり返し判定 置ける場所の定義(1) • 置くことで ひっくり返せること – そのためには、 置く場所の 周囲8マスに 相手の石が 置かれているのが 前提条件になる – 初手で黒が置けるのは、 前提条件のみだと 右の赤いセル ○ ● ●○ あるセルにおける 周囲の情報を得るには • cellInfo[x][y]の周囲8セル – [x-1][y-1], [x][y-1], [x+1][y-1] – [x-1][y], [x+1][y] – [x-1][y+1], [x][y+1], [x+1][y+1] • 範囲外(0未満、8以上)の場合は対象外 • これをこのままコーディングすると ださいので、ループで処理しよう コーディング例 CellPosition aroundPos; for(int i = -1; i <= 1; ++i) { // 横軸を-1から+1まで aroundPos.x = pos.x + i; // ずらしたX座標値を得る // 範囲外だったら処理しない if(aroundPos.x < 0 || aroundPos.x > 7) continue; for(int j = -1; j <= 1; ++j) { // 縦軸を-1から+1まで // 基準座標の時は処理しない if(i == 0 && j == 0) continue; aroundPos.y = pos.y + j; // ずらしたY座標値を得る // 範囲外だったら処理しない if(aroundPos.y < 0 || aroundPos.y > 7) continue; // 相手の色だったらとりあえず置けそうな場所とする if(cellInfo[aroundPos.x][aroundPos.y].color == oppositeColor) { vecList.push_back(CellPosition(i, j)); cout << ": OK" << endl; } else { cout << ": NG" << endl; } } } 置ける場所の定義(2) • 相手の石があった 方向の先に、 自分の石があること – 端に到達した場合は その時点でNG – 隣接する相手の石が 複数存在した場合は、 それぞれの方向で判定 – 初手の場合青いセルが 最終的にOKになる ○ ● ●○ こんな手順で実装した 1. 石を打った位置から、相手の石が 見つかった方向へ1歩ずつ進む 2. 相手の石が見つかった時は、その座標を 一時的にメモしながら更に先へ進む 3. 自分の石が見つかったら、これまでメモ していた相手の石リストを、正式なリスト に加えてその方向の探索を終了する 4. 石が置かれてない、盤面外に出た、等の 場合は、これまでのメモを破棄して探索を 終了する ひっくり返し候補リストができた • ループでブン回してひっくり返すだけ • なのだが、これを毎回必ずやってしまう のはちと問題 – この後のToDoでそれを考えよう 最初から良い設計で書けなくてもしょうがない リファクタリング 行き当たりばったりコーディング • 実は私もそう – 授業見てれば分かるだろ! • じゃあいつ直すか? – 「今でしょ」はもう使い古されすぎ – 『この設計クソやなほんま!』と思った時が 直し時! • 何かをする時に面倒だと思う設計はよろしくない • 面倒なままゴリ押すより、設計を見直した方が 一見手間が増えても結果的には良いことが多い 今回のプロジェクトの 大きな変更点 • 盤面サイズの定数化 – 8とか、それに基づく7や35なんて数を 直接ハードコーディングするのはダサすぎる • Stoneの管理をBoardへ委任 – 石はボードの上に乗っている – つまりBoardのメンバにするのが自然 • 構造体の追加 – 1つのセルに複数の数値を持たせたい – 2つの数値のペアを1まとまりに扱いたい 今日のToDo • 石を置けるかどうかだけをチェックする 処理が必要 – 現状だと石を置けるかチェックし、 ひっくり返すところまでやってしまう • 勝ち負けを判定するにはどうすれば? – 盤面が石で埋まったとき – お互い打てる場所が無くなったとき 闇魔術の初歩の初歩 演算子再定義 (オペレータオーバーロード) CellPosition構造体で ちょこっと使用 // 闇魔術:演算子再定義(オペレータオーバーロード) friend CellPosition operator+ (const CellPosition &l, const CellPosition &r) { return CellPosition(l.x + r.x, l.y + r.y); }; // ↑これを作ることで // ↓こう書ける vCheck = vCheck + (*ite); // 使わない場合はこう書いてた↓ //vCheck.x = vCheck.x + ite->x; //vCheck.y = vCheck.y + ite->y; 演算子も関数だということ • 演算子の左右に来る 変数やオブジェクトを引数として取り、 演算結果をreturnするだけのもの • 自分の独自ルールが作れるが、 あまりに分かりづらいルールは 共同開発ではやめよう – +演算子なのに減算される – =演算子なのに代入にならない TO BE CONTINUED…
© Copyright 2024 ExpyDoc