★ポインタ(ダブルポインタ2)★


続いては、前回前々回のプログラムを振り返って、関数に分割してみましょう。

迷路の自動生成とダブルポインタを使った関数を作ります。

いつも通り、大まかな流れから考えていきます。

1.迷路のサイズ決定
↓
2.領域の確保
↓
3.迷路の初期化(外周のみ)
↓
4.迷路の自動生成
↓
5.迷路の表示
↓
6.領域の解放

まずは、定数とmain関数を作ります。

※これまでと同じく関数ごとに作っていき、main関数のみ更新します。

※プロトタイプ宣言などは、皆さんで追加してください。

<sample program 171-01>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define DIRECTION 4

enum {
    FLOOR,
    WALL,
};

enum {
    UP,
    RIGHT,
    DOWN,
    LEFT,
};

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    return 0;
}

1.迷路のサイズ決定

関数名 DecideMazeSize
戻り値 なし
引 数 縦方向を格納する変数のアドレス
    横方向を格納する変数のアドレス
機 能 迷路の縦横サイズを決定する
void DecideMazeSize(int *pRow, int *pCol)
{
    *pRow = 7 + (rand() % 5) * 2;
    *pCol = 7 + (rand() % 5) * 2;
}

単純に迷路のサイズを決定するだけの関数です。

短いプログラムですが、機能ごとに関数分けした方が良いと思います。

<sample program 171-02>

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    DecideMazeSize(&row, &col);

    return 0;
}

2.領域の確保

関数名 AllocateMazeArea
戻り値 成功 1、失敗 0
引 数 迷路用領域を格納するポインタのアドレス
    縦方向の要素数、横方向の要素数
機 能 迷路用の領域(1次元配列)を確保する
int AllocateMazeArea(int **ppMaze, const int size)
{
    *ppMaze = (int*)malloc(sizeof(int) * size);

    if (!*ppMaze) {
        return 0;
    }

    return 1;
}

前回やったダブルポインタを使った関数です。

<sample program 171-03>

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    DecideMazeSize(&row, &col);

    if (!AllocateMazeArea(&pMaze, row * col)) {
        return 1;
    }

    return 0;
}

3.迷路の初期化(外周のみ)

関数名 InitializeMaze
戻り値 なし
引 数 迷路用領域の先頭アドレス
    縦方向の要素数、横方向の要素数
機 能 迷路の床と外周を設定する
void InitializeMaze(int* const pMaze, const int row, const int col)
{
    int i;
    int j;
  
    for (i = 1; i < row - 1; i++) {
        for (j = 1; j < col - 1; j++) {
            pMaze[i * col + j] = FLOOR;
        }
    }
  
    for (i = 0; i < row; i++) {
        pMaze[i * col] = WALL;
        pMaze[i * col + (col - 1)] = WALL;
    }
  
    for (j = 1; j < col - 1; j++) {
        pMaze[col] = WALL;
        pMaze[(row - 1) * col + j] = WALL;
    }
}

今回も「柱」は自動生成の時に作ります。

<sample program 171-04>

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    DecideMazeSize(&row, &col);

    if (!AllocateMazeArea(&pMaze, row * col)) {
        return 1;
    }

    InitializeMaze(pMaze, row, col);

    return 0;
}

4.迷路の自動生成

関数名 GenerateMaze
戻り値 なし
引 数 迷路用領域の先頭アドレス
    縦方向の要素数、横方向の要素数
機 能 迷路の「柱」と乱数を使って壁を設定する
void GenerateMaze(int* const pMaze, const int row, const int col)
{
    int i;
    int j;
  
    for (i = 2; i < row - 2; i += 2) {
        for (j = 2; j < col - 2; j += 2) {
  
            pMaze[i * col + j] = WALL;
  
            switch (rand() % DIRECTION) {
            case UP:
                pMaze[(i - 1) * col + j] = WALL;
                break;
            case RIGHT:
                pMaze[i * col + (j + 1)] = WALL;
                break;
            case DOWN:
                pMaze[(i + 1) * col + j] = WALL;
                break;
            case LEFT:
                pMaze[i * col + (j - 1)] = WALL;
                break;
            }
        }
    }
}

特に変わったところはありません。

<sample program 171-05>

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    DecideMazeSize(&row, &col);

    if (!AllocateMazeArea(&pMaze, row * col)) {
        return 1;
    }

    InitializeMaze(pMaze, row, col);

    GenerateMaze(pMaze, row, col);

    return 0;
}

5.迷路の表示

関数名 ShowMaze
戻り値 なし
引 数 迷路用領域の先頭アドレス
    縦方向の要素数、横方向の要素数
