概要
前回:ASP.NET Core MVCであみだくじを作ってみる 5 (Razorを使う)
今回は、Razorを使って選択した番号のあみだを辿る処理を作ります。単なるおまけです。
前回同様、ASP.NET Core の Razor 構文リファレンスを参照しながら作っていきます。
描画したあみだを保持する
あみだを辿るには、ランダムに描画したあみだを保持しておく必要があります。
Kuji\Index.cshtmlの<div class="kuji-line">を以下のように変更します。
追加した行に+の印を付けました。
<div class="kuji-line">
@{
var rd = new Random();
var rcount = Math.Max(20, Model.Result.Count * 4); // グリッドレイアウトの行数
// 行番号リスト(4行目以降、全行数 - 上下のボタンや結果表示域で使用している行を除く行数)
var rows = Enumerable.Range(4, rcount - 6).ToList();
+ // 列ごとに横線の行番号を保持する用のリスト
+ var lines = new List<List<int>>();
<!--人数の分だけループ-->
for (var i = 1; i < Model.Result.Count + 1; i++)
{
<!--選択肢ボタン-->
<button class="select-btn" style="grid-row:2;grid-column:@i" asp-route-id="@i">@i</button>
<!--縦線-->
<div class="vertical-line" style="grid-row:3 / span @(rcount - 4);grid-column:@i"></div>
+ var hlines = new List<int>(); // 横線を行番号を保持する用
<!--横線-->
if (i < Model.NumberOfKuji)
{
var hcount = rd.Next(1, rcount / 4); // 横線の数
for (var j = 0; j < hcount; j++)
{
if (rows.Count <= 0) break; // 行が足りなくなったら終了
int rno = rows[rd.Next(0, rows.Count - 1)]; // 横線を引く行番号
rows.Remove(rno); // 重複する行番号を使わないようにするため
<p class="horizontal-line" style="grid-row:@rno;grid-column:@i"></p>
+ hlines.Add(rno);
}
}
+ lines.Add(hlines); // 列ごとに横線の行番号を保持する
+
<!--結果-->
<!--横幅を揃えるため、PadRightで5文字分に揃える-->
<div style="grid-row:@(rcount - 1);grid-column:@i">@Model.Result[i - 1].Item.PadRight(5, ' ')</div>
}
<!--1行分を余白とする-->
<div style="grid-row:@rcount;grid-column:1 / span @Model.NumberOfKuji"></div>
}
<!--あみだを隠すためのマスク領域-->
@if (Model.SelectId == 0)
{
<div class="mask"></div>
}
</div>
番号を選択した後の処理を追加する
Kuji\Index.cshtmlの<div class="kuji-line">の<!--1行分を余白とする-->の前に、以下の処理を追加します。
選択した番号の縦線を辿り、右への横線と左への横線、どちらが上かを判定して上にあるほうの横線を辿ります。
横線を辿って縦線を移動したら、その縦線を辿り、同じように上にあるほうの横線を辿ります。
if (Model.SelectId > 0) // 番号を選択した場合
{
// 選択した番号の列から始める
var currentCol = Model.SelectId - 1;
// 縦線が始まる行から始める
var currentRow = 3;
while (currentRow < rcount - 1)
{
// 現在の列の右側に延びる横線のうち、現在の行より下にある横線を取得する
var rightRow = (currentCol == Model.NumberOfKuji) ? null : lines[currentCol].Where(c => currentRow < c).ToList();
// 現在の列の左側に延びる横線のうち、現在の行より下にある横線を取得する
var leftRow = (0 == currentCol) ? null : lines[currentCol - 1].Where(c => currentRow < c).ToList();
// 右への線のうち、一番上にある横線を取得する
var rightMin = (rightRow != null && rightRow.Count > 0) ? rightRow.Min() : 999;
// 左への線のうち、一番上にある横線を取得する
var leftMin = (leftRow != null && leftRow.Count > 0) ? leftRow.Min() : 999;
if (rightMin < leftMin)
{
// 右へ進む
// 現在の行から右へ進む横線までの縦線
<div class="vertical-line follow" style="grid-row:@currentRow / span @Math.Max(1, (rightMin - currentRow));grid-column:@(currentCol + 1)"></div>
// 右への横線
<p class="horizontal-line follow" style="grid-row:@rightMin;grid-column:@(currentCol + 1)"></p>
currentCol++; // 右へ進んだ
currentRow = (currentRow == rightMin) ? currentRow + 1 : rightMin;
}
else if (rightMin > leftMin)
{
// 左へ進む
// 現在の行から左へ進む横線までの縦線
<div class="vertical-line follow" style="grid-row:@currentRow / span @Math.Max(1, (leftMin - currentRow));grid-column:@(currentCol + 1)"></div>
currentCol--; // 左へ進んだ
// 左への横線
<p class="horizontal-line follow" style="grid-row:@leftMin;grid-column:@(currentCol + 1)"></p>
currentRow = (currentRow == leftMin) ? currentRow + 1 : leftMin;
}
else
{
<div class="vertical-line follow" style="grid-row:@currentRow;grid-column:@(currentCol + 1)"></div>
currentRow++;
}
}
}
いろいろ触ってきたので、Kuji\Index.cshtmlの全体を載せておきます。
@model Amidakuji.Models.KujiModel
@{
ViewData["Title"] = "あみだくじ";
}
<form method="post" asp-controller="Kuji" asp-action="Index">
<div class="kuji-container">
<h1>@Model.Title</h1>
<p>くじの数は、@Model.NumberOfKuji 本です。</p>
<!--あみだくじの領域(グリッドレイアウト)-->
<div class="kuji-line">
@{
var rd = new Random();
var rcount = Math.Max(20, Model.Result.Count * 4); // グリッドレイアウトの行数
// 行番号リスト(4行目以降、全行数 - 上下のボタンや結果表示域で使用している行を除く行数)
var rows = Enumerable.Range(4, rcount - 6).ToList();
// 列ごとに横線の行番号を保持する用のリスト
var lines = new List<List<int>>();
<!--人数の分だけループ-->
for (var i = 1; i < Model.Result.Count + 1; i++)
{
<!--選択肢ボタン-->
<button class="select-btn" style="grid-row:2;grid-column:@i" asp-route-id="@i">@i</button>
<!--縦線-->
<div class="vertical-line" style="grid-row:3 / span @(rcount - 4);grid-column:@i"></div>
var hlines = new List<int>(); // 横線を行番号を保持する用
<!--横線-->
if (i < Model.NumberOfKuji)
{
var hcount = rd.Next(1, rcount / 4); // 横線の数
for (var j = 0; j < hcount; j++)
{
if (rows.Count <= 0) break; // 行が足りなくなったら終了
int rno = rows[rd.Next(0, rows.Count - 1)]; // 横線を引く行番号
rows.Remove(rno); // 重複する行番号を使わないようにするため
<p class="horizontal-line" style="grid-row:@rno;grid-column:@i"></p>
hlines.Add(rno);
}
}
lines.Add(hlines); // 列ごとに横線の行番号を保持する
<!--結果-->
<!--横幅を揃えるため、PadRightで5文字分に揃える-->
<div style="grid-row:@(rcount - 1);grid-column:@i">@Model.Result[i - 1].Item.PadRight(5, ' ')</div>
}
<!--1行分を余白とする-->
<div style="grid-row:@rcount;grid-column:1 / span @Model.NumberOfKuji"></div>
if (Model.SelectId > 0) // 番号を選択した場合
{
// 選択した番号の列から始める
var currentCol = Model.SelectId - 1;
// 縦線が始まる行から始める
var currentRow = 3;
while (currentRow < rcount - 1)
{
// 現在の列の右側に延びる横線のうち、現在の行より下にある横線を取得する
var rightRow = (currentCol == Model.NumberOfKuji) ? null : lines[currentCol].Where(c => currentRow < c).ToList();
// 現在の列の左側に延びる横線のうち、現在の行より下にある横線を取得する
var leftRow = (0 == currentCol) ? null : lines[currentCol - 1].Where(c => currentRow < c).ToList();
// 右への線のうち、一番上にある横線を取得する
var rightMin = (rightRow != null && rightRow.Count > 0) ? rightRow.Min() : 999;
// 左への線のうち、一番上にある横線を取得する
var leftMin = (leftRow != null && leftRow.Count > 0) ? leftRow.Min() : 999;
if (rightMin < leftMin)
{
// 右へ進む
// 現在の行から右へ進む横線までの縦線
<div class="vertical-line follow" style="grid-row:@currentRow / span @Math.Max(1, (rightMin - currentRow));grid-column:@(currentCol + 1)"></div>
// 右への横線
<p class="horizontal-line follow" style="grid-row:@rightMin;grid-column:@(currentCol + 1)"></p>
currentCol++; // 右へ進んだ
currentRow = (currentRow == rightMin) ? currentRow + 1 : rightMin;
}
else if (rightMin > leftMin)
{
// 左へ進む
// 現在の行から左へ進む横線までの縦線
<div class="vertical-line follow" style="grid-row:@currentRow / span @Math.Max(1, (leftMin - currentRow));grid-column:@(currentCol + 1)"></div>
currentCol--; // 左へ進んだ
// 左への横線
<p class="horizontal-line follow" style="grid-row:@leftMin;grid-column:@(currentCol + 1)"></p>
currentRow = (currentRow == leftMin) ? currentRow + 1 : leftMin;
}
else
{
<div class="vertical-line follow" style="grid-row:@currentRow;grid-column:@(currentCol + 1)"></div>
currentRow++;
}
}
}
}
<!--あみだを隠すためのマスク領域-->
@if (Model.SelectId == 0)
{
<div class="mask"></div>
}
</div>
</div>
<!--モデルをコントローラーへ通知-->
<input type="hidden" asp-for="Title" value="@Model.Title" />
<input type="hidden" asp-for="NumberOfKuji" value="@Model.NumberOfKuji" />
@for (var i = 0; i < Model.Result.Count; i++)
{
<input type="hidden" asp-for="Result[i].Item" value="@Model.Result[i].Item" />
}
<input type="hidden" asp-for="SelectId" value="@Model.SelectId" />
</form>
実行してみる
ちなみに、くじの数が多くなると、行数が足りなくなって横線が入らない場合があります。
そのうち、気が向いたら改善する・・・かもしれません。
まとめ
今回は、Razorを使って選択した番号のあみだを辿る処理を作成しました。
駆け足ですが、ASP.NET Core MVCの学習(入門)は果たせたかな、と思いますので、今回で終わりにします!
GitHubの使い方を勉強したら、ソース全体をUPしようと思います。
→pushしました。ソース全体はこちら