昨日の件,コーディングの前に,少し検討します.
尺取り虫の動き方を,日本語で書いてみます.
- 上,右下,右,左上,左上,上,右下,右下,右下,右,左上,左上,左上,左上,…
ここから,規則を作ることができます.
- 原点を含むY軸(x=0)にいるときは,1回だけ上に移動し,向きを右下に切り替えます.
- 原点以外のX軸(y=0,ただしx≠0)にいるときは,1回だけ右に移動し,向きを左上に切り替えます.
- x≠0, y≠0のときは,右下または左上に移動し,向きを変えません.
規則性はもっとありますが,それはまた必要なときに考えるとして,ここに書いた規則から,尺取り虫プログラムの基本形を書くことにします.
まずは尺取り虫構造体を定義します.持つべき情報は,X座標,Y座標,ステップ数(何回移動したか),それと方向となります.方向は8方向ではなく,「上」「右下」「右」「左上」の4つです.これは列挙体としましょう.
構造体(what)を定義したら,そこに作用する関数(how)ですが,「内容を出力する」と「1ステップ移動する」の2つが最低限必要です.あとはmain関数.
ということで,ソースファイルは以下のようになりました.
/* inchworm1.c */ #include <stdio.h> #define INCHWORM_COORD_MIN 0 enum inchworm_dir { INCHDIR_UP, INCHDIR_RIGHT, INCHDIR_UPPERLEFT, INCHDIR_LOWERRIGHT }; struct inchworm { int x, y; int step; enum inchworm_dir dir; }; void inchworm_put(struct inchworm *wp) { printf("%5d: (%5d,%5d)\n", wp->step, wp->x, wp->y); } void inchworm_move(struct inchworm *wp) { switch(wp->dir) { case INCHDIR_UP: wp->y++; wp->dir = INCHDIR_LOWERRIGHT; break; case INCHDIR_RIGHT: wp->x++; wp->dir = INCHDIR_UPPERLEFT; break; case INCHDIR_UPPERLEFT: wp->x--; wp->y++; if (wp->x == INCHWORM_COORD_MIN) { wp->dir = INCHDIR_UP; } break; case INCHDIR_LOWERRIGHT: wp->x++; wp->y--; if (wp->y == INCHWORM_COORD_MIN) { wp->dir = INCHDIR_RIGHT; } break; default: printf("wrong state\n"); } wp->step++; } int main(void) { struct inchworm w = { INCHWORM_COORD_MIN, INCHWORM_COORD_MIN, 0, INCHDIR_UP }; do { inchworm_put(&w); inchworm_move(&w); } while (w.step <= 100); return 0; }
- 方向の列挙子と,inchworm構造体(のポインタ)を引数にとる関数は,他の名前と競合することのないよう,「INCHDIR_」や「inchworm_」という接頭語をつけました.
- 関数inchworm_put, inchworm_moveはいずれも,構造体を引数にとっても,記述できますが,ここはポインタをとるようにしました.
- 「wp->y++」といった式があります.演算子の優先順位に注意すると,これは「(wp->y)++」であって,「wp->(y++)」ではありません.
- INCHWORM_COORD_MINという定数を定義しました.要はx=0,またはy=0を判定するためのものです.この値を1にすると,(1,1)を始点とし,第1象限の各点を動く尺取り虫となります.
- 「inchworm_put(&w);」の直前に「if (x<5&&y<5)」をつけると,{(x,y)|0≦x<5, 0≦y<5}の範囲で各点をどんな順序で巡回するかを知ることができます.