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