第4回 基本の応用

基本課題

制御構造の応用

d1) a(1) = a(2) = 1, a(n) = a(n-1) + a(n-2) で表される数列をa(1)からa(10)まで表示するプログラムを作成しなさい。ただし、配列は使ってはならない。

配列の応用

★d2) まず,ともに要素数5の整数配列aとbを定義し,キーボードから数値を読み込む.そして,aとbに共通の要素があるかどうか調べ,ある場合にはそれらをすべて表示するプログラムを作成しなさい。

★d3) 下記のような勝ち点表(の数値部分)を表す2次元配列int point[4][5]を定義し,各チームの勝ち点を集計して表示しなさい。

ブラジルオーストラリアクロアチア 日本 勝ち点
ブラジル0333
オーストラリア0013
クロアチア0101
日本0010

【ポイント】 上の表と2次元配列point[][]の要素との対応は以下のようにする。

ブラジルオーストラリアクロアチア 日本 勝ち点
ブラジル[0][0][0][1][0][2][0][3][0][4]
オーストラリア[1][0][1][1][1][2][1][3][1][4]
クロアチア[2][0][2][1][2][2][2][3][2][4]
日本[3][0][3][1][3][2][3][3][3][4]

関数の応用

★d4) double型の引数を取り、その絶対値を返す関数absoluteを定義し、さらにその関数を利用して関数 f(x) = |-x + 1|を定義しなさい。関数f(x)の動作を確認するプログラムを作成しなさい。

d5) 自然数nに関して,以下の定義で表される再帰関数factをC言語のプログラムで作成しなさい。

n≧1のとき  fact(n) = n・fact(n-1)
n=0のとき  fact(0) = 1

【ポイント】 関数の中では自分自身の関数を呼ぶことも可能であり,これを「再帰」という。再帰関数を作るときには,必ず処理が終わるようにすることを注意する。

int fact(int n)
{
    /* この中で fact(n-1) を使って計算 */
}

応用課題

dx1) キーボードから0以上100未満の整数を複数読み込み、1ケタ、10台、20台、30台…90台の整数がそれぞれ何個ずつあるか数えるプログラムを作成しなさい。負数が入力された時点で入力の終了とする。

dx2) 2次元配列を用いて2×2の行列double A[2][2]とdouble B[2][2]を定義し,AとBの各要素に数値を読み込ませてから,その積double C[2][2]を計算するプログラムを作成しなさい。

dx3) 半径を引数として円の面積を返す関数circleを作成しなさい。次に、そのcircleを使って、半径と高さを引数として円柱の体積を求める関数cylinderを作成しなさい。最後に,cylinderを使って円柱の体積を表示するプログラムにまとめなさい。

バブルソート

配列の中身を順番に(小さい順や大きい順に)並べ替えることを考えてみよう。もっとも古くからある方法は、バブルソートと呼ばれている。この方法では、配列を調べて、隣同士が逆順に並んでいるところがあれば交換する。これを何回も繰り返して、交換する必要がなくなるまで続ける。交換の必要がなくなれば、配列の要素はすべて順番に並んだことになる。

準備) キーボードから10個の整数を要素とする配列aを読み込み、配列の先頭から順に隣同士の要素を比較して、前の要素が後の要素よりも大きいところをすべて表示するプログラムを作成しなさい。

   i→                   →|       iの変化は8まで
   0  1  2  3  4  5  6  7  8  9
a [__|__|__|__|__|__|__|__|__|__]

        a[i]とa[i+1]を比較

dx4) 以下に示すような動作をするプログラムを作成しなさい。

  1. キーボードから10個の整数を読み込み、配列aに格納する。
  2. 配列の先頭から順に隣同士の要素を比較して、前の要素が後の要素よりも大きければ交換する。
  3. 配列の最後の要素まで到達したら:
    • 交換回数が0回より多ければ、0にセットしなおして2.に戻って繰り返す。
    • 交換回数が0回ならば、配列全体を表示して終了する。

