|
|
>多重ループ嫌い
ならば単ループに多重 if です。
int i=j=k=l=0;
while (i < 10) {
printf("%d %d %d %d\n",i,j,k,l);
if (l++ >= 10) {
l = 0;
if (k++ >= 10) {
k = 0;
if (j++ >= 10) {
j = 0;
i++;
}
}
}
}
ぎゃー(;`Д´)/
>猫の宮さん
うにゃー、こりゃバグだらけだにゃー。まず i がグローバル変数だから、ネストの底で 10 回まわったらネストを全部抜けて終了なのにゃー。仕様どおりに動きませんにゃ。アルゴリズムとしても、関数入り口で depth++ しているのは良くないのにゃー。これは呼び出し側でやるべき処理なのにゃ。判定が関数入り口側にあるから、一番内側のループでも毎回毎回 loop(5); を呼び出して、呼び出された先で depth > 4 判定して return するのは無駄なのにゃー。
>構造体はよくわからんにゃー
それで C++ に手を出すのは93中練から雷電へ乗り換えるようなものですにゃー(;;゜Д゜;;)
構造体の意味はゲームプログラムをやってみれば判りやすいです。例えば昔なつかしい平安京エイリアン。あの敵キャラをどうやって制御するか。エイリアンに「現在位置」「現在の移動方向」「生死」の情報が必要だとして、これを
int alien_x[10], alien_y[10], alien_v[10], alien_f[10];
みたいな定義にして
void move_alien(void)
{
int x,y;
for (i=0;i<10;i++) {
if (alien_f[i]) {
x=alien_x[i]+XV[alien_v[i]];
y=alien_y[i]+YV[alien_v[i]];
switch (MAP(x,y)) {
.
.
.
こんなコードで書くのが FORTRAN 的スタイル。
これを COBOL 的にすると
struct alien_t {
int x, y, v, f;
};
struct alien_t alien[10];
void move_alien(void)
{
int x,y;
for (i=0;i<10;i++) {
if (alien[i].f) {
x=alien[i].x+XV[alien[i].v];
y=alien[i].y+YV[alien[i].v];
switch (MAP(x,y)) {
.
.
.
になります。はっきり言ってあんまり違いません。むしろ単に読みにくくなっただけのように感じます。
さて、構造化プログラミングではこうなります。
struct alien_t {
int x, y, v, f;
};
struct alien_t alien[10];
void move_alien(struct alien_t* ap)
{
int x,y;
x=ap->x+XV[ap->v];
y=ap->x+YV[ap->v];
switch (MAP(x,y)) {
.
.
.
void move_aliens(void)
{
int i;
for (i=0;i<10;i++) {
if (alien[i].f) move_alien(&alien[i]);
}
}
FORTRAN や COBOL では、「サブルーチン」が「エイリアン10匹を動かす」という機能として実装されていたのに対し、構造化プログラムでは「エイリアン1匹を動かす」関数(あるいはプロシージャ、ないしはメソッド)と「10匹のエイリアンを動かす」機能に分離されています。
こういったプログラミングの何が良いかというと、例えば「パックマン」みたいに、敵キャラに異なる性格付けがされている場合、
void move_aliens(void)
{
int i;
for (i=0;i<10;i++) {
switch (alien[i].f) {
case 1:
move_red_alien(&alien[i]);
break;
case 2:
move_pink_alien(&alien[i]);
break;
case 3:
move_blue_alien(&alien[i]);
break;
case 4:
move_green_alien(&alien[i]);
break;
}
}
のように、「性格」を別のコーディングとして実装できることです。FORTRAN 型や COBOL 型のプログラミングでは、「性格」に関する変数を新たに増やし、move_alien() サブルーチンの中で性格の if を入れて「逃げるか、向かって行くか、ウロつくか」の判定を入れなければなりません。例えばこんな感じ?
void move_alien(void)
{
int x,y;
for (i=0;i<10;i++) {
if (alien[i].f) {
x=alien[i].x+XV[alien[i].v];
y=alien[i].y+YV[alien[i].v];
switch (MAP(x,y)) {
case WALL: // 移動先のマップが壁だった場合
switch (alien[i].f) {
case 1: // 検非違使へ向かって行く方向へ変針する
.
.
.
case 2: // ランダム方向へ変針する
.
.
.
case 3: // 検非違使から逃げる方向へ変針する
.
.
.
こんな switch が「他のエイリアンに当たった場合」やら「文岐路に差しかかった場合」のそれぞれに散りばめられるとプログラムは破綻に近づいてゆきます。構造化プログラミングでは、機能単位の分割に関する考え方が逆になります。共通部分をこそルーチンとして外部に放り出し、「異なる部分」を呼び出し元に残しておくのです。
あぁ、真面目に説法してしまった。絶望した!説法好きな自分に絶望した!!
|
|