さて、再帰呼び出しの使い道について、実用的とは言えませんが、少し趣向を変えてみましょう。
今回の題材は「画像の塗りつぶし」です。
ペイントツールなどで、閉ざされた領域をある色で塗りつぶすことをイメージしてみてください。
例えば、こんな絵を、
塗りつぶしツールを使って、
のように塗りつぶすイメージです。
ただ、2Dグラフィックは扱えませんので、あくまでもコンソールで作ります。
迷路などで使った2次元配列を利用して、疑似的な画像を作ります。
<画像イメージ> □□□□□□□□□□□ □□□□□□□□□□□ □□□□□□□□□□□ □□■□□□□□■□□ □□□■□□□■□□□ □□■■■■■■■□□ □■■□■■■□■■□ ■■■■■■■■■■■ ■□■■■■■■■□■ ■□■□□□□□■□■ □□□■■□■■□□□
まずはこれを作りましょう。
□と■を使いますので、配列内では0と1で表現することにしましょう。
まずは必要なものを考えます。
2次元配列の縦は11マス、横も11マスです。
これは#defineで定義しましょう。
□を0、■を1で表現しますが、WHITEとBLACKという定数をenumで用意します。
2次元配列fieldを用意し、初期値を入れて表示するところまで作りましょう。
表示にはShowField関数を作成し、2次元配列を渡して表示します。
<sample program 150-01>
#include <stdio.h>
#define ROW 11
#define COL 11
enum {
WHITE,
BLACK,
};
void ShowField(const int field[ROW][COL]);
int main(void)
{
int field[ROW][COL] = {
{ 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, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1 },
{ 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
};
ShowField(field);
return 0;
}
void ShowField(const int field[ROW][COL])
{
int i;
int j;
for (i = 0; i < ROW; i++) {
for (j = 0; j < COL; j++) {
switch (field[i][j]) {
case WHITE:
printf("□");
break;
case BLACK:
printf("■");
break;
}
}
printf("\n");
}
printf("\n");
}
|
<実行結果>
□□□□□□□□□□□ □□□□□□□□□□□ □□□□□□□□□□□ □□■□□□□□■□□ □□□■□□□■□□□ □□■■■■■■■□□ □■■□■■■□■■□ ■■■■■■■■■■■ ■□■■■■■■■□■ ■□■□□□□□■□■ □□□■■□■■□□□ 続行するには何かキーを押してください・・・
画像の準備は出来ました。
コンソールではマウスが使えませんので、どの領域を塗りつぶすか座標を入力することで選択します。
そのために、以前作った「宝探し」のように座標を表示しましょう。
<sample program 150-02>
#include <stdio.h>
#define ROW 11
#define COL 11
enum {
WHITE,
BLACK,
};
void ShowField(const int field[ROW][COL]);
int main(void)
{
int field[ROW][COL] = {
{ 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, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1 },
{ 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
};
ShowField(field);
return 0;
}
void ShowField(const int field[ROW][COL])
{
int i;
int j;
printf(" 0 1 2 3 4 5 6 7 8 9 10\n");
for (i = 0; i < ROW; i++) {
printf("%2d ", i);
for (j = 0; j < COL; j++) {
switch (field[i][j]) {
case WHITE:
printf("□");
break;
case BLACK:
printf("■");
break;
}
}
printf("\n");
}
printf("\n");
}
|
<実行結果>
0 1 2 3 4 5 6 7 8 9 10 0 □□□□□□□□□□□ 1 □□□□□□□□□□□ 2 □□□□□□□□□□□ 3 □□■□□□□□■□□ 4 □□□■□□□■□□□ 5 □□■■■■■■■□□ 6 □■■□■■■□■■□ 7 ■■■■■■■■■■■ 8 ■□■■■■■■■□■ 9 ■□■□□□□□■□■ 10 □□□■■□■■□□□ 続行するには何かキーを押してください・・・
次に塗りつぶす座標を入力出来るように、変数xとyを作り、入力出来るようにします。
<sample program 150-03>
#include <stdio.h>
#define ROW 11
#define COL 11
enum {
WHITE,
BLACK,
};
void ShowField(const int field[ROW][COL]);
int main(void)
{
int x;
int y;
int field[ROW][COL] = {
{ 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, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1 },
{ 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
};
ShowField(field);
do {
printf("Input X:");
scanf("%d", &x);
} while (x < 0 || x >= COL);
do {
printf("Input Y:");
scanf("%d", &y);
} while (y < 0 || y >= ROW);
return 0;
}
void ShowField(const int field[ROW][COL])
{
int i;
int j;
printf(" 0 1 2 3 4 5 6 7 8 9 10\n");
for (i = 0; i < ROW; i++) {
printf("%2d ", i);
for (j = 0; j < COL; j++) {
switch (field[i][j]) {
case WHITE:
printf("□");
break;
case BLACK:
printf("■");
break;
}
}
printf("\n");
}
printf("\n");
}
|
<実行結果>
0 1 2 3 4 5 6 7 8 9 10 0 □□□□□□□□□□□ 1 □□□□□□□□□□□ 2 □□□□□□□□□□□ 3 □□■□□□□□■□□ 4 □□□■□□□■□□□ 5 □□■■■■■■■□□ 6 □■■□■■■□■■□ 7 ■■■■■■■■■■■ 8 ■□■■■■■■■□■ 9 ■□■□□□□□■□■ 10 □□□■■□■■□□□ Input X:5 Input Y:0 続行するには何かキーを押してください・・・
さて、ここからが本番です。
指定した座標を含む領域を塗りつぶすプログラムを考えます。
今のところ、色は白黒しか使えませんので、図形の「☆」で塗りつぶすことにします。
仮に、「☆」を赤(RED)としましょう。
enumに追加するのと、表示のところにも追加します。
<sample program 150-04>
#include <stdio.h>
#define ROW 11
#define COL 11
enum {
WHITE,
BLACK,
RED,
};
void ShowField(const int field[ROW][COL]);
int main(void)
{
int x;
int y;
int field[ROW][COL] = {
{ 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, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1 },
{ 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
};
ShowField(field);
do {
printf("Input X:");
scanf("%d", &x);
} while (x < 0 || x >= COL);
do {
printf("Input Y:");
scanf("%d", &y);
} while (y < 0 || y >= ROW);
return 0;
}
void ShowField(const int field[ROW][COL])
{
int i;
int j;
printf(" 0 1 2 3 4 5 6 7 8 9 10\n");
for (i = 0; i < ROW; i++) {
printf("%2d ", i);
for (j = 0; j < COL; j++) {
switch (field[i][j]) {
case WHITE:
printf("□");
break;
case BLACK:
printf("■");
break;
case RED:
printf("☆");
break;
}
}
printf("\n");
}
printf("\n");
}
|
<実行結果>
0 1 2 3 4 5 6 7 8 9 10 0 □□□□□□□□□□□ 1 □□□□□□□□□□□ 2 □□□□□□□□□□□ 3 □□■□□□□□■□□ 4 □□□■□□□■□□□ 5 □□■■■■■■■□□ 6 □■■□■■■□■■□ 7 ■■■■■■■■■■■ 8 ■□■■■■■■■□■ 9 ■□■□□□□□■□■ 10 □□□■■□■■□□□ Input X:0 Input Y:10 続行するには何かキーを押してください・・・
最後に再帰呼び出し用の関数を考えます。
塗りつぶすために必要なデータは以下の通りです。
配列 field 座標 x, y 元の色 sourColor 選択した座標の色情報 新しい色 destColor 今回は赤(RED) |
これらを引数として関数Fillを作成します。
<プロトタイプ宣言>
void Fill(int field[ROW][COL], const int x, const int y, const int sourColor, const int destColor); |
長いですが、必要なデータです。
field内で指定された座標(x,y)の色(sourColor)を新しい色(destColor)で塗りつぶします。
いきなり関数を書くのではなく、まずは流れを書いてみます。
<再帰呼び出し用:Fill関数> 1.field内の指定された座標を新しい色で書き換えます。 2.指定された座標の1つ上のマスを調べて、sourColorと同じ色であれば、座標を変えてFill関数を呼び出します。 3.指定された座標の1つ右のマスを調べて、sourColorと同じ色であれば、座標を変えてFill関数を呼び出します。 4.指定された座標の1つ下のマスを調べて、sourColorと同じ色であれば、座標を変えてFill関数を呼び出します。 5.指定された座標の1つ左のマスを調べて、sourColorと同じ色であれば、座標を変えてFill関数を呼び出します。
隣り合ったマス(上下左右)の色がsourColorと同じであれば、自分自身を呼び出すのです。
1は簡単に、
field[y][x] = destColor; |
これでOKです。
2以降は少し考えなければなりません。
1つ上のマスを見てsourColorと同じかどうか調べるプログラムは、
if (field[y - 1][x] == sourColor) |
で作れますが、座標によってはマズい状況になります。
もし、指定された座標が画像の左上(x = 0, y = 0)であった場合、
field[y - 1][x] |
は
field[0 - 1][0] |
となり、
field[-1][0] |
になるため、配列の領域を超えてしまいます。
端の座標を選択することも考慮し、次のようにすれば大丈夫です。
if (y - 1 > 0) {
if(field[y - 1][x] == sourColor) {
}
}
|
座標を変えてFill関数を呼び出すというのは、1つ上の色がsourColorと同じであれば、1つ上のマスを塗りつぶすため、1つ上の座標を指定して自分自身を呼び出します。
if (y - 1 > 0) {
if(field[y - 1][x] == sourColor) {
Fill(field, x, y - 1, sourColor, destColor);
}
}
|
これで、1つ上の座標を使ってFill関数を呼び出せます。
それでは、完成形を作りましょう。
<sample program 150-05>
#include <stdio.h>
#define ROW 11
#define COL 11
enum {
WHITE,
BLACK,
RED,
};
void ShowField(const int field[ROW][COL]);
void Fill(int field[ROW][COL], const int x, const int y, const int sourColor, const int destColor);
int main(void)
{
int x;
int y;
int field[ROW][COL] = {
{ 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, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1 },
{ 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0 },
};
ShowField(field);
do {
printf("Input X:");
scanf("%d", &x);
} while (x < 0 || x >= COL);
do {
printf("Input Y:");
scanf("%d", &y);
} while (y < 0 || y >= ROW);
Fill(field, x, y, field[y][x], RED);
ShowField(field);
return 0;
}
void ShowField(const int field[ROW][COL])
{
int i;
int j;
printf(" 0 1 2 3 4 5 6 7 8 9 10\n");
for (i = 0; i < ROW; i++) {
printf("%2d ", i);
for (j = 0; j < COL; j++) {
switch (field[i][j]) {
case WHITE:
printf("□");
break;
case BLACK:
printf("■");
break;
case RED:
printf("☆");
break;
}
}
printf("\n");
}
printf("\n");
}
void Fill(int field[ROW][COL], const int x, const int y, const int sourColor, const int destColor)
{
field[y][x] = destColor;
if (y - 1 >= 0) {
if (field[y - 1][x] == sourColor) {
Fill(field, x, y - 1, sourColor, destColor);
}
}
if (x + 1 < COL) {
if (field[y][x + 1] == sourColor) {
Fill(field, x + 1, y, sourColor, destColor);
}
}
if (y + 1 < ROW) {
if (field[y + 1][x] == sourColor) {
Fill(field, x, y + 1, sourColor, destColor);
}
}
if (x - 1 >= 0) {
if (field[y][x - 1] == sourColor) {
Fill(field, x - 1, y, sourColor, destColor);
}
}
}
|
<実行結果>
0 1 2 3 4 5 6 7 8 9 10 0 □□□□□□□□□□□ 1 □□□□□□□□□□□ 2 □□□□□□□□□□□ 3 □□■□□□□□■□□ 4 □□□■□□□■□□□ 5 □□■■■■■■■□□ 6 □■■□■■■□■■□ 7 ■■■■■■■■■■■ 8 ■□■■■■■■■□■ 9 ■□■□□□□□■□■ 10 □□□■■□■■□□□ Input X:0 Input Y:10 0 1 2 3 4 5 6 7 8 9 10 0 □□□□□□□□□□□ 1 □□□□□□□□□□□ 2 □□□□□□□□□□□ 3 □□■□□□□□■□□ 4 □□□■□□□■□□□ 5 □□■■■■■■■□□ 6 □■■□■■■□■■□ 7 ■■■■■■■■■■■ 8 ■☆■■■■■■■□■ 9 ■☆■□□□□□■□■ 10 ☆☆☆■■□■■□□□ 続行するには何かキーを押してください・・・
※色々な座標を指定して試してみてください。
最後に、どのように動作しているのか順を追って見てみましょう。
まず、最初の状態を数値で表したのが↓です。
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 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 1 0 1 1 0 0 0
指定した座標が、
X 0 Y 10
だとすると起点はここです。
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 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 0 1
1 0 1 0 0 0 0 0 1 0 1
0 0 0 1 1 0 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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 0 1
1 0 1 0 0 0 0 0 1 0 1
2 0 0 1 1 0 1 1 0 0 0
こうなります。
関数内で次につながっているマスをチェックする順番は「上右下左」の順ですから、次は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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 0 1
1 0 1 0 0 0 0 0 1 0 1
2 0 0 1 1 0 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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 0 1
1 0 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 1 1 0 0 0
ここからまた「上右下左」の順番にチェックしていきます。
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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 0 1
1 0 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 1 1 0 0 0
起点が変わったので、また「上右下左」の順でチェックします。
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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 1 1 0 0 0
ここから「上右下左」をチェックしますが、どこも塗り替えるべき色ではありません。
塗り替えるマスが無いので、この関数は終わり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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 1 1 0 0 0
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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 0 1 1 0 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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 2 1 1 0 1 1 0 0 0
ここでも「上右下左」をチェックしますが、塗り替えるべき色はありませんので、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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 2 1 1 0 1 1 0 0 0
この起点は「上右」のみチェック済みですから「下左」をチェックします。
塗り替えるべき色はありませんので、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 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 0 0
0 1 1 0 1 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 0 1
1 2 1 0 0 0 0 0 1 0 1
2 2 2 1 1 0 1 1 0 0 0
最初の起点に戻りました。
最初の起点は「上右」のみチェック済みですから「下左」をチェックします。
塗り替えるべき色はありませんので、main関数に戻って終わりです。
最初に実用的でないと書きました。
小さい領域であれば問題無いのですが、領域が大きくなれば途中で止まってしまいます。
次回は、人気ゲームの一部を題材に再帰を使ったプログラムを作ってみましょう。