LoginSignup
3

More than 1 year has passed since last update.

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

Last updated at Posted at 2020-12-03

はじめに

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

本題

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

ビットボード(Wikipedia)

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

あらかじめ仕込んでおく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

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

おしまい😽

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3