====== 前回までの話(すごろくの演習問題のつづき) ======
==== 演習問題:すごろくを作ってみよう ====
すごろく
int goal_dist = 10;
盤面の構成
S_ _ _ _ _ _ _ _ _ _G
1 2 3 4 5 6 7 8 9 10コマ
Oが自分の駒(スタート状態)
SO _ _ _ _ _ _ _ _ _G
3コマ目に自分がいる
S_ _ O _ _ _ _ _ _ _G
ゴールした状態
S_ _ _ _ _ _ _ _ _ OG
⓪初期盤面表示
①サイコロ振る(賽の目表示)
rand() % 6 + 1
②盤面表示(自駒を進める)
③ゴールしたか?
(goal_distを自分の駒が過ぎたか?)
YES:おめでとうの表示
NO:2に戻る
=== 乱数とサイコロ ===
さいころは以下のように作ることができそう。\\
- 乱数の初期化(プログラム中ではじめの方で1度だけ行われればよい)
- 乱数の発生(1~6)
- あとは変数に好きにぶっこんで使う!
//乱数の初期化(1回だけやる)
srand((unsigned int)time(nullptr));
int saikoro;
//1~6の乱数を作ってsaikoroに代入
saikoro = rand() % 6 + 1;
さいころを10回振るサンプルソースコード\\
#include
using std::cout;
using std::cin;
using std::endl;
int main()
{
//const つけると定数になります。定数は変えられない数
const int goal_dist = 10;
//乱数の初期化(1回だけやる)
srand((unsigned int)time(nullptr));
//さいころを10回振る繰り返し
for (int i = 0; i < 10; i++)
{
cout << rand() % 6 + 1 << endl;
}
return 0;
}
==== すごろくの設計 ====
- 初期盤面の表示
- サイコロを振る
- コマを進める
- ゴールした?
* YES:ループを抜ける
* NO :2に戻る
- おめでとうのメッセージ表示→終了
==== 盤面の表示から考えてみる ====
盤面は以下のように表される。\\
S: スタート地点
G: ゴール地点
O: 自分のコマ
SO _ _ _ _ _ _ _ _ _G
初めに、自分のコマなしで盤面のみ表示してみる。\\
== ソースコード:盤面の表示 ==
#include
using std::cout;
using std::cin;
using std::endl;
int main()
{
//const つけると定数になります。定数は変えられない数
//すごろくのマスの数を表す
const int goal_dist = 10;
//乱数の初期化(1回だけやる)
srand((unsigned int)time(nullptr));
//盤面を表示するブロック
cout << "S";
for (int i = 1; i <= goal_dist; i++)
{
cout << "_";
}
cout << "G";
return 0;
}
== 実行結果:盤面の表示 ==
S__________G
* このままだと、"\_"が全部つながってしまって、自分が何コマ目にいるか分かりづらい。
* スペースを空けるなど工夫してみよう
* 例:S_ _ _ _ _ _ _ _ _ _G
* スペースの表示の仕方とGの表示の仕方でちょっと条件判断がひつようになるよね
==== 盤面に自分のコマを表示 ====
自分のコマが今どこにいるかという変数を考える。\\
//盤面上の位置を1~goal_distで表す
int piece = 1;
この変数を使って、現在の盤面を表示するときに、\\
マスの位置=自コマの位置なら、"O"\\
それ以外なら、"_"を表示するように改良する。\\
== ソースコード:自コマの表示 ==
#include
using std::cout;
using std::cin;
using std::endl;
int main()
{
//const つけると定数になります。定数は変えられない数
//すごろくのマスの数を表す
const int goal_dist = 10;
//乱数の初期化(1回だけやる)
srand((unsigned int)time(nullptr));
//すごろくのコマを表す(1がスタート、goal_distがゴール)
int piece = 4;//特に意味はないが4マス目にいることにする
//盤面を表示するブロック
cout << "S";//スタートを表示
for (int i = 1; i <= goal_dist; i++)
{
//iがpieceと同じときは"O"それ以外はマス"_"を表示
if (i == piece)
{cout << "O";} //自コマを表示するブロック
else
{cout << "_";} //マスを表示するブロック
//goal_dist回目はスペースじゃなくGoalを表示
if (i != goal_dist)
{cout << " ";} //最後以外はスペースを入れる
else
{cout << "G";} //最後はスペースじゃなくゴール(G)
}
return 0;
}
== 実行結果:自コマの表示 ==
goal_dist = 10で\\
piece = 1 のとき\\
SO _ _ _ _ _ _ _ _ _G
goal_dist = 10で\\
piece = 4 のとき\\
S_ _ _ O _ _ _ _ _ _G
* goal\_distを変えると盤面のマスの数が変化するよね?
* 自分のマスの位置とgoal\_distを変更して、表示がどう変化するかいろいろ試してみよう
==== せめて、すごろくらしく ====
最後に、すごろくとして完成させる!\\
- 初期盤面の表示
- サイコロを振る
- コマを進める
- ゴールした?
* YES:ループを抜ける
* NO :2に戻る
- おめでとうのメッセージ表示→終了
どのようにループを組み合わせれば、サイコロを振ってゴールまでコマを進められるかな?\\
繰り返しの条件、つまりゴールの条件
初めは、ゴールを超えたら、ゴール!
{
サイコロ振る
コマ進める
//盤面を表示する繰り返し
現在の盤面が表示される
SO _ _ _ _ _ _ _ _ _G
}
ループ抜けたら、ゴールしてるはずだから。。。
cout << "ゴール!おめでとう!" << endl;
追加:
さいころがピッタリじゃないとゴールできない
進めなかったり、戻ったりを追加
* ゲームとして考えてみると、すごろくはゲーム開始後必ず一度はサイコロを振って駒を進める処理を行う
* 。。。という事は、前判定?後判定?どちらが適していますか?
* 応用として、今回盤面の表示は、初期盤面と、ゲーム中の盤面表示と、同じループブロックを2回も書きました
* 現代的なプログラムでは同じことを2回書くのは無駄とされています。
* こんな時はどうすればいいのか調べてみよう