JavaScriptで作る変則リバーシ①

# はじめに
今回は通常のリバーシから以下を変えた、**盤面がいつもとは違う変則リバーシ**を作りましたので、ご紹介したいと思います。

- 盤面の形
- 石の初期配置
- 盤面の色

なお、プログラムの土台部分はこちら。

https://qiita.com/y-tetsu/items/59237213d544f14bbc9c

# できたもの
以下のような、ブラウザで遊べるものを作りました。自身が先手(黒)で、相手(白)はランダムに打ってくるコンピュータ、としています。
<a href="https://y-tetsu.github.io/colorful-reversi/" target="_blank"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/2cbdd1ea-52c2-19ce-a027-5ff0d68ce4b2.png" width=50%></a>

ソースコードなど一式は、以下に置いております。

https://github.com/y-tetsu/colorful-reversi/tree/ch01

ということで、お見せしたい結果も出揃いましたので
簡単ではありますが、作った上でのポイントを説明していきたいと思います。


# 盤面の形を変える
盤面の形を変える、といっても別段、何か特別な処理を追加する必要はありません。

単に、石が置けないことを表す、"穴"という情報を何らか用意すれば、それでOKです。下図にイメージを示します。アルファベットの"h"が穴(hole)を表しています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/2a2d8769-0bfc-3f12-075b-20212bc8f7e0.png" width=50%>

