第2回 盤面の作成
盤面を作って表示しよう
まずは、スライドパズルの盤面をプログラムの中に作って、画面に表示してみよう!
ここでは、次の4つを作ります。
Board構造体Position構造体InitBoard()PrintBoard()
Visual Studioで使う準備
Visual Studioでscanf()などを使うと、C4996の警告が出ることがあります。
授業でいつも使っているように、ファイルの一番上へ次の1行を書いておこう!
#define _CRT_SECURE_NO_WARNINGS
そのあとに、標準入出力を使うためのstdio.hを読み込みます。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
_CRT_SECURE_NO_WARNINGSは、#include <stdio.h>より前に書きます。
この先も、この2行はソースファイルの先頭に置いたまま使います。
1.盤面を構造体で表そう
今回作るスライドパズルは、横4マス、縦4マスです。
完成状態は次のようになります。
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 □
全部で16マスあるので、タイルの並びは配列で保存できます。
int tile[16];
この配列を「盤面」という1つのデータとして扱えるように、構造体にまとめてみよう!
盤面で使う定数を用意しよう!
#define BOARD_WIDTH 4
#define BOARD_HEIGHT 4
#define BLANK_TILE (BOARD_WIDTH * BOARD_HEIGHT)
BLANK_TILEは盤面のマス数と同じ16になり、空白を表す番号として使います。1~15は数字のタイルです。
穴埋め
typedef struct
{
// 横のマス数 × 縦のマス数ぶんの要素を用意する
int tile[____________________________];
} Board;
2.位置も構造体にしよう
これから、
空白はどこにある?
11番のタイルはどこにある?
という処理が必要になります。
位置は、
x → 横の位置
y → 縦の位置
で表します。
穴埋め
typedef struct
{
// 横方向の位置を表すメンバ
int ______;
// 縦方向の位置を表すメンバ
int ______;
} Position;
完成形
模範解答を見る
typedef struct
{
int tile[BOARD_WIDTH * BOARD_HEIGHT];
} Board;
typedef struct
{
int x;
int y;
} Position;
これで、
Board board;
Position pos;
のように、盤面と位置をそれぞれ1つの型として扱えます。
3.構造体を関数へ渡してみよう!
このあと作るInitBoard()では、Board構造体を関数へ渡します。
void InitBoard(Board* board)
ここに出てくる、
Board* board
は、Board構造体を指すポインタです。
構造体を関数へ渡すときは、構造体そのものを丸ごと渡すのではなく、ポインタで渡すと効率よく扱えます。
詳しい仕組みは、今は秘密にしておきます。
まずは、
構造体を関数へ渡すときはポインタで渡す
と覚えておこう!
そして、ポインタで渡された構造体のメンバへアクセスするときは、.ではなく->を使います。
board->tile
これは、
boardが指しているBoard構造体のtile
という意味です。
このあと、
board->tile[i]
という書き方が何度も出てきます。
4.完成状態の盤面を作ろう
次は、Boardの中に完成状態のデータを入れてみよう!
配列では次のようになります。
添字 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
値 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
よく見ると、
入れる数字 = 配列の添字 + 1
です。
この規則を使って、盤面を初期化するInitBoard()を作ってみよう!
穴埋め
void InitBoard(Board* board)
{
// 横のマス数 × 縦のマス数だけ繰り返す
for (int i = 0; i < ____________________________; i++)
{
// iが0なら1、1なら2…となるようにタイル番号を入れる
board->tile[i] = __________;
}
}
模範解答
模範解答を見る
void InitBoard(Board* board)
{
for (int i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; i++)
{
board->tile[i] = i + 1;
}
}
5.盤面を表示しよう
盤面ができたら、Boardの内容を4×4に表示してみよう!
tileは1次元配列ですが、画面では2次元に並べたいので、二重ループを使います。
for (int y = 0; y < BOARD_HEIGHT; y++)
{
for (int x = 0; x < BOARD_WIDTH; x++)
{
// 1マス表示
}
printf("\n");
}
ここで必要になるのが、xとyから配列の添字を求める式です。
index = y * BOARD_WIDTH + x;
穴埋め
void PrintBoard(Board* board)
{
for (int y = 0; y < BOARD_HEIGHT; y++)
{
for (int x = 0; x < BOARD_WIDTH; x++)
{
// xとyから1次元配列の添字を求める
int index = ____________________________;
// このマスが空白なら数字を表示しない
if (board->tile[index] == __________________)
{
printf(" ");
}
else
{
printf("%3d ", board->tile[index]);
}
}
printf("\n");
}
}
模範解答
模範解答を見る
void PrintBoard(Board* board)
{
for (int y = 0; y < BOARD_HEIGHT; y++)
{
for (int x = 0; x < BOARD_WIDTH; x++)
{
int index = y * BOARD_WIDTH + x;
if (board->tile[index] == BLANK_TILE)
{
printf(" ");
}
else
{
printf("%3d ", board->tile[index]);
}
}
printf("\n");
}
}
6.動作確認
int main(void)
{
Board board;
InitBoard(&board);
PrintBoard(&board);
return 0;
}
次のように表示されれば成功です。
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15
ここまでで、
盤面を作る
↓
盤面を表示する
ところまで完成しました。
盤面を表示できたね。次は、指定したタイルの位置を探して、動かせるか調べてみよう!

