JavaScript、jQueryでオセロを作ってみるシリーズのその1です。
本記事の環境
※PCに環境構築を行う必要はありません。
WEBブラウザ(Google Chome)
テキストエディタ
成果物(画面)
所感
- オセロ盤、石を表示できるようにするのが難しかった。
- どこに石を置けるかの判定処理が難しかった。
- 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>