0
0

JavaScript、jQueryでオセロを作る。その1

Last updated at Posted at 2023-11-27

JavaScript、jQueryでオセロを作ってみるシリーズのその1です。

本記事の環境

※PCに環境構築を行う必要はありません。
WEBブラウザ(Google Chome)
テキストエディタ

成果物(画面)

オセロ02.png
オセロ03.png
オセロ01.png

所感

  • オセロ盤、石を表示できるようにするのが難しかった。
  • どこに石を置けるかの判定処理が難しかった。
  • COM側の「どこに置くのが最善手か」の思考処理は追って作ってみたい。

成果物(ソースコード)

  • 参考程度にしてください。軽くは動作確認済みです。
othello.html
<!DOCTYPE html>
<html>
  <head>
    <title>オセロ</title>
    <style>
      body {
        background-color : #eee;
      }
      #board {
        position : relative;
        top : 50px;
        left : 50px;
        background-color : black;
      }
      #board td {
        width : 20px;
        height : 20px;
        background-color : green;
      }
      .whiteStone {
        width : 20px;
        height : 20px;
        border-radius : 50%;
        background-color : white;
        color : white;
        text-align : center;
      }
      .blackStone {
        width : 20px;
        height : 20px;
        border-radius : 50%;
        background-color : black;
        color : black;
        text-align : center;
      }
    </style>
  </head>
  <body>
    <template id="massImg">
      <td id="1_1"></td>
    </template>
    <div>
      <div>
        <table id='board'><tbody id='boardbody'></tbody></table>
      </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script language="JavaScript">
      // オセロ情報
      const MAX_NUM = 8;
      const MIN_NUM = 1;
      const VALUE0 = "0";
      const VALUE1 = "1";
      const VALUE2 = "2";
      const COLOR1 = "white";
      const COLOR2 = "black";
      
      // 反転判定パターン
      const CHECK_PATTERN = [
        [ 0,  1],  // 上
        [ 0, -1],  // 下
        [-1,  0],  // 左
        [ 1,  0],  // 右
        [ 1,  1],  // 右上
        [ 1, -1],  // 右下
        [-1,  1],  // 左上
        [-1, -1],  // 左下
      ];
      
      // オセロマス
      function Mass(x, y, stone) {
        // プロパティ
        this.x = x;
        this.y = y;
        this.stone = stone;
      }
      
      // オセロ盤
      function Board() {
        // プロパティ
        this.board = [];

        // 初期化処理
        this.init = function() {
          this.board = [];
          let mass;
          for (let y = MAX_NUM; y >= MIN_NUM; y--) {
            for (let x = MIN_NUM; x <= MAX_NUM; x++) {
              mass = new Mass(x, y, VALUE0);
              this.board.push(mass);
            }
          }
          return;
        };
      }
      
      // オセロ
      function Othello () {
        // プロパティ
        let board = new Board();
        
        // 初期化処理
        this.init = function() {
          // オセロ盤の初期化処理を呼び出す。
          board.init();
        }
        
        // オセロ盤表示処理
        this.outputBoard = function() {
          $("#boardbody").empty();
          let content_massImg = $("#massImg").contents();
          for (let y = MAX_NUM; y >= MIN_NUM; y--) {
            $("<tr id='y" + y + "'></tr>").appendTo("#boardbody");
            for (let x = MIN_NUM; x <= MAX_NUM; x++) {
              $(content_massImg).prop("id", x + "_" + y);
              $(content_massImg).clone().appendTo("#y" + y);
            }
          }
          $("#boardbody").show();
        }
        
        // 初期石設置処理
        this.setDefaultStone = function() {
          $("#" + (MAX_NUM / 2) + "_" + (MAX_NUM / 2)).html("<div class='blackStone'>B</div>");
          $("#" + (MAX_NUM / 2 + 1) + "_" + (MAX_NUM / 2)).html("<div class='whiteStone'>W</div>");
          $("#" + (MAX_NUM / 2) + "_" + (MAX_NUM / 2 + 1)).html("<div class='whiteStone'>W</div>");
          $("#" + (MAX_NUM / 2 + 1) + "_" + (MAX_NUM / 2 + 1)).html("<div class='blackStone'>B</div>");
        }
        
        // オセロマス選択イベント設定処理
        this.setMassEvent = function() {
          let stone_color = "black";
          for (let y = MAX_NUM; y >= MIN_NUM; y--) {
            for (let x = MIN_NUM; x <= MAX_NUM; x++) {
              $("#" + x + "_" + y).on("click", function () {
                // 反転判定処理を呼び出す。
                let reverseList = checkMain(x, y, stone_color);
                if (reverseList.length >= 1) {
                  // 反転できる石がある場合
                  
                  // 当該操作の石を置く。
                  if (stone_color == "black") {
                    $("#" + x + "_" + y).html("<div class='blackStone'>B</div>");
                  } else {
                    $("#" + x + "_" + y).html("<div class='whiteStone'>W</div>");
                  }
                  // 反転実行処理を呼び出す。
                  reverse(reverseList, stone_color);
                  if (stone_color == "black") {
                    stone_color = "white";
                  } else {
                    stone_color = "black";
                  }
                } else {
                  alert("x" + x + "y" + y + "には置けません。");
                }
              });
            }
          }
        }
        
        // 反転実行処理
        function reverse(reverseList, stone_color) {
          for (let target = 0; target < reverseList.length; target++) {
            let targetX = reverseList[target][0];
            let targetY = reverseList[target][1];
            if (stone_color == "black") {
              $("#" + targetX + "_" + targetY).html("<div class='blackStone'>B</div>");
            } else {
              $("#" + targetX + "_" + targetY).html("<div class='whiteStone'>W</div>");
            }
          }
        }
        
        // 反転判定処理
        function checkMain(x, y, stone_color) {
          let reverseList = checkCore(x, y, stone_color);
          return reverseList;
        }
        
        // 反転判定実処理
        function checkCore(x, y, stone_color) {
          let reverseList = [];
          let color_1 = "B";
          let color_2 = "W";
          if (stone_color == "white") {
            color_1 = "W";
            color_2 = "B";
          }
          for (let target = 0; target < CHECK_PATTERN.length; target++) {
            let targetX = x + CHECK_PATTERN[target][0];
            let targetY = y + CHECK_PATTERN[target][1];
            if ((targetX >= MIN_NUM) && (targetX <= MAX_NUM) && (targetY >= MIN_NUM) && (targetY <= MAX_NUM)) {
              if ($($("#" + targetX + "_" + targetY).contents()).html() == color_2) {
                let reverseList_work = [];
                let reverse_flg = false;
                reverseList_work.push([targetX, targetY]);
                //alert("stock1 : " + targetX + "_" + targetY);
                for (let shift = 2; shift <= MAX_NUM; shift++) {
                  let targetX2 = x + CHECK_PATTERN[target][0] * shift;
                  let targetY2 = y + CHECK_PATTERN[target][1] * shift;
                  //alert("TARGET : " + targetX2 + "_" + targetY2);
                  if ((targetX2 < MIN_NUM) || (targetX2 > MAX_NUM) || (targetY2 < MIN_NUM) || (targetY2 > MAX_NUM)) {
                    //alert("break1 : " + targetX2 + "_" + targetY2);
                    break;
                  }
                  if ($($("#" + targetX2 + "_" + targetY2).contents()).html() == color_2) {
                    reverseList_work.push([targetX2, targetY2]);
                    //alert("stock2 : " + targetX2 + "_" + targetY2);
                  } else if ($($("#" + targetX2 + "_" + targetY2).contents()).html() == color_1) {
                    //alert("break2 : " + targetX2 + "_" + targetY2);
                    reverse_flg = true;
                    break;
                  }
                }
                if (reverse_flg) {
                  reverseList = reverseList.concat(reverseList_work);
                }
              }
            }
          }
          return reverseList;
        }
      }
      
      // オセロ盤表示処理を呼び出す。
      let game = new Othello();
      game.outputBoard();
      
      // 初期石設置処理を呼び出す。
      game.setDefaultStone();
      
      // オセロマス選択イベント設定処理を呼び出す。
      game.setMassEvent();
    </script>
  </body>
</html>
0
0
2

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
0
0