上のプログラムの動作の意味をよく考えて、どうして整列ができるのか理解しなさい。

2分探索法

準備) 以下に示すソースコードは,小さい順(昇順)に並んだ整数配列a[]のa[n]〜a[m]の要素に整数xが含まれるかどうか探す関数 binary_search と,その動作を確かめるプログラムである。【???】の部分を適切に埋めて関数を完成させ,正しく動くかどうか確かめなさい。

int binary_search(int a[], int n, int m, int x)
{
    int c;

    if (【???】) 
        return -1;  /* 探索範囲がない→探索失敗 */

    c = (n + m) / 2;  /* 真ん中の位置の計算 */
    if (x < a[c]) { 
        /* xが真ん中の要素より小さい場合 */
        return binary_search(a, n, c - 1, x);
    } else if (【???】) {
        /* xが真ん中の要素より大きい場合 */
        return 【???】;
    } else {
        /* x == a[c] なので発見→発見位置を返す */
        return c;
    }
}

int main(void)
{
    int a[] = {  1,  2,  4,  6,  8, 
                 9, 12, 14, 17, 20,
                25, 26, 28, 30, 32, 
                34, 35, 36, 39, 40 };
    int x, index;

    scanf("%d", &x);    
    index = binary_search(a, 0, 19, x);
    if (index != -1)
        printf("a[%d]=%d\n", index, a[index]);
    else
        printf("Not found.\n");
    return 0;    
}
   

dx5) 上記の関数binary_searchを改造して,大きい順(降順)に並んでいる配列から整数を探索する関数を作り,キーボードから入力された数値を使って動作を確かめるプログラムを作成しなさい。

発展課題

マインスイーパ

dz1) Windowsにも標準でついてくるゲーム「マインスイーパ」を作成しなさい。詳しいルールが分からない人は,Windowsでゲームを起動し,ヘルプを読むとよい。

準備

  1. 2次元配列で9×9の盤面を用意する。たとえば,各マスの値に下記のような意味を持たせる。
    int board[9][9];
    • -1: まだ開けていなくて,何もない。
    • -2: まだ開けていなくて,地雷が隠されている。
    • 0〜8: 既に開いていて,周囲に地雷が0〜8個あることが分かっている。
  2. まず,すべてのマス目をまだ開けていない状態にする。
    for (x = 0; x < 9; x++) {
        for (y = 0; y < 9; y++) { 
            board[x][y] = -1;
        }
    }
  3. そして,ランダムな位置に地雷を10個埋設する。下記の例では同じ位置に地雷を重なって埋設してしまう可能性があるので,さらに改良したほうがよい。
    for (i = 0; i < 10; i++) {
        x = rand() % 9;
        y = rand() % 9;
        board[x][y] = -2;
    }

ゲーム

  1. 盤面を表示する。下記は数字で表示する例。
    printf("   ");
    for (x = 0; x < 9; x++) {
        printf("%d ", x);
    }
    for (y = 0; y < 9; y++) {
        printf("%d: ", y);
        for (x = 0; x < 9; x++) {
            if (board[x][y] < 0)
                printf("- ");
            else
                printf("%d ", board[x][y]);
        }
        printf("\n");
     }
  2. キーボードから座標 (x, y) を読み込む。
  3. 座標位置が地雷だったらゲームオーバー。
    if (board[x][y] == -2) { ...
  4. 座標位置が地雷でなく,まだ開いていなかったら,周りの8つのマス目を調べて,周りにある地雷の個数をそのマス目の値にする。※ここがポイント。
    else if (board[x][y] == -1) { ...
  5. 地雷以外のすべてのマス目が開いたら攻略成功。

盤面の大きさを変えたり,地雷の目印に旗を立てて,旗と地雷の位置が完全に一致したら攻略成功にするともっとよい。


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2006-11-17 (金) 19:06:34