はじめに
- 作成したクラシックマウスの解説。
- 今回はプログラムを作るにあたって、座標の設定など。
- 機体写真、動画などは「その1」をご参照。
座標など
プログラムを作るにあたって、以下の情報の設定を行った。独学なので非効率な部分や間違いがあるかもしれません。
- 区画(場所)
- 壁情報
- 機体の向き
- 歩数情報
これらの情報をもとに、機体をコントロールしています。
区画(場所)
- いろいろ試したのですが、16x16の迷路の左下からスタートするとして、左上隅を(0,0)、右下隅を(15,15)としています。(縦=行、横=列)としているので、スタート位置は(15,0)となります。ゴールは(7,7)(7,8)(8,7)(8,8)の4つです。
- プログラム上はサイズを可変できるようにしています。
- (gyo,retu)という2つの変数で場所を決定しています。
- この向きで座標を設定したのは、Arduino言語の配列宣言に合わせたのも理由の一つです。下の壁情報で配列を宣言していますが、見た目に合わせた形にすると、この向きになりました。
壁情報
- 各区画に壁があるわけですが、その壁の有無をどのように設定するか悩みました。各区域に4つの壁がある、とするとわかりやすいのですが、同じ壁に二つの異なる呼び方ができてしまうのがいやでした。
- 何とか壁情報を一つの情報で管理できないかと考えて、以下のような形にしてみました。
- 各区画の上側にある壁をwu[gyo][retu]であらわす。
- 各区画の左側にある壁をwl[gyo][retu]であらわす。
- ただし、区画は0から15までしかないので、このままでは、一番下の壁と一番右の壁が表現できなくなってしまいます。なので、16x16の外側に仮想的に区画があるようにしています。一番下の壁はwu[16][retu]、一番右の壁はwl[gyo][16]として定義しています。
- 従って、壁情報については以下の2種類の配列で定義しています。壁の枚数もこれで合うはず。
- bool wu[17][16]; と bool wl[16][17]
- 各要素は0(壁なし)、1(壁あり)で定義します。
- 探索に従って壁情報を更新していくわけですが、初期値としては、周囲の壁と、スタート位置の壁はあるものとして与えています。以下ご参照ください。あまりスマートではないですが。
bool wu[17][16]= {
{1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1, 1, 1},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0},
{1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1, 1, 1}};
//{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
bool wl[16][17]= {
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1},
{1,1,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1}};
//{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}
機体の向き
- 機体の向きは、座標の取り方に合わせて以下としています。左下がスタートだとして
- 上向き: (-1,0) スタート時の向き
- 下向き: (1,0)
- 左向き: (0,-1)
- 右向き: (0.1)
- (mg,mr)の二つの変数で向きを決定しています。
- この定義にしておくと、機体が回転したときの向きが、回転行列を適用することによって、mg,mrのまま扱えるのでプログラムが楽です。ベクトルを90°回転させればよいので、2x2の回転行列を作用させればよいですが、数学で使う座標系と向きが違うので、その点を考慮して適用することになります。
- 回転前 (mg,mr) → 右90°回転後 (mr,-mg)
- 回転前 (mg,mr) → 左90°回転後 (-mr,mg)
- プログラム上は一旦別変数を用いる必要があります。
- また、この形で向きを定義しておくと、現在位置の座標に向きを足せば、そのまま正面の区画の座標になるので、何かと便利です。
歩数情報
- 足立法で、各区画の歩数情報を計算するので、そのための配列を準備します。
- 単純に各区画に対応して、s[16][16];と宣言しています。各配列にその区画に対応した歩数が入ることになります。
- 歩数の最大値は16*16-1になるので、データ型はuint8_tにしています。配列が大きいので、データ型はなるべく小さくしたいところです。初期値としては、ゴールは0とし、その他は255としています。
- 別途解説する足立法では、都度初期状態から計算しなおしているので、初期値も都度設定しています。
- プログラムの中で、上記の宣言外の配列を参照するように見える部分があるのですが、実際に参照されることはないので、エラーにはならないようになっています。
以上