LoginSignup
12
3

More than 3 years have 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版のビットボード実装の記事書きます

12
3
0

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
  3. You can use dark theme
What you can do with signing up
12
3