2017 04 03

マインスイーパーを作るの2

昨日の続き。 まずは見た目から。

minesweeper.html

<!doctype html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>minesweeper</title> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="minesweeper.css" /> <script src="minesweeper.js"></script> </head> <body> <input type="radio" name="mode" id="rdoOpen" value="0" checked="checked"/> <input type="radio" name="mode" id="rdoFlag" value="1" disabled="true" /> <div id="header"> <span> MINESWEEPER </span> <span> <label for="rdoOpen" id="lblOpen">開</label> <label for="rdoFlag" id="lblFlag">旗</label> </span> <span> 旗 <span id="countFlag">0</span> 未 <span id="countRest">0</span> </span> </div> <div id="body"> </div> <div id="msg"> </div> </body> </html>

minesweeper.css

* { margin: 0; padding: 0; } body { font-size: 10pt; } #header { color: #f0f0f0; background: #404040; display: table; table-layout: fixed; width: 100%; } #header > span { display: table-cell; height: 3em; vertical-align: middle; } #header > span:nth-child(1) { text-align: left; padding-left: 1em; } #header > span:nth-child(2) { text-align: center; } #header > span:nth-child(3) { text-align: right; font-family: monospace; padding-right: 1em; } #body { text-align: center; padding: 0.6em 0; background: #000000; border-bottom: 1px solid #000000; max-width: 100%; overflow: auto; } table { margin: 0 auto; background: #606060; border-collapse: separate; table-layout: fixed; } td { width: 1.8em; height: 1.8em; text-align: center; vertical-align: middle; cursor: pointer; box-sizing: border-box; line-height: 1; } td.open { color: #ffffff; background: #000000; } td.hide { border-style: outset; border-width: 2px; color: #000000; background: #e0e0e0; } tr:first-child , tr:last-child , td:first-child , td:last-child { display: none; } input[type="radio"] { display: none; } label { padding: 1em; line-height: 1; cursor: pointer; } #lblOpen { color: #a0a0a0; } #lblFlag { color: #009900; } #rdoOpen:checked ~ #header #lblOpen { color: #ffffff; background: #000000; font-weight: bold; } #rdoFlag:checked ~ #header #lblFlag { color: #00ff00; background: #000000; font-weight: bold; } #rdoFlag:checked ~ #body table { background: #008800; } #msg { position: fixed; left: 0; top: 0; right: 0; bottom: 0; box-sizing: border-box; padding-top: 10%; text-align: center; color: #ffffff; background: rgba( 0, 0, 0, 0.8 ); font-size: 200%; font-weight: bold; display: none; }

盤面はtableとして実装するが、行数と列数の定義に従ってjavascriptで作る予定なので、htmlファイル内には盤面用のtableは無い。

隣接するセルの状態から自分のセルの状態を決める場合、最外周のセルは隣が無い場合があるので、周囲のセルの状態を取得する中で有るか無いかの条件分岐が発生してしまう。 そうした面倒を回避するために、最外周の更に外側にダミーのセルを配置し、それらを非表示にしておく。

操作モードは排他なので、ラジオボタンで選択する。

ラジオボタンの選択に応じてラベルやテーブルの表示状態を変えるのを、javascriptを使わずにcssだけでやりたかったのだが、cssのセレクタで 「選択されたラジオボタンの後方の要素」 と適用するには、ラジオボタンと操作対象の要素がDOM上の同レベルか、ラジオボタンの方が上位にいる必要がある。 ラジオボタンがbody直下の先頭にあるのはそのため。

その結果、ラジオボタンとそのラベルが遠く離れてしまったので、ラジオボタンは非表示にした。 ラジオボタンが見えなくても、ラベルが見えてれば問題無いからね。

爆死または完遂時のメッセージは、最初はシンプルに alert() で表示すれば良いと思っていた。 しかしそれだと爆死にしても完遂にしても寂しい気がしてきたので、ちょっとだけ派手にしてみた。

あと、ここまで未だ出ていないが、爆弾と旗は文字で表示する。

爆弾

絵文字の旗(🚩)も考えたが、実際にセルの中に表示してみると、絵文字はちょっと収まりが悪い上に薄い。 そもそもの話、旗を立てる目的は 「ここに爆弾がありますよ」 と示すこと。 なので三角(▽)は適任っぽいし、温かい目で見れば旗に見えなくもないし、という理由で▽を採用。

爆弾は、爆死の一瞬しか見えないので割とどうでもいいのだが、一応探してみると、そのものずばり爆発(💥)なんて絵文字があった。 で、この爆発と●とをセルの中に表示してみたら、俺のメインマシンのMacBookでは絵文字の爆発よりも文字の●の方がインパクトが強かった。 なのでこちらも●を採用。

ところでこの表示のテストをするのに、minesweeper.htmlの中に

<div id="body"> <table id="board"> <tbody> <tr> <td class="hide"></td> <td class="hide">▽</td> <td class="hide">🚩</td> <td class="open"></td> <td class="open">1</td> <td class="open">●</td> <td class="open">💥</td> </tr> </tbody> </table> </div>

と、各要素の表示パターンを並べて書いてみたのだが、灰色の線が一本表示されるのみでセルは全く表示されなかった。 絵文字どころか普通の文字も数字も表示されない。 何故? と、数分悩んでしまった。

原因はminesweeper.cssの中で最初と最後のtrを非表示になるように指定していたから。 テスト用の記述ではtrが一つしかないので最初かつ最後。 もう寄って集って消される状態だったのだな。

スタイルシートの指定が意図通りに効いていたことを意図せず確認できたのだが、気付いたときはちょっと笑ってしまった。 わざわざ消しておきながら、表示されないって悩んでるんだからね。 俺はいったい何をやっているのかと。

ということで、続きは明日。