Vue.jsでオセロ盤を作ってみる

##はじめに
本日は12月4日❗️
チノちゃん誕生日おめでとう👏😸🎊

##本題
オセロ盤はビットボードというデータ構造で実装するのが良いらしい⚪️⚫️✨
Vue.jsで石を並べるところまでやるぞ❗️😺


[ビットボード(Wikipedia)](https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%83%E3%83%88%E3%83%9C%E3%83%BC%E3%83%89)

※この記事では、ビットボードの難しい説明を省略します😿
ビットボードで石を返す処理はサーバー側で行い、その結果の石情報が渡ってくるところからやります✊😸❗️

あらかじめ仕込んでおく3分クッキングスタイルですね😽🍳✨

## 早速実装

残念ながらJavaScriptの数値は32bitなので、1つの変数で64マス表すことができません❗️😾
ゆるせねぇ...

というわけで、サーバー側で1次元配列に変換してフロント側に渡ってくるってことにしました✊😸❗️

### 最初に思い付いたやつ

``` Board.vue
<template>
  <div class="board">
    <div v-for="i in 8" class="row">
      <div v-for="j in 8" class="cell">
        <div v-if="blackStones[i * 8 + j]" class="stone black"></div>
        <div v-else-if="whiteStones[i * 8 + j]" class="stone white"></div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      blackStones: [
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
      ],
      whiteStones: [
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
      ]
    }
  }
}
</script>
```



二重ループで回して `1` が立ってたらそれぞれの石の要素を追加する感じ

しかしここで問題が…
`v-for="i in 8"` のindexが1始まりなのです😿
`[i * 8 + j]` を `[(i -1) * 8 + j - 1]` と書かなければならないのでわかりづらい❗️😾

### 改良
``` Board.vue
<template>
  <div class="board">
    <div v-for="i in Array(boardSize).keys()" class="row">
      <div v-for="j in Array(boardSize).keys()" class="cell">
        <div v-if="blackStones[i * boardSize + j]" class="stone black"></div>
        <div v-else-if="whiteStones[i * boardSize + j]" class="stone white"></div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      boardSize: 8,
      blackStones: [
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
      ],
      whiteStones: [
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
      ]
    }
  }
}
</script>
```
いろんな方法がありそうだけど、一番短そうな `Array(8).keys()` で動いたのでこれでいいや❗️😸


### 完成版
``` Board.vue
<template>
  <div class="board">
    <div class="logo rot">Othello</div>
    <div class="board-main">
      <div v-for="i in Array(boardSize).keys()" class="row">
        <div v-for="j in Array(boardSize).keys()" class="cell">
          <div v-if="blackStones[i * boardSize + j]" class="stone black"></div>
          <div v-else-if="whiteStones[i * boardSize + j]" class="stone white"></div>
        </div>
      </div>
    </div>
    <div class="logo">Othello</div>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      boardSize: 8,
      blackStones: [
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
      ],
      whiteStones: [
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
      ]
    }
  }
}
</script>

<style lang="scss" scoped>
.board-frame {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  margin: auto;
  width: 430px;
  height: 470px;
  background: #333;
  border-top: 3px solid rgba(255, 255, 255, 0.2);
  border-right: 5px solid rgba(0, 0, 0, 0.2);
  border-bottom: 5px solid rgba(0, 0, 0, 0.2);
  border-left: 3px solid rgba(255, 255, 255, 0.2);
  border-radius: 8px;

  .logo {
    color: gold;
    text-align: center;
  }

  .rot {
    transform: scale(-1,-1);
  }

  .board {
    display: flex;
    flex-direction: column;
    margin: auto;
    width: 408px;
    height: 408px;
    background: darkgreen;
    border-left: 1px solid #000;
    border-top: 1px solid #000;

    .row {
      display: flex;
    }

    .cell {
      display: flex;
      justify-content: center;
      align-items: center;
      border-bottom: 1px solid #000;
      border-right: 1px solid #000;
      width: 50px;
      height: 50px;

      .stone {
        border-radius: 50%;
        width: 85%;
        height: 85%;
      }

      .black {
        background: #333;
      }

      .white {
        background: #eee;
      }
    }
  }
}
</style>
```

CSSでオセロ盤っぽくした😼✨
![コメント 2020-11-23 143746.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122701/5f534c99-e582-aeb3-8c99-f8dece8ea4f3.png)


あとは、なんらかのイベントと紐付けて、 `blackStones` `whiteStones` の値が変わったら盤面を差分レンダリングする感じですね❗️😸


おしまい😽

※気が向いたらPHP版のビットボード実装の記事書きます