前回記事の[盤面情報の表現](https://qiita.com/y-tetsu/items/59237213d544f14bbc9c#%E7%9B%A4%E9%9D%A2%E6%83%85%E5%A0%B1%E3%81%AE%E8%A1%A8%E7%8F%BE)のところでは、以下のように8x8マスの盤面の外側を"壁"で囲い、**盤面の端を判定する目的**で利用していました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/c7d0bf45-44e6-4e17-d1f8-d12d983c078a.png" width=50%>

ここでは、この"壁"を、"穴"、と呼び名を変え**盤面の形状を変える目的**"でも"利用しています。ここが、いつもとは少し異なる点です。(ごくごく、わずかな違いですけれど)

ということで、盤面の情報を表すものとしては、全部で以下の4つを用意すれば、盤面の形を変える事ができそうです。

1. 黒の石
2. 白の石
3. 空きマス
4. 穴

ちなみにこの"穴"を使うと、文字通り盤面の中をくりぬいた形状(下図参照)でも、自由に作ってリバーシのルールのまま遊ぶことが可能です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/123e701d-4670-9db6-323d-f9c0c82770eb.png" width=50%>

# 石の初期配置を変える
石の初期配置を変えるには、ゲーム開始前に好きなマスに、あらかじめ、石を置いておくだけでよいです。なんとなく、上下左右**対称な配置**にしたくなってしまいますよね。

下図に、配置を変えてみたイメージを示します。アルファベットの"d"が石(disc)を表しています。また、対応する色(黒と白)は見たままとしています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/9fcc46f4-4e76-75a5-4d0d-5c6e52dd6af9.png" width=50%>

結局、ここまでの作りとしては、初期配置を変更するのみで、他は普通のリバーシと一緒で良さそうでした。

私の方でご用意しました、実際の盤面情報(初期配置)のJavaScriptコードでは、以下のように作っています。(先に示しましたソースコード一式の中の下記設定を変えることで、お好きな形の盤面が作れますよ)
```board.js
const H = 0;  // 穴
const E = 1;  // 空きマス
const B = 2;  // 黒色の石
const W = 3;  // 白色の石

const BOARD = [
  H, H, H, H, H, H, H, H, H, H,
  H, H, H, E, E, E, E, H, H, H,
  H, H, E, E, E, E, E, E, H, H,
  H, E, E, E, B, W, E, E, E, H,
  H, E, E, B, W, B, W, E, E, H,
  H, E, E, W, B, W, B, E, E, H,
  H, E, E, E, W, B, E, E, E, H,
  H, H, E, E, E, E, E, E, H, H,
  H, H, H, E, E, E, E, H, H, H,
  H, H, H, H, H, H, H, H, H, H,
];
```

盤面情報をブラウザに描画した結果は以下のようになります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/60f5a46b-3cc6-1dee-d1b8-5653198cd1f9.png" width=50%>

# 盤面の色を変える
何とか目新しさを、ということで、せめて盤面の色だけでも自由に設定できるようにしてみます。色がいろいろ変えられると、絵が描けたりしてちょっと楽しくなったりしませんかね？

ここでは、盤面を表す10x10=100マスそれぞれの色を指定するための情報を、追加することにします。特にひねりのない、力技です。

## 盤面の色指定
以下のコードで(`BOARD_COLOR`配列を使って)、盤面の各マスの色を番号で指定します。
```board.js
const BOARD_COLOR = [
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', '*', '*', '1', '1', '2', '2', '*', '*', '*',
  '*', '*', '1', '1', '1', '2', '2', '2', '*', '*',
  '*', '1', '1', '1', '1', '2', '2', '2', '2', '*',
  '*', '1', '1', '1', '1', '2', '2', '2', '2', '*',
  '*', '3', '3', '3', '3', '4', '4', '4', '4', '*',
  '*', '3', '3', '3', '3', '4', '4', '4', '4', '*',
  '*', '*', '3', '3', '3', '4', '4', '4', '*', '*',
  '*', '*', '*', '3', '3', '4', '4', '*', '*', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
];
```

## 色情報の設定
先ほどの色を指定した番号が、実際に何色かを決める設定も用意しておきます。これは、`BOARD_COLOR`配列の初期設定を1文字で表現して、見やすくしたいがためです。`BOARD_COLOR`配列の値に直接、色の名前を指定してもやりたい事は実現できます。
```board.js
const COLOR_CODE = {
  '0': 'green',
  '1': 'lightskyblue',
  '2': 'pink',
  '3': 'mediumaquamarine',
  '4': 'navajowhite',
  '*': '* no color *',
};
```

描画処理(*ui.js*)は以下のように、`createBoardTable()`の背景色と盤面形状の反映部分が変更になっています。
```diff_javascript
- // 盤面のサイズと背景色
+ // 盤面のサイズと背景色と形
  for (let i=0; i<BOARD.length; i++) {
     const square = document.getElementById(UI_BOARD + i);
     square.width = 60;
     square.height = 60;
-    if (gameBoard[i] !== X) {
-        square.style.backgroundColor = 'green';
+    const boardColor = BOARD_COLOR[i];
+    if (gameBoard[i] !== H && boardColor !== '*') {  // 穴と色なしは除外
+      square.style.backgroundColor = COLOR_CODE[boardColor];
     }
   }
```

先の盤面の形や石の初期配置に加え、今回の盤面の色も反映させた結果が以下です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/5d2a316d-0ac6-c0cd-482a-51c248d903c9.png" width=50%>

たとえば、`BOARD_COLOR[13]`には"1"の色番号が設定されていますが、この"1"を、`COLOR_CODE["1"]`で辞書引きすると、**lightskyblue**が得られます。

つまり、`BOARD_COLOR[13]` のマス(下図**C1**の黄色星印のついた箇所)の色が、**lightskyblue**色であることが示されています。(同様に、`BOARD_COLOR[15]`の**E1**の場合は、**pink**色の設定となっており実際のゲーム画面もそうなっていることが確認できますね)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/d23ecd86-447d-91b0-1485-c3fda450ff5a.png" width=50%>

このように、ブラウザに表示させるテーブルの各マスの背景色(**.style.backgroundColor**)に、盤面の色指定情報(`BOARD_COLOR`配列)から得られた実際の色を設定することで、盤面の色付けを実現しました。

# 完成
以上で、今回作ろうと思っていた、**盤面がいつもとは違う変則リバーシ**が完成しました。

完成したものをプレイしている様子が、以下になります。(コンピュータはランダムに打っているだけなので、端さえ押さえておけば楽勝でした)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/f4f21021-116d-3795-3628-95ff6187e08e.gif" width=75%>

# おまけ
せっかくですので、今回私が変則リバーシを考えた中で、こんなのも面白いかなと思ったものを、3つだけご紹介したいと思います。

## 逆4x4リバーシ
外側が石で埋められた、中の4x4のマスで遊ぶリバーシ。どうやらこの盤面、先手後手が最善手を打つと**必ず引き分け**となるようです(独自調べ)。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/922c48ca-8c3c-a9f2-7d1b-4436b76064b5.gif" width=75%>

```board.js
const BOARD = [
  H, H, H, H, H, H, H, H, H, H,
  H, W, W, W, W, B, B, B, B, H,
  H, W, B, B, B, W, W, W, B, H,
  H, W, B, E, E, E, E, W, B, H,
  H, W, B, E, E, E, E, W, B, H,
  H, B, W, E, E, E, E, B, W, H,
  H, B, W, E, E, E, E, B, W, H,
  H, B, W, W, W, B, B, B, W, H,
  H, B, B, B, B, W, W, W, W, H,
  H, H, H, H, H, H, H, H, H, H,
];
const BOARD_COLOR = [
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', '*',
  '*', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', '*',
  '*', 'd', 'd', 'c', 'c', 'c', 'c', 'd', 'd', '*',
  '*', 'd', 'd', 'c', 'c', 'c', 'c', 'd', 'd', '*',
  '*', 'd', 'd', 'c', 'c', 'c', 'c', 'd', 'd', '*',
  '*', 'd', 'd', 'c', 'c', 'c', 'c', 'd', 'd', '*',
  '*', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', '*',
  '*', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
];
const COLOR_CODE_CONFIG = {
  'c': 'silver',
  'd': 'gray',
  '*': '* no color *',  // 色指定なし(背景色を設定)
};
```

## ドーナツリバーシ
ぽっかり穴が開いた形の盤面で、初期配置の石が2セットあるリバーシ。置いた石がトッピングに見えないこともない！？(ドーナツ食べたくなってきた…)。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/e72cbb9f-3c65-10f1-4c1d-3dd90c42a66a.gif" width=75%>

```board.js
const BOARD = [
  H, H, H, H, H, H, H, H, H, H,
  H, H, H, E, E, E, E, E, H, H,
  H, H, E, E, E, E, E, E, E, H,
  H, E, E, E, E, E, E, E, E, H,
  H, E, W, B, H, H, W, B, E, H,
  H, E, B, W, H, H, B, W, E, H,
  H, E, E, E, E, E, E, E, E, H,
  H, E, E, E, E, E, E, E, H, H,
  H, H, E, E, E, E, E, E, H, H,
  H, H, H, H, H, H, H, H, H, H,
];
const BOARD_COLOR = [
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', '*', '*', '9', '9', '9', '9', '9', '*', '*',
  '*', '*', '9', '9', '9', '9', '9', '9', '9', '*',
  '*', '9', '9', '9', '9', '9', '9', '9', '9', '*',
  '*', '9', '9', '9', '*', '*', '9', '9', '9', '*',
  '*', '9', '9', '9', '*', '*', '9', '9', '8', '*',
  '*', '9', '9', '9', '9', '9', '9', '8', '8', '*',
  '*', '8', '8', '9', '9', '9', '8', '8', '*', '*',
  '*', '*', '8', '8', '8', '8', '8', '*', '*', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
];
const COLOR_CODE_CONFIG = {
  '8': 'navajowhite',
  '9': 'pink',
  '*': '* no color *',  // 色指定なし(背景色を設定)
};
```

## 目隠しリバーシ
対戦相手の**白の石が見えない**リバーシ。4x4サイズとはいえ、記憶力と推理力が、かなり試されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653390/2217e225-b4ca-1b51-4018-8ef17d9253ac.gif" width=75%>

```board.js
const BOARD = [
  H, H, H, H, H, H, H, H, H, H,
  H, H, H, H, H, H, H, H, H, H,
  H, H, H, H, H, H, H, H, H, H,
  H, H, H, E, E, E, E, H, H, H,
  H, H, H, E, W, B, E, H, H, H,
  H, H, H, E, B, W, E, H, H, H,
  H, H, H, E, E, E, E, H, H, H,
  H, H, H, H, H, H, H, H, H, H,
  H, H, H, H, H, H, H, H, H, H,
  H, H, H, H, H, H, H, H, H, H,
];
const BOARD_COLOR = [
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', '*', '*', 'f', 'f', 'f', 'f', '*', '*', '*',
  '*', '*', '*', 'f', 'f', 'f', 'f', '*', '*', '*',
  '*', '*', '*', 'f', 'f', 'f', 'f', '*', '*', '*',
  '*', '*', '*', 'f', 'f', 'f', 'f', '*', '*', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
  '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
];
const COLOR_CODE_CONFIG = {
  'f': 'white',
  '*': '* no color *',  // 色指定なし(背景色を設定)
};
```


# 最後に
盤面の形や色、石の配置がいつもと異なるリバーシを作ってみましたが、いかがでしたでしょうか。まだまだ、盤面の大きさを変えたり、先手後手を入れ替えたり、といったオリジナルの変則ルールを織り込む要素は、随所にありそうですね。
最後まで読んで下さり、ありがとうございました。

本記事の続編となる以下も、よかったら見てみてください。

https://qiita.com/y-tetsu/items/d1a5c7485cb34ae5c904

それでは皆様、よきリバーシ・ライフを！