スモウルビー・プログラミング甲子園 命令コードの種類と使い方 Ⅰ はじめに 本書では、AIプログラムを作る際の参考となるように、色々な命令コードとその 使い方をご紹介します。 ここで紹介した命令コードを参考にしていただき、高得点を目指して自分だけのA Iプログラムを作ってみてください。 [目 次] Ⅰ はじめに P1 Ⅱ 最初に覚えておくこと P2 Ⅲ 命令コードの説明 P7 Ⅳ 具体的な使い方 P12 1 Ⅱ 最初に覚えておくこと 1.マップについて (1)マップを構成する最小単位をセル(又はマス)と呼びます。 (2)横軸をx軸、縦軸をy軸とします。 (3)x軸、y軸ともに0~14番までの番号が付いています。 (4)セルの場所のことを座標と呼びます。 0 北 1 例えば、右の表の網掛けのセルの座標は、 2 3 [9,10]と表示します。 4 (2つの数字のうち、先頭がx軸の番号、 5 6 次がy軸の番号です。) 西 東 7 y軸 8 9 10 11 12 y軸 13 14 0 1 12 2 10 11 3 4 9 5 8 6 x軸 7 7 6 8 5 4 9 1 0 3 11 1 2 12 13 0 14 0 14 13 南 1 13 2 3 11 12 0 4 10 5 6 9 1 7 8 7 2 3 4 5 6 7 8 x軸 x軸 8 6 9 5 10 4 11 3 12 2 13 14 9 10 11 12 13 14 14 1 0 y軸 2.プレイヤキャラクタの動きについて (1)最初に自キャラクタが持っている情報は、自分とゴールの位置(座標)情報のみで、マッ プ全体の情報は持っていません。 (どのルートが通れるか、どこに加点アイテムがあるかなど は命令コードを使って調べないと分かりません。 ) ・ゲーム開始時点では、自キャラクタ とゴールの位置(座標)情報のみを 認識しています。 ・それ以外のマップ情報は認識してい ません。 最初の状態 2 (2)プレイヤキャラクタの行動をプログラムする際に、使用回数に制限のある行動命令があり ます。次の行動命令は、1ターンでいずれか2回までしか使用できません。また、①の move_to は、1ターンで1回しか使えません。 なお、制限を超えた命令は何も実行されません。 【制限のある行動命令】 ① move_to ② get_map_area ③ set_trap_item 例えば ・get_map_area →move_to 〇(2回なので有効) ・get_map_area → move_to → set_trap_item ×(3回なので無効) ・move_to → move_to → ×(move_to は1回のみのため無効) (3)また、プレイヤキャラクタが1ターンで移動できるのは、現在地から東西南北に1マスで す。 (1ターンで移動できるのは1歩だけです。) 3.プログラム上で使用する値について マップの構成(空間、水たまり、壁、ゴール)や加点アイテムなどの情報はあらかじめ値が決 まっています。この値を使う(指定する)ことにより、加点アイテムなどの検索が可能になりま す。また、検索結果として、対戦環境からプレイヤキャラクタに返される情報( 「戻り値」と言い ます。 )もこの値で返されます。下の表が値(戻り値)の一覧です。 項目 戻り値 内 容 0 空間セル(移動可能) マップ 1 壁セル(移動できない) 情報 2 水たまりセル(移動すると次のターンで1回移動ができない) 3 ゴール a お茶(10 点) 加点 b 和菓子(20 点) アイテム c 丁銀(30 点) d シロイルカ(40 点) A 毒キノコ(-10 点) 減点 B 蛇(-20 点) アイテム C トラバサミ(-30 点) D 爆弾(-40 点) 3 4.覚えて欲しいプログラムのルール ここでは、AIプログラムを作る前に覚えておいて欲しいプログラムのルール等をご説明しま す。 (1)引数(ひきすう) 引数とは、プログラミングにおいて、サブルーチンや関数、API などを呼び出す(コール) ときに指定する変数や定数のことです。 AIプログラムを作成する際には、命令コードの引数として、座標や変数を指定する場合が あります。 ※変数については、 (3)変数で説明します。 [引数] 引数として座標を指定する場合 move_to [7,7] ※[7,7]が引数 引数として変数を指定する場合 move_to route[1] ※route[1]が引数 ※「move_to」は移動するための命令コードで、後ろに引数として移動先の座標又 は変数を指定して使います。 (2)配列 配列は複数の他の変数を管理するために使うオブジェクトです。括弧[]で囲んだ中に変数を カンマ(,)で区切って記述します。 マップ上の座標も配列で表示します。 (例[7,7])また、命令コードの中には、実行した際の 戻り値として、複数の座標で返されるものもあります。 [配列] 単体の座標配列 [7,7] 複数の座標配列 [[7,8],[7,9],[7,10]] 例えば、経路検索を行うための命令コード「calc_route」を使うと、複数の座標配列が得ら れます。 ・自キャラクタの現在地からゴールまでの最短ルートを検索 ・得られる情報は、次のような座標配列 例) [[13,9],[13,8],[13,7],[12,7],[11,7]] ※先頭が自キャラクタの現在地で、以下ルート順に座標がならび、最 後がゴールの座標 なお、得られた座標配列は、次のように先頭が 0 から始まる番号で指定することができます。 例) 座標配列 [[13,9],[13,8],[13,7],[12,7],[11,7]] 番 号 ↑ ↑ ↑ ↑ ↑ 0 1 2 3 4 4 (3)変数 変数とは、数値や文字列に名前を付けることを言います。変数を使うことにより、その場 に応じて違う数値や文字を使うことができます。 例)num = 10 「num」が変数の名前で、中に入っているものが「10」です。 ※変数は数値や文字を入れるための「箱」で、変数につける名前は「箱」の名前です。 ※変数の名前は、一定の規則に従っていれば、自由に付けられます。 (英小文字かアンダー スコア「_」で始まる英文字、数字、アンダースコアで名前を付けます。但し、Ruby であらかじめ定義されている予約語と同じ名前を付けることはできません。 ) AIプログラムは、毎ターン、同じプログラムを繰り返すため、決まった座標を使うこと はほとんどなく、何らかの命令コードで求めた値を使用することになります。こうした場合 に変数が役に立ちます。 次の例を見てください。 「calc_route」に「route」という名前を付けています。 「calc_route」は、自キャラクタ の現在地からゴールまでの最短ルートを検索する命令コードで、検索結果はルート順の座標 配列が返されます。これで「calc_route」で得られた検索結果(座標配列)を変数「route」 を使って指定することができるようになります。 ・例) 「calc_route」で得られた座標配列が[[13,9],[13,8],[13,7],[12,7],[11,7]]の場合 ・座標配列には、0 から順番に番号が付いています。 ・ 「route」という名前を付けているので、各座標は次のように指定できます。 得られた座標 [13,9] [13,8] [13,7] [12,7] [11,7] 変数名で指定 route[0] route[1] route[2] route[3] route[4] ※先頭の route[0]が自キャラクタの現在地で、以下ルート順の座標が続き、最後の route[4]がゴールの座標となります。 次に「move_to」は移動するための命令コードですが、引数として移動先の座標を指定す る必要があります。ここで変数「route[1]」を移動先座標として指定することにより、毎タ ーン最短ルートの座標に移動することができます。 ※「route[0]」は自キャラクタの座標のため、移動先として指定できるのは毎ターンいず れも1マス先の「route[1]」となります。 5 5.プログラムの例 (1)AIプログラムは、1ターンの行動内容をプログラミングしますので、ゲームの最初から 最後まで、同じプログラムが繰り返されます。 (2)このため、どのような状況でも対応できる行動をプログラミングする必要があります。 (3)例えば、対戦環境にあるサンプルAIプログラム(smpl02)は、次のように行動するよう プログラミングしてあります。 (4)この内容であれば、毎ターン同じプログラムを繰り返しても、ゴールを目指して行動する ことができます。 【smpl02】 ※「◇ずっと( )繰り返す」の内側に1ターンの行動命令が入っています。 (これで毎ターン、同じ行動を繰り返します。 ) ① ② ③ ④ ⑤ ⑥ ① 自分の現在地を中心とした5×5セルの範囲のマップを検索します。 ② 減点アイテムの位置を検索します。 ③ 減点アイテムに接触せずにゴールできる最短ルートを検索します。 ※指定したルートがない場合は、現在地の座標のみが返されます。 (指定したルートがある場合は複数の座標 情報が返されます。 ) ④ もし減点アイテムに接触せずにゴールできる最短ルートがない(③の検索結果の座標数が1つの)場合は、 ゴールまでの最短ルートを検索します。 ⑤ ③の座標を移動先として移動します。(③のルートがない場合は、④の座標を移動先として移動します。) ⑥ 現在のターンを終了し、次のターンを待ちます。 ※各命令コードの詳しい説明は「Ⅲ 命令コードの説明」をご覧ください。 6 Ⅲ 命令コードの説明 次に、使用できる命令コードについてご説明します。ここで紹介する命令コードは、本大会の ために用意した命令コードです。詳しい使い方はそれぞれのページをご覧ください。 また、 「Ⅳ 具体的な使い方」では、これらの具体的な使用例をご紹介しています。 [本大会のために用意した命令コード一覧] 命令コードの種類 実行できる内容 ページ move_to キャラクタを動かす P8 calc_route 指定した 2 点間の最短ルートを検索する P8 get_map_area 指定した範囲(5×5 セル)のマップ情報を検索する P9 set_trap_item トラップアイテムをマップに置く P9 turn_over ターンを終了する P9 map 指定した座標のセル情報を呼び出す P10 map_all マップ全体のマップ情報を呼び出す P10 locate_objects other_player_x, 指定した範囲に、指定した要素が存在するかどうかを 確認する P10 対戦相手の座標(位置)情報を呼び出す P11 妨害キャラクタの座標(位置)情報を呼び出す P11 goal_x, goal_y ゴールの座標情報を呼び出す P11 player_x, player_y 自分の座標(位置)情報を呼び出す P12 other_player_y enemy_x, enemy_y 7 move_to(引数) ※命令実行回数にカウント(1 ターン1回まで) (1)実行内容 ・引数(ひきすう)として、移動先の座標(配列または変数)を指定します。 ・指定した座標にキャラクタが移動します。 (移動先は自キャラクタの現在地から東西南北いずれかの方向に1マスです。) (2)解 説 ・X10、Y5 のセルに移動したい場合には、move_to[10, 5]と指定します。 ・移動できるのは空間と水たまりだけで、壁には移動できません。 ・水たまりに移動した場合、次のターンは移動が出来ません。 ・移動できない座標を指定した場合、エラーが返されます。 ・この場合でも命令実行回数はカウントされますので注意してください。 calc_route(引数) (1)実行内容 ・引数として、ハッシュを指定します。 ・指定できるハッシュは次のとおりです。 src 出発地点です。[13,8]などの座標を指定します。 省略した場合は、キャラクタの現在地が出発地点になります。 dst 到着地点です。[7,7]などの座標を指定します。 省略した場合は、ゴールの座標が到着地点になります。 except_cells ルートに含めたくない座標を指定します。 配列を使えば複数の指定が可能です。 省略も可能です。 ・ハッシュで指定した内容で 2 点間の最短ルートを検索します。 ・戻り値として、先頭が出発地点、最後が到着地点のルート情報が返されます。 例)[[13,9],[13,8],[13,7],[12,7],[11,7],[10,7],[9,7],[8,7],[7,7]] →[13,9]が出発地点の座標、以降ルート順の座標、最後の[7,7]が到着地点の座標 (2)解説 ・出発地点を[13,9]、到着地点を[7,7]、避けたい座標を[9,9]として、経路検索を実施した い場合は次のとおりです。 calc_route(src:[13,9],dst:[7,7],except_cells:[9,9]) ・引数(src、dst、except_cells)を省略した場合、自キャラクタの現在地からゴールまで の最短ルートを検索し、ルート順の座標配列が返されます。 calc_route ・except_cells で指定した座標を通らずには到着地点にたどりつけない場合、出発地点の座 標が1つだけ返されます。 8 ・また、得られた座標情報は、先頭から順番に 0,1,2,3・・・の番号で指定できます。 ・マップ検索を実施していないエリアを含んでこの命令コードを実行した場合、未検索エリ アのセルは全て移動可能とみなしてルート検索しますので、注意してください。 (実際には 壁があって目的地点に到達できないことがあります。 ) get_map_area(引数) ※命令実行回数にカウント(1 ターン2回まで) (1)実行内容 ・引数として、探索したい範囲の中心座標を指定します。 ・指定した範囲(5x5 セル)のマップ情報を検索します。 ・戻り値として、指定した範囲(5×5 セル)のマップ情報が返されます。 (2)解 説 ・得られるマップ情報は、指定した範囲の以下の情報です。 →マップ構成(空間・壁・水たまり・ゴール) →加点アイテム・減点アイテム・妨害キャラクタの位置と種類 ・また、得られた情報は、自動的に AI ライブラリ内部の記録として保存され、map 命令や enemy_x,enemy_y 命令で取得できるようになります。 set_trap_item ※命令実行回数にカウント(1 ターン2回まで) (1)実行内容 ・引数は不要です。 ・トラップアイテムを自キャラクタの現在地に置きます。 (2)解説 ・プレイヤキャラクタは、1ゲームに2回までトラップアイテム(爆弾(-40 点) )を使用す ることができます。 ・プレイヤキャラクタの現在地にトラップアイテムを配置するため、移動せずに同一セルに 止まったままだと自分が減点されますので、注意してください。 turn_over (1)実行内容 ・引数は不要です。 ・現在のターンを終了させ、次のターンを待ちます。 ・戻り値として、自キャラクタの現在地の座標が得られます。 (2)解説 ・必ず全ての行動を終えた段階で turn_over が実行されるようにしてください。 ・この命令が実行されないと、ターンの制限時間10秒を超え、ゲームオーバーとなります。 9 map(引数) (1)実行内容 ・引数として、セル情報を呼び出したい座標を指定してください。 ・指定した座標のセル情報を呼び出します。 ・戻り値として、指定した座標のセル情報が返されます。 (マップ情報取得済みの座標に限る。 ) (2)解 説 ・得られるセル情報は、以下の情報です。 →マップ構成(空間・壁・水たまり・ゴール) →加点アイテム・減点アイテム・妨害キャラクタの有無 ・未探索座標を指定した場合は、-1 が返されます。 ・また、マップエリア外を指定した場合は、nil が返されます。 map_all (1)実行内容 ・引数は不要です。 ・マップ全体のマップ情報を呼び出します。 ・戻り値として、マップ情報取得済みのマップエリアのマップ情報が返されます。 (2)解 説 ・得られるマップ情報は、以下の情報です。 →マップ構成(空間・壁・水たまり・ゴール) →加点アイテム・減点アイテム・妨害キャラクタの位置と種類 ・未探索セルは、-1 が返されます。 ・また、マップエリア外を指定した場合は、nil が返されます。 locate_objects(引数) (1)実行内容 ・引数としてハッシュを指定します。 ・指定できるハッシュは以下のとおりです。 sq_size:指定する範囲の縦横のセル数。省略可(省略時は 5 になります。 ) cent:指定する範囲の中心座標。省略可(省略時はキャラクタがいる座標になります。) objects:探索する要素。省略可(省略時は全減点アイテムになります。 ) ・指定した範囲に、指定した要素が存在するかどうかを確認します。 ・戻り値として、指定した要素がある座標情報が返されます。 10 (2)解 説 ・objects として指定できるものは、以下の指定値です。 (指定値に付けた変数での指定も可 能です。 ) 加点アイテム 減点アイテム 指定値 指定値 お茶(10 点) a 毒キノコ(-10 点) A 和菓子(20 点) b 蛇(-20 点) B 丁銀(30 点) c トラバサミ(-30 点) C シロイルカ(40 点) d 爆弾(-40 点) D ・なお、未探索のマップエリアの情報は取得できません。 other_player_x,other_player_y (1)実行内容 ・引数は不要です。 ・対戦相手の位置情報を呼び出します。 ・戻り値として、対戦相手の位置情報が得られます。 ・get_map_area で対戦相手の位置情報を取得していない場合は、nil が返されます。 (get_map_area を実行した範囲に対戦相手がいない場合も nil が返されます。 ) ・得られる位置情報は、最後に get_map_area を実行して対戦相手を把握した時点での情報 です。 (対戦相手は移動しますので、注意してください。 ) enemy_x,enemy_y (1)実行内容 ・引数は不要です。 ・妨害キャラクタの位置情報を呼び出します。 ・戻り値として、妨害キャラクタの位置情報が得られます。 ・get_map_area を実行していない場合は、nil が返されます。 (get_map_area を実行した範囲に妨害キャラクタがいなくても、位置情報は得られます。 ) ・得られる位置情報は、最後に get_map_area を実行した時点での妨害キャラクタの座標で す。 (妨害キャラクタは移動しますので、注意してください。 ) goal_x,goal_y (1)実行内容 ・引数は不要です。 ・ゴールの位置情報を呼び出します。 ・戻り値として、ゴールの座標が得られます。 11 player_x,player_y (1)実行内容 ・引数は不要です。 ・自キャラクタの位置情報を呼び出します。 ・戻り値として、自キャラクタの座標が得られます。 Ⅳ 具体的な使い方 【自キャラクタの現在地を中心とした 5×5 セル分のマップ情報を探索】 get_map_area の引数として player_x, player_y を入力することにより、命令を実行でき ます。 【自キャラクタの現在地からゴールまでの最短経路を検索し、その結果を移動先に指定して移動】 ① ② calc_route を使うことにより、 自キャラクタの現在地からゴールまでの最短ルートを検索し、 その座標配列を得ることができます。また、このルート検索で得られた座標を移動先として使 用するため、 「res」という変数名を付けます。 (例)res=calc_route 返された座標配列 [[13,9],[13,8],[13,7],[12,7],[11,7],[10,9],[9,7],[8,7],[7,7]] 順番に進むとゴールに到着 ※先頭が自キャラクタの現在地の座標[13,9]、最後がゴールの座 標[7,7]。ルート順に座標がならんでいます。 ※座標配列は先頭から 0,1,2,3,・・・と指定できます。 res = [[13,9],[13,8],[13,7],[12,7],[11,7],[10,9],[9,7],[8,7],[7,7]] res[0] = [13,9] res[1] = [13,8] res[2] = [13,7] 次に、②の move_to res[1]を見てください。move_to(引数)は、移動するための命令コ ードで、 (引数)のところに移動先の座標を入れます。ここでは res[1]を移動先座標として指 定しています。こういう形で使うことで、calc_route の検索結果を移動先として指定すること が可能になります。 (「得られた情報の何番目の座標」という形で引数を指定しています。 ) また、①の calc_route で得られる座標配列の先頭は、自キャラクタの座標(res[0])になり ます。プレイヤキャラクタが移動できるのは1マスと決まっていますので、移動先としては、 res[1]を指定します。 12 ※AIプログラムは、毎ターン同じ行動を繰り返すので、移動先に具体的な座標(例えば[3,5] など)を指定することはまずありません。使用する場合は、今回のようにルート検索など の命令と一緒に実行し、その結果を移動先の座標として指定するような使い方をします。 【ゴールの 1 マス手前でトラップアイテムを配置する】 set_trap_item を使用することで、トラップアイテムを配置できます。 (引数は不要です。 ) ただし、この命令コードは毎ターン使用する必要がなく、また、1ゲームで2回しか使えな いことから、 「◆もし( )ならば」などの条件分岐を使って、特定の条件の下でのみ使用す るようにしましょう。 次に具体的な使用例をご紹介します。 条件 [左のプログラムの内容] ① ① ゴールまでの最短ルートを検索 ② もし、①で得られる座標配列に含 まれる座標の数が2つならば、 ② 「トラップアイテムを配置」し、 「①で得られた座標(res[1])に移動」 ③ ①で得られる座標配列に含まれる ③ 座標の数が2つ以外であれば、 「マップ探索を実施」し、 「①で得られた座標(res[1])に移動」 このプログラムは、 「◆もし( )ならば、 ( )でなければ」という条件分岐を使うこと により、条件によって異なる行動をとるようになっています。 [条件]res.length=2 ( YES なら②を実行 NO なら③を実行 ).length は配列の中に含まれる要素の数を求めるコードです。 (詳しくは P15 で説明) ここでは、res.length ですから、①の res に含まれる座標の数を求めています。また、res は calc_route で得られた座標配列で、この座標配列は、先頭が自キャラクタの座標からはじ まり、通るべきルート順の座標が続き、最後がゴールの座標となっています。よって res.length=2(calc_route で得られる座標配列の中の座標が2つ)になる場合は、自キャラ クタの座標とゴールの座標の2つが返される状態、つまりゴールの1マス手前の時だけにな ります。 【未探索のエリア(マップ情報が-1 のセル)があるかどうかを確認する】 map_all を使った場合に、未探索のセル(座標)があるとそのセル(座標)は-1 で返されま す。これを利用して未探索エリアがあるかどうかを確認する方法をご説明します。 まず、map_all がマップ情報を取得するための命令コードです。次にこの結果に-1 が含まれ 13 るかどうかを確認するための命令コードが include?(-1)です。結果は真(true)か偽(false) で返されます。map_all では、[[8,9],[9,9],[-1],[-1],[9,12]]といったような 2 次元配列で情 報が返されるため、このままでは include?が使えません。(include?が使えるのは[1,2,3]とい った場合です。 )このため、flatten という命令コードを使います。flatten を使うと2次元配列 の情報が[8,9,9,9,-1,-1,9,12]といった形に変換され、include?が使えるようになります。 なお、map_all で得た情報は、真の場合は〇〇〇する、偽の場合は●●●するといった別の 命令コードと組み合わせて使用します。 【map_all.flatten.include?(-1)の処理の流れ】 map_all →[[8,9],[9,9],[-1],[-1],[9,12]] flatten →[8,9,9,9,-1,-1,9,12] include? →真(-1 が含まれる) 【マップ上の加点アイテムがある場所を調べる】 マップ全ての範囲を調べたい場合、マップのセル数は 15、中心座標は[7,7]になりますので、 sq_size:15、cent:[7,7]と指定します。加点アイテムの4種類は、a~d で指定(P11 参照) されていますので、objects:[“a”,”b”,”c”,”d”]として指定します。これでマップ上にある加点ア イテムの位置情報が得られます。 また、 「セット」と「♠式」を組み合わせて使うことにより、この命令コードで得られた情報 (4種類の加点アイテムの位置)を一つの名前で定義することでき、これより後の行動命令を 組む際にこの名前を使用することで、この情報を参照できます。 (ここでは treasures という名 前を付けました。 ) 【減点アイテムを避けて、自キャラクタの現在地からゴールまでの最短ルートを検索】 最初に、locate_objects(sq_size:15,cent:[7,7])を使って減点アイテムの位置情報を調べま す。先ほどの加点アイテムの位置を調べる際には、objects[“a”,”b”,”c”,”d”]として4種類の加点 アイテムを指定する必要がありましたが、減点アイテムの場合は objects を指定する必要はあ りません。 (locate_objects は objects を指定しない場合、減点アイテムを対象として命令が 実行されます。 )また、この結果をルート検索で使用しますので、 「セット」を使って traps と いう名前を付けておきます。 次に、calc_route を使ってルート検索を行います。calc_route では、except_cells を指定 することにより、通らない(避ける)座標を指定することができます。ここでは減点アイテム を避けるため、先ほど名前を付けた traps を使います。 calc_route(except_cells:traps) これで、減点アイテムを避けて、自キャラクタの現在地からゴールまでの最短ルートを検索 できます。 ※減点アイテムなど、except_cells で指定した座標を通らずに到着地点にたどりつけない 14 場合は、出発地点の座標が1つだけ返されます。 ※このルート検索の結果を move_to などで使用するため、この命令コードに「route」と いう名前を付けています。 【指定したルートがない場合、最短ルート再検索し移動】 減点アイテムを避け A て、自キャラクタの現在 地からゴールまでの最 短ルートを検索 先ほど「減点アイテムを避けて、自キャラクタの現在地からゴールまでの最短ルートを検索」 する方法をご説明しましたが、場合によっては、減点アイテムを避けてゴールするルートがない ことがあります。ここでは、こうした場合の対応方法をご説明します。 まず、Aの命令コードで指定したルートがあるかないかを判定する必要があります。calc_route では指定したルートがない場合、出発地点の座標が1つだけ返されますので、calc_route で得ら れた座標数を確認することにより、ルートの有無が判定できます。 (座標数が1つの時は指定した ルートがないことになります。 ) 次に、もし指定したルートがなかった場合の行動を入力します。ここでは減点アイテムを避け てゴールすることをあきらめ、単純にゴールまでの最短ルートを検索し、その最短ルートで移動 することとします。 ① Aの検索結果(座標配列)の数を確認 座標数を確認する方法として length を使います。使い方は数を確認したい配列又は変数の 後に「.length」を付けます。ここでは、route の数を確認したいので、 「route.length」と します。 ② route.length の数が1かどうかを判定 演算ブロックを使い右のような式を完成させます。 ③ 自キャラクタの現在地からゴールまでの最短経路を検索 calc_route で最短経路を再検索します。また、後でこの結果を使うため route という変数 名をつけておきます。 ④ 制御ブロック「もし( )ならば」の中に命令コードを入れる 今回の最短ルートの再検索は、もし(指定ルートがない)ならば実行する内容ですので、 制御ブロック「もし( )ならば」を使い、このブロックの中に②~③のブロックを入 れ込みます。 15 ⑤ 変数 route[1]を移動先として移動 このプログラムでは、2つの違う命令コードに route という同じ名前を付けています。こ うした場合は、最後に実行された命令コードの結果が route に反映されます。 ■指定ルートがある場合は ・ のみが実行されるため、こ の結果が route に反映されます。 ・よって、move_to route[1]は、減点アイテムを避けて最短ルートを移動します。 ■指定ルートがない場合は、 ・◆もし( )ならばの中の が最後に実行 されるため、この結果が route に反映されます。 ・よって、move_to route[1]では、単純にゴールまでの最短ルートを移動します。 【最後に・・・smpl03 のプログラム内容を考えてみよう!】 最後に対戦環境にあるサンプルAIプログラムの中で一番高度な内容になっている smpl03 の 内容を簡単にご説明します。 みなさんも一緒にこの内容を考えていただき、自分のAIプログラムの参考にしてみてくださ い。 ※プログラムの中にある「♠コメント」部分は、プログラム内容の説明文であり、プログラム 本体とは関係ありません。 (♠コメントの下の部分のプログラム内容を説明しています。 ) [smpl03 のコードと個別の意味] ・nilに dst という変数名を付けます。(dst = nil と定義します。) ・nilは「存在しない」という意味です。 未探索エリアがあるかどうかを確認します。 意味 searched = map_all で取得した情報に 2回繰り返す -1 がない。 もし未探索エリアがあるならば 意味 searched = 「偽」(-1 がある) map_x = -3 map_y = -3 を指定します。 (次ページにつづく) 16 3回繰り返す (map_y + 5)を 15 で割ります。 割った余りの数を map_y とし ます。map_x も同じです。これ を 3 回×3 回(計 9 回)繰り返 します。この式で求められる 数値は 2,7,12,2,7,12 を繰り返 します。 map_x と map_y の座標が未探索(-1)であるかを確認 し、未探索(-1)であれば繰り返しをやめて、次の命 令へ進みます。これを計 9 回繰り返した場合に探索 する座標は次のようになります。 [2,2],[7,2],[12,2] [2,7],[7,7],[12,7] [2,12],[7,12],[12,12] 繰り返しをやめた場合、get_map_area(map_x,map_y)を実行します。 未探索エリアがあるかどうかを確認します。 意味 searched = map_all で取得した情報に -1 がない。 未探索エリアがないならば(searched に-1 がないならば) dst = nil でないならば get_map_area(player_x,player_y)を実行します。 最短ルートの残り座標数が 5 より少ないならば dst = nil と定義します。 加 点 アイ テム の位置情報を 検索します。 加点アイテムの位置情報を近い順に並べ替えま す。 dst = nil ならば dst = treasures.first と定義します。 もし「treasures の中に dst が含まれていない」 または「player_x,player_y = dst」ならば dst = treasures.first と定義します。 17 dstを到着地点として最短ルートを検索します。 route[1]を移動先として移動します。 ターンを終了します。 [考え方とポイント] x軸 1.マップ情報の取得 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 経路検索などで正確な答えを得るためには、マップ情 1 報の把握が必要です。また、マップ検索は効率的に実施 3 すると9回でマップ全体を把握することができます。 5 こうしたことから、smpl03 ではマップ検索を優先し て実施するようプログラムされています。 2 4 6 y 7 軸 8 9 10 右の図の黒い座標を指定してマップ検索を行うと、 9回でマップ全体を把握できます。このため smpl03 11 12 13 14 では、次の式によりこの座標を求めています。 map_x = -3 ( map_x + 5 ) % 15」 (map_y も同じ。 ) →この答えは、1回目が2、2回目が7、3回目が12となり、4回目以降も2, 7,12が繰り返されます。 また、P17 の先頭部分で「3回繰り返す」を2回使っています。これで9箇所の中心座標につ いて、未探索かどうかを確認し、未探索であればその座標を中心に5×5マスのマップ検索を実 施します。なお、この「3回繰り返す」の命令は「2回繰り返す」 (P16 の中段)の中に入ってい ます。これは get_map_area が1ターン2回の制限があるためです。 2.変数 dst について Ruby の変数は、異なる内容で同じ名前を付けた場合、一番近いところで実行された内容が変 数に代入されます。smpl03 では、この性質を利用して dst をルート検索の到着地点に指定して います。具体的には、一番先頭に「dst = nil」と定義し、プログラムの途中(P17 下段)では「dst = treasures.first」と定義しています。これにより状況に応じて「calc_route(dst:dst)」の到着 地点をゴールと一番近い加点アイテムに使い分けることが可能になります。 ( 「dst = nil」の場合 は dst が存在しないことになり、calc_route で dst を省略した場合(到着地点がゴールになる。 ) のルート検索を行います。 ) 3.最後に smpl03 では、 「もし( )ならば」などの条件分岐が沢山使われており、プログラムを読むこ とに苦戦するかもしれません。しかしながら、条件分岐を使いこなすことにより、高得点を目指 すことが可能になります。smpl03 を参考にしていただき、条件分岐を勉強してください。 18
© Copyright 2024 ExpyDoc