講座全体の概要
プログラミング基礎講座の総仕上げ、「ハイ&ロー」というトランプゲームを作成する実践演習です。数回に分けてヒントや実際のプログラム例の提示、解説等を行っていきます。今回は演習の回答例を掲載します。
講座全体の概要は以下の記事ゼロから始めるプログラミング基礎講座 第1回【講座の概要・目的】をご覧ください。
演習の内容等は前々回の記事ゼロから始めるプログラミング基礎講座 第9回【実践演習】PART1前回の記事ゼロから始めるプログラミング基礎講座 第9回【実践演習】PART2 ヒントにありますので、そちらを先にご覧ください。
回答例
あくまで例であり、これが唯一の正解というわけではありません。プログラムのコードが人それぞれで異なるのは当然です。自分のプログラムとの違い等を見て、「ここはこうすればもっと良かった」とか、「こんな方法があるのか」、「ここは自分の方が優れているな」、「ここは何でこうしているのだろう?」等と考えることが成長につながります。
回答例で良くわからない箇所などがあったら、当ページの下部にあるコメント欄で質問してください。
Index.cshtml.cs
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace HighAndLow.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
[TempData]
public GameState CurrentGameState { get; set; }
[TempData]
public bool PlayerIsParent { get; set; }
[TempData]
public bool HasCalled { get; set; }
[TempData]
public Card CurrentPlayerCard { get; set; }
[TempData]
public Card CurrentCpuCard { get; set; }
[TempData]
public List<Card> PlayerCards { get; set; }
[TempData]
public List<Card> CpuCards { get; set; }
[BindProperty]
public HighOrLow HighLowChoice { get; set; }
[TempData]
public int PlayerScore { get; set; }
[TempData]
public int CpuScore { get; set; }
public string ResultMessage { get; set; }
public enum HighOrLow
{
未選択,
ハイ,
ロー
}
private enum Judement
{
当たり,
はずれ,
引き分け
}
public enum GameState
{
BeforePlay,
Playing,
End
}
public void OnGet()
{
CurrentGameState = GameState.BeforePlay;
}
public IActionResult OnPostGameStart()
{
InitState();
DealCards();
SetCurrentCard();
return Page();
}
private void InitState()
{
CurrentGameState = GameState.Playing;
PlayerIsParent = false;
PlayerScore = 0;
CpuScore = 0;
HasCalled = false;
ResultMessage = string.Empty;
HighLowChoice = HighOrLow.未選択;
}
public IActionResult OnPostCall()
{
if (!InputIsValid())
{
return BadRequest();
}
HasCalled = true;
Judement judement = Judge();
SetResult(judement);
return Page();
}
private bool InputIsValid()
{
return (HighLowChoice == HighOrLow.ハイ || HighLowChoice == HighOrLow.ロー);
}
public IActionResult OnPostNext()
{
HasCalled = false;
PlayerIsParent = !PlayerIsParent;
SetCurrentCard();
if (PlayerIsParent)
{
HighLowChoice = ChoiceByCpu();
}
else
{
HighLowChoice = HighOrLow.未選択;
}
return Page();
}
private void SetCurrentCard()
{
if ((PlayerCards.Count > 0) && (CpuCards.Count > 0))
{
CurrentPlayerCard = GetNextCard(PlayerCards);
CurrentCpuCard = GetNextCard(CpuCards);
}
else
{
CurrentGameState = GameState.End;
ResultMessage = GetResultMessage();
}
}
private string GetResultMessage()
{
if (PlayerScore > CpuScore)
{
return "あなたの勝ちです。";
}
else if (PlayerScore < CpuScore)
{
return "あなたの負けです。";
}
else
{
return "引き分けです。";
}
}
private void SetResult(Judement judement)
{
const string RESULT_MESSAGE_POINT_CPU = "CPUが2枚獲得";
const string RESULT_MESSAGE_POINT_PLAYER = "プレイヤーが2枚獲得";
const string RESULT_MESSAGE_POINT_BOTH = "両者が1枚ずつ獲得";
ResultMessage = $"{judement}:";
if (judement == Judement.当たり)
{
if (PlayerIsParent)
{
CpuScore += 2;
ResultMessage += RESULT_MESSAGE_POINT_CPU;
}
else
{
PlayerScore += 2;
ResultMessage += RESULT_MESSAGE_POINT_PLAYER;
}
}
else if (judement == Judement.はずれ)
{
if (PlayerIsParent)
{
PlayerScore += 2;
ResultMessage += RESULT_MESSAGE_POINT_PLAYER;
}
else
{
CpuScore += 2;
ResultMessage += RESULT_MESSAGE_POINT_CPU;
}
}
else
{
CpuScore += 1;
PlayerScore += 1;
ResultMessage += RESULT_MESSAGE_POINT_BOTH;
}
}
private Card GetNextCard(List<Card> cards)
{
Card card = null;
if (cards.Count > 0)
{
card = cards[0];
cards.RemoveAt(0);
}
return card;
}
private void DealCards()
{
PlayerCards = new List<Card>();
CpuCards = new List<Card>();
Cards cards = new Cards();
bool dealToPlayer = true;
foreach (Card card in cards)
{
if (dealToPlayer)
{
PlayerCards.Add(card);
}
else
{
CpuCards.Add(card);
}
dealToPlayer = !dealToPlayer;
}
}
private HighOrLow ChoiceByCpu()
{
if (CurrentPlayerCard.Number > 6)
{
return HighOrLow.ロー;
}
else
{
return HighOrLow.ハイ;
}
}
private Judement Judge()
{
if (PlayerIsParent)
{
return Judge(HighLowChoice, CurrentPlayerCard, CurrentCpuCard);
}
else
{
return Judge(HighLowChoice, CurrentCpuCard, CurrentPlayerCard);
}
}
private Judement Judge(HighOrLow choice, Card parentCard, Card childCard)
{
int compare = childCard.Number - parentCard.Number;
if (compare == 0)
{
return Judement.引き分け;
}
else if (compare > 0 && choice == HighOrLow.ハイ)
{
return Judement.当たり;
}
else if (compare < 0 && choice == HighOrLow.ロー)
{
return Judement.当たり;
}
else
{
return Judement.はずれ;
}
}
}
}
Index.cshtml
@page "{handler?}"
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1>ハイ&ロー</h1>
@{
if (Model.CurrentGameState == IndexModel.GameState.BeforePlay)
{
<form method="post">
<div class="row w-100 mt-3 mb-5 justify-content-center">
<input asp-page-handler="GameStart" class="btn btn-primary col-sm-2" type="submit" value="ゲーム開始" />
</div>
</form>
return;
}
else if (Model.CurrentGameState == IndexModel.GameState.End)
{
<div class="container-fluid mb-4">
<div class="row mb-4">
<div class="col-6 d-flex flex-column" id="PlayerCard">
<span>プレイヤーの総獲得枚数</span>
<span>@Model.PlayerScore</span>
</div>
<div class="col-6 d-flex flex-column" id="CpuCard">
<span>CPUのの総獲得枚数</span>
<span>@Model.CpuScore</span>
</div>
</div>
<div class="row mb-4">
<span class="col">@Model.ResultMessage</span>
</div>
</div>
<form method="post">
<div class="row w-100 mt-3 mb-5 justify-content-center">
<input asp-page-handler="GameStart" class="btn btn-primary col-sm-2" type="submit" value="新たにゲーム開始" />
</div>
</form>
return;
}
}
<div class="container-fluid mb-4">
<div class="row">
<div class="col-6 d-flex flex-column" id="PlayerCard">
@{
<span>プレイヤーカード</span>
if (Model.PlayerIsParent || Model.HasCalled)
{
@Model.CurrentPlayerCard.CardImage.FrontImageToHtml();
}
else
{
@Model.CurrentPlayerCard.CardImage.BackImageToHtml();
}
}
</div>
<div class="col-6 d-flex flex-column" id="CpuCard">
@{
<span>CPUカード</span>
if (!(Model.PlayerIsParent) || Model.HasCalled)
{
@Model.CurrentCpuCard.CardImage.FrontImageToHtml();
}
else
{
@Model.CurrentCpuCard.CardImage.BackImageToHtml();
}
}
</div>
</div>
</div>
<form method="post">
@{
string pointerEventStyle = "pointer-events: none";
if (Model.HasCalled)
{
<div class="form-text mb-3">@Model.ResultMessage</div>
}
else if (Model.PlayerIsParent)
{
<div class="form-text mb-3">CPUの番です。CPUの選択は@(Model.HighLowChoice)です。コールしてください。</div>
}
else
{
<div class="form-text mb-3">プレイヤーの番です。ハイかローを選択してコールしてください。</div>
pointerEventStyle = "pointer-events: auto";
}
}
<div class="form-check form-check-inline justify-content-center mb-2" style="@pointerEventStyle">
<div class="mr-3">
<input class="form-check-input" asp-for="HighLowChoice" type="radio" value="@IndexModel.HighOrLow.ハイ" id="radioHigh" required />
<label class="form-check-label" for="radioHigh">@IndexModel.HighOrLow.ハイ</label>
</div>
<div class="mr-3">
<input class="form-check-input" asp-for="HighLowChoice" type="radio" value="@IndexModel.HighOrLow.ロー" id="radioLow" />
<label class="form-check-label" for="radioLow">@IndexModel.HighOrLow.ロー</label>
</div>
</div>
<div class="mt-3">
@{
if (Model.HasCalled)
{
<button asp-page-handler="Call" class="btn btn-dark col-sm-2" type="submit" disabled="disabled">コール</button>
<button asp-page-handler="Next" class="btn btn-primary col-sm-2" type="submit">次のカードを出す</button>
}
else
{
<button asp-page-handler="Call" class="btn btn-primary col-sm-2" type="submit">コール</button>
<button asp-page-handler="Next" class="btn btn-dark col-sm-2" type="submit" disabled="disabled">次のカードを出す</button>
}
}
</div>
</form>
</div>
@{
<script>
document.getElementById('radioHigh').removeAttribute('checked');
document.getElementById('radioLow').removeAttribute('checked');
</script>
if (Model.HighLowChoice == IndexModel.HighOrLow.ハイ)
{
<script>
document.getElementById('radioHigh').setAttribute('checked', 'checked');
</script>
}
else if (Model.HighLowChoice == IndexModel.HighOrLow.ロー)
{
<script>
document.getElementById('radioLow').setAttribute('checked', 'checked');
</script>
}
}
@{
TempData.Keep();
}
なお、前々回の記事内のこれまでの講座で取り扱っていない事項についてに記載の通り、プロジェクトへのファイル追加と、Startup.csの変更を行っていることが前提です。
次回は回答例の解説
今回は以上、回答例の掲載のみとします。自身で作成したプログラムと見比べて確認したり、独力では完成できなかった部分について回答例を参考に再度チャレンジしたりしてみてください。
次回は回答例の解説を行います。
この記事へのコメントはありません。