第4回 そのタイル動くよ!
タイルを動かそう
SearchTile()とCanMoveTile()を使って、実際にタイルを動かすMoveTile()を作ってみよう!
1.タイルを動かすには何が必要?
例えば、次の盤面を考えます。
1 2 3 4
5 6 7 8
9 10 12
13 14 11 15
11番のタイルを動かすと、
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15
になります。
実際にやっていることは、
11番のタイル
と、
空白
の場所を入れ替えているだけです。
2.処理を順番に考えよう
いきなりプログラムを書く前に、まずは何をすればよいか順番に考えてみよう!
① 指定したタイルが動かせるか調べる
② 空白の位置を探す
③ 指定したタイルの位置を探す
④ 2つの位置を配列の添字に変換する
⑤ 配列の中身を入れ替える
使える関数を当てはめると、
① → CanMoveTile()
② → SearchTile()
③ → SearchTile()
でできます。
つまり今回新しく考えるのは、
位置を配列の添字に変換する
値を入れ替える
という部分です。
3.動かせないなら何もしない
まずは、指定したタイルが動かせるか調べよう!
動かせないなら、その場で関数を終了すればよいです。
if (CanMoveTile(board, number) == 0)
{
return;
}
CanMoveTile()は、
動かせる → 1
動かせない → 0
を返すので、0だったらその場でreturnします。
4.空白とタイルの位置を探す
位置を探す処理には、作っておいたSearchTile()を使おう!
どの関数を使えばよいか考えて、穴を埋めてみよう!
穴埋め
Position blank = ________________________________;
Position tile = _________________________________;
ヒント
空白を探すときは、
BLANK_TILE
を使います。
指定したタイルの番号は、
number
に入っています。
5.位置を配列の添字に変換する
SearchTile()で分かるのは、
x
y
です。
しかし、実際に書き換えるのは、
board->tile[index]
という1次元配列です。
盤面を表示するときに使った式をもう一度使います。
index = y × BOARD_WIDTH + x
穴埋め
int blankIndex = ________________________________________;
int tileIndex = _________________________________________;
ここも、自分で式を組み立ててください。
6.2つの値を入れ替える
例えば、
A = 11
B = 16
を入れ替えたいとします。
いきなり、
A = B;
B = A;
とすると、
最初の行でAが16になってしまうので、
A = 16
B = 16
となってしまいます。
そこで、一時的に値を保存する変数を使います。
int temp = A;
A = B;
B = temp;
これで、
A = 16
B = 11
と正しく入れ替えられます。
同じことを、タイルと空白で行います。
7.MoveTile()を完成させよう
これまでに作った関数を使って、MoveTile()を完成させよう!
void MoveTile(Board* board, int number)
{
if (CanMoveTile(board, number) == 0)
{
return;
}
Position blank = ________________________________;
Position tile = _________________________________;
int blankIndex = ________________________________________;
int tileIndex = _________________________________________;
int temp = board->tile[blankIndex];
_________________________________________________;
_________________________________________________;
}
8.動作確認をしよう
例えば、完成状態では15番のタイルを動かせます。
int main(void)
{
Board board;
InitBoard(&board);
PrintBoard(&board);
printf("\n");
MoveTile(&board, 15);
PrintBoard(&board);
return 0;
}
最初は、
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15
です。
15番を動かしたあと、
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15
のように空白と15番が入れ替われば成功です。
9.模範解答
模範解答を見る
void MoveTile(Board* board, int number)
{
if (CanMoveTile(board, number) == 0)
{
return;
}
Position blank = SearchTile(board, BLANK_TILE);
Position tile = SearchTile(board, number);
int blankIndex = blank.y * BOARD_WIDTH + blank.x;
int tileIndex = tile.y * BOARD_WIDTH + tile.x;
int temp = board->tile[blankIndex];
board->tile[blankIndex] = board->tile[tileIndex];
board->tile[tileIndex] = temp;
}
今回作ったのはMoveTile()です。
10.関数を組み合わせて処理を作った
今回のMoveTile()では、
CanMoveTile()
SearchTile()
を使っています。
つまり、
タイルを探す
動かせるか調べる
という処理をもう一度自分で書いたわけではありません。
前に作った関数を使って、
タイルを実際に動かす
という、さらに大きな処理を作っています。
関数を作るときは、
その関数の中ですべてを自分でやる必要はありません。
すでに使える関数があるなら、それを使った方が短く、分かりやすく書けます。
タイルを動かせるようになったので、次は盤面が完成したかを判定します。

