演習課題「ループ処理で値を取り出す」
コードエリアにはキューを実現するプログラムがあります。
キューの各要素は RPG の敵を表す構造体です。
コードを修正し、ループ処理でキューから各要素を取り出してメッセージを出力してください。
プログラムを実行して、正しく出力されれば演習課題クリアです!
期待する出力値
スライムは勇者を攻撃した。5のダメージ!
モンスターは勇者を攻撃した。10のダメージ!
ドラゴンは勇者を攻撃した。20のダメージ!
#08:RPGの攻撃シーンをつくろう
今回のチャプターでは、キューを使った具体例として、RPGの攻撃シーンを出力するプログラムを作成します。
// RPGの攻撃シーンをつくろう
#include <stdio.h>
#define N 10
typedef int data_t;
data_t queue[N];
int head;
int tail;
void init(void)
{
head = 0;
tail = 0;
}
void enqueue(data_t x)
{
if (head == (tail + 1) % N) {
printf("queue overflow\n");
return;
}
queue[tail] = x;
tail = (tail + 1) % N;
}
void dequeue(data_t *x)
{
if (head == tail) {
printf("queue underflow\n");
return;
}
*x = queue[head];
head = (head + 1) % N;
}
int main(void)
{
}
キューの要素のデータ型は data_t としています。
typedef のところを変更すれば、実際にキューで使うデータ型を変更できます。// キューの要素を構造体にする
typedef struct {
char name[20];
int hp;
} data_t;
◯ キューに追加する data_t slime = {"スライム", 5};
data_t monster = {"モンスター", 10};
data_t dragon = {"ドラゴン", 20};
enqueue(slime);
enqueue(monster);
enqueue(dragon);
※ 構造体から宣言した変数は、通常の変数と同じように関数の引数で渡すことができます。
◯ キューから取り出す data_t target;
dequeue(&target);
printf("%s\n", target.name);
キューでデータを取り出すには、data_t 型の変数 target を使う必要があります。
dequeue の引数に &target を指定して、target の値をキューから取り出した値に書き換えます。
1 から 10 のランダムな数は、次のようにして生成できます。#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
srand(time(NULL));
int random = rand() % 10 + 1;
}
・srand で引数の値をもとにランダムな数を初期化しています。
・rand() でランダムな数が生成されるため、「rand() % 10 + 1」で 1 から 10 のランダムな値を生成できます。
※rand() で生成される値の最大値は、次のようにして確認できます。#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("ランダムな数の最大値 : %d\n", RAND_MAX);
}
出力 :2147483647
rand() を使うと、0 から RAND_MAX の値がランダムで生成されます。
dequeue 関数に戻り値を設定すれば、dequeue に成功したかどうかを判定できます。void dequeue(data_t *x)
{
if (head == tail) {
return 1;
}
*x = queue[head];
head = (head + 1) % N;
return 0;
}
関数の戻り値は、
・関数の処理が成功したとき 0
・関数の処理が失敗したとき 0 以外
にすることが多いので、この例では、
・dequeue が成功したとき 0
・dequeue が失敗したとき 1
にしています。
このチャプターで作成したコードです。// RPGの攻撃シーンをつくろう
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 10
typedef struct {
char name[20];
int hp;
} data_t;
data_t queue[N];
int head;
int tail;
void init(void)
{
head = 0;
tail = 0;
}
void enqueue(data_t x)
{
if (head == (tail + 1) % N) {
printf("queue overflow\n");
return;
}
queue[tail] = x;
tail = (tail + 1) % N;
}
int dequeue(data_t *x)
{
if (head == tail) {
return 1;
}
*x = queue[head];
head = (head + 1) % N;
return 0;
}
int main(void)
{
init();
data_t slime = {"スライム", 5};
data_t monster = {"モンスター", 10};
data_t dragon = {"ドラゴン", 20};
enqueue(slime);
enqueue(monster);
enqueue(dragon);
srand(time(NULL));
data_t target;
while (dequeue(&target) == 0) {
while (target.hp > 0) {
int hit = rand() % 10 + 1;
printf("%sを攻撃した。%dのダメージ!\n", target.name, hit);
target.hp -= hit;
}
printf("%sを倒した!\n", target.name);
}
}
dequeue 関数と同様に、enqueue 関数にも戻り値を設定できます。int enqueue(data_t x)
{
if (head == (tail + 1) % N) {
return 1;
}
queue[tail] = x;
tail = (tail + 1) % N;
return 0;
}
戻り値を設定すると、関数が処理に成功したかどうかを知ることができて便利です。
【ワレコのコラム】正常終了した関数の戻り値はゼロで良いか? - われこ われこ
https://www.wareko.jp/blog/should-return-value-of-normally-terminated-function-be-zero