講座全体の概要
プログラミング基礎講座の総仕上げ、「ハイ&ロー」というトランプゲームを作成する実践演習です。数回に分けてヒントや実際のプログラム例の提示、解説等を行っていきます。今回は初心者におすすめするプログラミングの進め方をお伝えします。講座全体の概要は以下の記事ゼロから始めるプログラミング基礎講座 第1回【講座の概要・目的】をご覧ください。
演習の目的
これまではプログラミングの様々な要素を個別に学習してきましたが、実際に1つのアプリケーション(プログラム)を最初から最後まで作成することで、それらの要素をどういった場面で使用し、どう組み合わせればいいのかを考える機会となります。これにより、それぞれの要素の理解が深めつつ、自分でプログラミングしたアプリケーションが動作する喜びと自信を付けていただきたいと思います。また、プログラミングの全体の流れ、何から始めてどう進めていけばいいのかも体感していただきたいと思います。
プログラミングは、知識を詰め込んでもそれほど意味はありません。基本だけ学習したら、あとは実践あるのみです。基本だけ押さえてあれば、あとは必要な時に必要な分だけ調べて実践していけば、自然と技術も上がっていきます。
課題の選定
自分で何か作りたいアプリケーションが既にある方は、必ずしもここで提示している課題でなくても構いません。とにかく、何か1つ目標とするアプリケーションを作ってください。
私が用意した課題は、プログラミングの基本的な要素をできるだけ網羅でき、結果が目で見てわかりやすいものとしてゲームを選びました。また、ゲームのルール自体もできるだけ単純なものを選んでいます。
演習課題 C#のWebアプリケーションとしてハイ&ローを作成
今回作成するゲームのルールは以下の通りとします。
ハイ&ローのルール
- ①ジョーカーを除くカード52枚をよく切り、2人に均等の枚数を裏向きで配る。配られたカードは裏向きのまま山にしておく。
- ②親および子を決める。
- ③親が自分の山の一番上からカードを1枚取り、表向きに置く。
- ④子が自分の山の一番上からカードを1枚取り、裏向きにおく。
- ⑤子は自分のカードが親のカードより大きい(ハイ)か小さい(ロー)かを予想して宣言する。
- ⑥子は自分のカードを表向きにし、予想が当たっていれば出されている2枚のカードを獲得する。はずれた場合は親が2枚獲得する。ただし、2枚が同じ数字の場合は自分のカードを1枚ずつ獲得する。(獲得したカードは山に戻さない。)
- ⑦親子を交代して③から⑦を繰り返し、山がなくなったら終了。
- ⑧最終的に獲得した枚数が多い人が勝ちとなる。
使用言語等
基本的にはこれまでの講座で使用してきたC#のWebアプリケーションを前提として話を進めますが、他の言語等でもできる内容です。
何から始めればいいのか?
プログラミングに不慣れな方は、まず何から始めていいのかわからないですよね。プログラミングを独学していると、特につまずく場面です。プログラミングに慣れている私でも、大きな課題(プログラム)に当たったときは、何から始めてどう進めていくか迷うことは多々あります。慣れてくると、ポイントになりそうな難しい部分が大体わかるので、まずそれをクリアしてから進めるということもできます。ですが、最初の内は、何がポイントになるかわかりませんよね。そこで、私がおすすめする進め方をお話しします。これは私自身もシステム開発の現場で実践してきた方法です。(そんなたいそうなものではありませんが。)
1.目標を明確にする。課題をしっかり理解する。
まずは作ろうとしているものをしっかり理解することから始めます。理解せずにプログラミングを始めると、途中で迷って、元に戻ってやりなおしたりすることが多くなります。
今回の課題では、まずゲームのルールをしっかり理解しましょう。また、それをどんなプログラムにするのかも明確なイメージをしましょう。ここでイメージするのは、プログラムの書き方ではなく、使い方です。
もっと具体的に言うと、画面のレイアウト、入力の仕方、ボタン等を押した時の画面の変化、途中経過・最終結果の表示の仕方をイメージします。すなわち仕様を明確にするということです。
今回は自分一人で行うものなので、仕様を何かに書き起こしたりする必要はありませんが、考えを整理したり、忘れないために何かに書き起こすことも自由です。
ただ、仕様を明確にするといっても、間違っていたり、考慮が足りなかったりしてもそれは構いません。それは気づいた時に対応すればいいので、考えすぎないようにしましょう。
2.抽象化 大まかな流れを考え、いくつかのステップに分解する。
ここからは、プログラムの中身について考えていきますが、考えたことをプログラムとして書きながら進めていきます。
ただし、最初から詳細に考えるのではなく、抽象的に考えて、いくつかのステップに分解して大まかな流れを決めます。
・カードを配る
・親と子でそれぞれ1枚のカードを表示する
・ハイかローを入力させて当たりはずれを表示する
・親と子を交代する
・次のカードを表示して繰り返す
・最後に合計点数を表示する
今回の課題であれば、だいたいこんな感じです。この段階で、「繰り返し処理があるから、この部分はループだな。」というようにイメージできるといいです。
また、ページを最初に表示する時(OnGet)、画面でボタンが押された時(OnPost~)といった処理のきっかけが複数あると思います。このような処理のきっかけのことをイベントと言いますが、処理の流れはイベントごとに分けて考えましょう。
ここで考えた各ステップそれぞれをメソッド(関数)としてプログラミングしていきましょう。ただし、メソッドの中身はまだ考えていませんので、空っぽでかまいません。
public IActionResult OnPostGameStart()
{
DealCards();
SetCurrentCard();
return Page();
}
// カードを配る
private void DealCards()
{
}
// 親と子でそれぞれ1枚のカードを表示する(実際の表示はcshtmlで行うので、ここでは配られたカードから1枚ずつ取得する。)
private void SetCurrentCard()
{
}
3.具体化 分解したステップの1つに注目し、詳細化する。
次に、先ほど考えた中の1つに注目して、より具体的にしていきます。何から注目してもいいですが、特に理由がなければ上から順に考えましょう。
「カードを配る」についてもう少し具体的に考えた例です。
・トランプ52枚を用意する
・52枚をシャッフルする
・52枚を2つに分ける
ここで考えた各ステップもそれぞれをメソッドとしてプログラミングします。そして、これらのメソッドの呼び出しが「カードを配る」メソッドの中身の処理となります。
先ほどのゲーム開始時の例だと、以下の部分を実装することになります。
// カードを配る
private void DealCards()
{
// ここに処理を書く。まだ具体化が十分でなければメソッドにしておく。
}
4.抽象化→具体化 を繰り返す
抽象的なステップを具体化していき、実際の処理がイメージできるぐらい十分具体化できたら、そのメソッド内に具体的な処理を実装します。
このように、最初は抽象的に考えて、徐々に具体的にしていくようにすると、全体像を見失うことなく、着実に進めていくことができます。
この考え方については以下の記事小学生にプログラミング学習は必要ない。プログラミング的思考とは何か。も参考にしてください。
これまでの講座で取り扱っていない事項について
これまでの講座の内容ではトランプのマークと数字をペアで管理したり、画面に表示したりする方法は触れていません。
これらの部分については私があらかじめソースコードを用意しましたので、以下からファイルをダウンロードしてください。
ファイルはzip形式で圧縮されており、展開すると以下の2つのファイルがあります。
- Cards.cs
- トランプカードを表す「Card」というクラス(型)等、トランプカードに関する処理を記述したもの。
- CustomTempDataSerializer.cs
- 「Card」をTempDataに保存できるようにするための処理を記述したもの。
上記ソースコードのプロジェクトへの追加方法
まず始めに、「HighAndLow」という名前でプロジェクトを作成してください。プロジェクト名を間違えないように気を付けてください。
続いて、先ほどの2つのファイルをプロジェクトへ追加します。
画面の右側にあるソリューションエクスプローラーで、ソリューションのすぐ下にある「HighAndLow」がプロジェクトファイルです。ここを右クリックして、メニューから[追加]→[既存の項目]を選択してください。
そうすると追加するファイルを指定する画面が表示されますので、展開しておいた2つのファイルを選択して[追加]を押してください。すると、ソリューションエクスプローラーに2つファイルが表示されるはずです。
追加ができたら、ソリューションエクスプローラーから「Startup.cs」を開いてください。これはVisual Studioで最初から作られているファイルですが、一部を変更する必要があります。以下の通りに変更してください。(コピペでOK)
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
public void ConfigureServices(IServiceCollection services)
{
var descriptor = ServiceDescriptor.Singleton(typeof(TempDataSerializer), typeof(CustomTempDataSerializer));
services.AddRazorPages().Services.Replace(descriptor);
}
通常、このファイルを変更する必要はほとんどありませんが、今回はCustomTempDataSerializer.csを有効にするために変更する必要があります。これについては覚える必要もありませんので、詳細は気にせずに進めてください。(説明も省きます。)
Cardクラスの使用方法
以下の使用例を参考にしてください。
namespace HighAndLow.Pages
{
public class IndexModel : PageModel
{
// TempData属性を付けることでCardクラスを保存できる。
[TempData]
public Card SampleCard { get; set; }
// TempData属性を付けることでCardクラスを要素に持つリストも保存できる。
[TempData]
public List<Card> SampleCards { get; set; }
private void Sample()
{
Cards cards = new Cards(); // Cardsクラスを初期化すると52枚のカードがシャッフルされた状態で作成されます。
SampleCards = new List<Card>();
foreach (Card card in cards)
{
// 初期化したCardsクラスの変数をforeachでループすると、1枚ずつカードを取り出せます。Cardクラスは1枚のカードを表します。
int number = card.Number; // カードの数字を取得。
CardMark mark = card.Mark; // カードのマークを取得。
SampleCards.Add(card); // Listにカードを追加。
}
SampleCard = SampleCards[0]; // Listの先頭からカードを取得。
}
}
}
@page "{handler?}"
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1>Sample</h1>
<div class="container-fluid mb-4">
<div class="row">
<div class="col-6 d-flex flex-column" id="PlayerCard">
<span>カードの表を表示</span>
@Model.SampleCard.CardImage.FrontImageToHtml();
</div>
<div class="col-6 d-flex flex-column" id="CpuCard">
<span>カードの裏を表示</span>
@Model.SampleCard.CardImage.BackImageToHtml();
</div>
</div>
</div>
</div>
@{
// 参照したTempDataが消えないようにする場合は以下の文を追加する。
TempData.Keep();
}
今回は以上です。次回は難しいポイントについてヒントとなるような解説をします。
この記事へのコメントはありません。