機 能 迷路を表示する
void ShowMaze(const int* const pMaze, const int row, const int col)
{
    int i;
    int j;
  
    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            if (pMaze[i * col + j] == FLOOR) {
                printf("□");
            }
            else {
                printf("■");
            }
        }
        printf("\n");
    }
}

スタート、ゴールは今回は設定しません。

<sample program 171-06>

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    DecideMazeSize(&row, &col);

    if (!AllocateMazeArea(&pMaze, row * col)) {
        return 1;
    }

    InitializeMaze(pMaze, row, col);

    GenerateMaze(pMaze, row, col);

    ShowMaze(pMaze, row, col);

    return 0;
}

6.領域の解放

関数名 ReleaseMazeArea
戻り値 なし
引 数 迷路用領域の先頭アドレス
機 能 迷路用領域を解放する
void ReleaseMazeArea(int *pMaze)
{
    free(pMaze);

    pMaze = NULL;
}

領域の解放(リリース)とダングリングポインタ対応をします。

<sample program 171-06>

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    DecideMazeSize(&row, &col);

    if (!AllocateMazeArea(&pMaze, row * col)) {
        return 1;
    }

    InitializeMaze(pMaze, row, col);

    GenerateMaze(pMaze, row, col);

    ShowMaze(pMaze, row, col);

    ReleaseMazeArea(pMaze);

    return 0;
}

最後にプログラム全体を書いておきます。

<sample program 171-07>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define DIRECTION 4

enum {
    FLOOR,
    WALL,
};

enum {
    UP,
    RIGHT,
    DOWN,
    LEFT,
};

void DecideMazeSize(int *pRow, int *pCol);

int AllocateMazeArea(int **ppMaze, const int size);

void InitializeMaze(int* const pMaze, const int row, const int col);

void GenerateMaze(int* const pMaze, const int row, const int col);

void ShowMaze(const int* const pMaze, const int row, const int col);

void ReleaseMazeArea(int *pMaze);

int main(void)
{
    int row;
    int col;

    int *pMaze;

    srand((unsigned int)time(NULL));

    DecideMazeSize(&row, &col);

    if (!AllocateMazeArea(&pMaze, row * col)) {
        return 1;
    }

    InitializeMaze(pMaze, row, col);

    GenerateMaze(pMaze, row, col);

    ShowMaze(pMaze, row, col);

    ReleaseMazeArea(pMaze);

    return 0;
}

void DecideMazeSize(int *pRow, int *pCol)
{
    *pRow = 7 + (rand() % 5) * 2;
    *pCol = 7 + (rand() % 5) * 2;
}

int AllocateMazeArea(int **ppMaze, const int size)
{
    *ppMaze = (int*)malloc(sizeof(int) * size);

    if (!*ppMaze) {
        return 0;
    }

    return 1;
}

void InitializeMaze(int* const pMaze, const int row, const int col)
{
    int i;
    int j;

    for (i = 1; i < row - 1; i++) {
        for (j = 1; j < col - 1; j++) {
            pMaze[i * col + j] = FLOOR;
        }
    }

    for (i = 0; i < row; i++) {
        pMaze[i * col] = WALL;
        pMaze[i * col + (col - 1)] = WALL;
    }

    for (j = 1; j < col - 1; j++) {
        pMaze[col] = WALL;
        pMaze[(row - 1) * col + j] = WALL;
    }
}

void GenerateMaze(int* const pMaze, const int row, const int col)
{
    int i;
    int j;

    for (i = 2; i < row - 2; i += 2) {
        for (j = 2; j < col - 2; j += 2) {

            pMaze[i * col + j] = WALL;

            switch (rand() % DIRECTION) {
            case UP:
                pMaze[(i - 1) * col + j] = WALL;
                break;
            case RIGHT:
                pMaze[i * col + (j + 1)] = WALL;
                break;
            case DOWN:
                pMaze[(i + 1) * col + j] = WALL;
                break;
            case LEFT:
                pMaze[i * col + (j - 1)] = WALL;
                break;
            }
        }
    }
}

void ShowMaze(const int* const pMaze, const int row, const int col)
{
    int i;
    int j;

    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            if (pMaze[i * col + j] == FLOOR) {
                printf("□");
            }
            else {
                printf("■");
            }
        }
        printf("\n");
    }
}

void ReleaseMazeArea(int *pMaze)
{
    free(pMaze);

    pMaze = NULL;
}

<実行結果>

■■■■■■■■■■■■■
■□□□□□□□■□■□■
■□■□■■■■■□■□■
■□■□■□□□□□■□■
■□■□■□■■■■■□■
■□■□□□■□■□□□■
■■■□■■■□■■■□■
■□□□□□□□□□□□■
■■■■■■■■■■■■■
続行するには何かキーを押してください・・・

次へ

戻る

目次へ