perlのみで、今マインスイーパーを作るとしたら


**時代遅れともディスられるperlで、昔懐かしいマインスイーパーを作っちゃったよ。perlはいくらでもモダンな書き方ができるし、立派に現役を張れるよ。**

本記事の企画は、Qiita夏祭り2020の 「 〇〇（言語）のみを使って、今△△（アプリ）を作るとしたら」 をテーマに立ち上げたものです。

# 新しい言語は学ぶにはゲームを作るに限る

BASIC、awk、perlと、私が主要言語と位置付けるプログラミング言語は時を追うにしたがって変遷してきました。その都度、私がまずやってみるのはゲームを作ることです。

<dl>
<dt>ゲームには基礎的素養がまんべんなく要求される</dt>
<dd>計算式の構築、配列やオブジェクトの管理、ユーザインタフェースの設計、エラー処理など、アプリを作るにあたって必要な基礎を幅広く復習することができます。</dd>
<dt>ゲームプログラムはレビューしてもらえる</dt>
<dd>これは言語の学習というよりプログラミングの初学者にとってこそかもしれませんが、作ったプログラムで周りの家族・友人に遊んでもらって批評してもらえることは有意義でしょう。ルールを理解してもらえなかったり、思いもよらない操作をされて「動かない!」と突き返されたり、といった、実務に入れば直面するであろう体験をいち早く積むことができます。<br>これが、「コロナウィルス関係公開データに基づく医療崩壊時期予測プログラム」とかだったらどうでしょうか。レビューを依頼しても「ママちょっと難しい話は分からないわ」と逃げられるのが関の山と思われます。
</dl>

# 昔取った杵柄をもう一度

さて、今回やってみようと思うのは、その昔PC-9801のMS-DOS上で`AWK`の勉強のために作った「マインスイーパー」を再現することです。

ただし、ここで公開するのはperl版。昔通りにawkで通してみるのも一興だとは思いましたが、考えているうちいろいろ欲が出てきました。せっかくならガチで遊べるものにしたい。そこで潰しの利くperlに乗り換えた次第です。

# 前提条件

* 端末ソフト上で遊べること。 ━ 私は普段、windows上のrloginやubuntu上の仮想端末から別のマシンにリモートログインして作業することが多いのです。ログインした先で、つまり仮想端末の画面上でそのまま遊べるゲームに需要がありました。
* 画面サイズ上許される範囲で、ボードのサイズや地雷の数を自由に指定できること。
* perl本体及び標準ライブラリのみ（いわゆるpure perl）で動作すること。
* プレイ記録を残すこと。プレイごとにベストレコードをチェックし、更新できたときは褒められること。

# ソース

githubにアップロードし公開しました。

[git@github.com:Koji-Doi/minesweeper-perl.git](https://github.com/Koji-Doi/minesweeper-perl)

# 解説

全体で380行のスクリプトになりました。もっとも、ドキュメントがそのうち50行を占めています。それ以外にエラー処理やログファイル管理などが多くを占めていて、ゲームそのものの処理に直接関わっているコードはそれほど多くありません。

当作品のキモとなる要素を挙げるとすれば、地雷の設置と「周辺地雷の数」データを同時に更新する手順、再帰呼び出しによってマス目を開いていく処理、そしてエスケープシーケンスの活用、といったところでしょうか。

今ではフルスクリーンのGUIなんてwebベースにしてしまうところですが、エスケープシーケンスによる疑似（？）フルスクリーンにも味があって私は好きです[^1]。

生のエスケースシーケンスをいちいちprint()の中に埋め込むのはスマートではないので、往年のBASICっぽいcolor()とかlocate()とかcls()とかの関数を作って処理しています。

[^1]: できれば「スタートレック」なんかも再現したいところです。今の若い人に見せてあげたい。チープな画面なりに雰囲気をうまく演出してみせてくれた往年の米国産ソフト。なかなか日本人には真似できない優れたセンスがあったように思います。

# 遊び方

## セットアップ

perlスクリプトなので、perlをインストールすれば遊べます[^2]。上記に示したとおり、githubからアーカイブをダウンロードして、カレントディレクトリに`minesweeper.pl`を置きます。

[^2]: 特別なことはしていないのでperl5.8以降ならどのバージョンでも動くはずです。もちろん現行の大半のUnix-like OSなら既に普通に利用可能でしょう。

## ゲームの起動

まず、次のようにするとヘルプが読めます。

```
perl minesweeper.pl -h
```

標準設定でゲームを起動するには次のようにすればよいです。

```
perl minesweeper.pl
```

ボードの幅・高さ・地雷数をこの順番で指定して起動することもできます。大きすぎるマス数が指定されたときは、強制的に上限値に設定し直されます。

横16マス、縦10マス、設置地雷数10で遊びたければ、次のようにします。

```
perl minesweeper.pl 16 10 10
```

## ゲームの進行

ゲームをスタートするとボードが表示され、その下にプロンプトメッセージがでます。![minisweeper1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383429/919553c6-2285-bd48-0eec-4bc7323f3c40.png)

開きたいマス目に対応するX,Y座標値をスペースなど入れずに入力してリターンキーを打ちます。例えば上のスクリーンショットの段階で、ボード右上隅のマスを開きたければ、入力すべきは

```
61
```
となります。

地雷が埋まっていると目されるマスを見出した際には、そこに「フラグ」を立てます。
![minisweeper4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383429/cb3de846-05f7-0b20-d610-cf54afc62d9f.png)

コマンドとしては、上記形式の座標値の前か後に`+`を付け加えます。上記例において、そこを地雷の設置場所とみなすなら、入力すべきは

```
+61
```
または、

```
61+
```

となります。日本語話者には「６－１のマス目に旗を立てる」をそのままコマンド化できる後者の形式の方が自然ではないかと思います。

また、`+`の代わりに`-`を指定すると既に立てた旗を取り消すことができます。

## ゲームの終了

旗を立てずに地雷が埋まったマスを開いてしまったら、その時点であなたの負け確定でゲームオーバーです。

![minisweeper3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383429/8ab7b56a-f771-46fb-8592-0582b3b36036.png)

すべてのマスに適切に旗をつけるか開き終わることができたとき、あなたの勝利でゲーム終了です。その記録は保存され、あなたは顕彰されるでしょう。
![minisweeper_success.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383429/89d16d6a-a4e0-7716-5f02-2fbfa1783c75.png)

## プレイ記録の保存と利用

プレイ記録はホームディレクトリ直下の`minesweeper.pl.rec`に追記されていきます。ごく単純なタブ区切りテキストです。書き込みに際して排他処理とか一切考慮していません。まあ実用上問題ないでしょう。

# おわりに

2020年現在、perlはトレンディな言語とはいいがたい状況にあります。それどころか、一部の方々には、何か嫌な思い出でもあるのか目の敵にされているらしく、時代遅れだの構文が変だの散々な言われようです。

確かにウェブアプリ=CGI=perlスクリプトだった時代は終わったかもしれません。しかし、perlは今でもテキスト処理に関しては最強言語の一つです。非常にシンプルなコードで複雑なことができます。文字列データの加工や検索の処理速度は相当速いです。

拙稿を通して、perlの可能性や面白さを知る切っ掛けとする人が一人でも出てくることを祈っています。