Skip to content

Instantly share code, notes, and snippets.

@odiak
Created April 5, 2011 02:06
Show Gist options
  • Save odiak/902893 to your computer and use it in GitHub Desktop.
Save odiak/902893 to your computer and use it in GitHub Desktop.
(function () {
var re = {};
// define board
re.board = [];
// define color
re.type = {
none: -1,
black: 0,
white: 1
};
// define user
re.user = {
player: re.type.black,
computer: re.type.white
};
// class name
re.class = {
black: "black",
white: "white"
};
// opposite type
re.type.reverse = function (t) {
switch (t) {
case re.type.white:
return re.type.black;
case re.type.black :
return re.type.white;
case re.type.none :
return re.type.none;
default :
return false;
}
};
re.type.getClass = function (t) {
switch (t) {
case re.type.none :
return re.class.none;
case re.type.black :
return re.class.black;
case re.type.white :
return re.class.white;
default :
return false;
}
};
var x, y;
// init Board
for (x = 0; x < 8; x ++) {
re.board[x] = [];
for (y = 0; y < 8; y ++) {
re.board[x][y] = re.type.none;
}
}
// alternative of document.createElement()
$.create = function (tagName, innerText, attributes) {
var res;
if (typeof innerText === "undefined" || !innerText) {
innerText = "";
}
if (typeof attributes === "undefined" || !attributes) {
attributes = {};
}
if (tagName) {
var e = document.createElement(tagName);
if (innerText) {
e.innerHTML = innerText;
}
var attr;
for (attr in attributes) {
if (attributes.hasOwnProperty(attr)) {
e[attr] = attributes[attr];
}
}
res = $(e);
} else {
res = false;
}
return res;
};
$(function () {
re.$ = $("#board");
re.$.append($.create("table"));
var a;
for (a = 0; a < 8; a ++) {
re.$.find("table").append(
$.create("tr")
);
}
re.$.find("table tr").each(function () {
var a;
for (a = 0; a < 8; a ++) {
$(this).append(
$.create("td")
);
}
});
re.$
.append(
$.create(
"div",
"",
{ id: "console" }
)
)
.find("div")
.append(
$.create("ul")
);
re.log("Welcome to Reversi Game!!");
re.$_ = re.$.find("td");
re.$_.click(function () {
var index = $(this).index(re.$_.selector);
re.clickAction(index);
});
$("#controllers .start").click(function () {
re.gameStart();
});
});
// 適当な文字列を作る関数
re.uniqueString = function (length) {
var chr = "", res = "", pos;
chr += "abcdefghijklmnopqrstuvwxyz";
chr += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
chr += "0123456789";
chr += "_-";
if (!arguments.length) {
length = 0;
}
var a;
for (a = 0; a < length; a ++) {
pos = chr.length * Math.random() | 0;
res += chr.charAt(pos);
}
return res;
};
// フラグ作る関数
re.Flag = function (bool) {
var flag = bool ? true : false;
return {
get: function () {
return flag;
},
set: function (bool) {
return (flag = (bool ? true : false));
},
on: function () {
return (flag = true);
},
off: function () {
return (flag = false);
},
reverse: function () {
flag = !flag;
return flag;
}
};
};
// setTimeoutとほぼ同じ
// カリー化っぽいこともできる
re.late = function () {
var arg = arguments, ms;
if (arg.length === 1) {
ms = arg[0];
return function (func) {
setTimeout(func, ms);
};
} else if (arg.length === 2) {
ms = arg[1];
setTimeout(func, ms);
}
};
re.text = function () {
return arguments.length ? Array.apply([], arguments).join("") : "";
};
re.t = re.text;
// フラグなど
var busy = re.Flag(true);
var isGameStarted = re.Flag(false);
var isPlayerTurn = re.Flag(false);
// 初期化する関数
re.init = function () {
// 盤を空にする
for (var w = 0; w < 8; w ++) {
for (var h = 0; h < 8; h ++) {
busy.off();
re.board.put(w, h, re.type.none);
busy.on();
}
}
var t = 1;
// 遅延させつつ、最初の4つの石を置く
setTimeout(function () {
busy.off();
re.board.put(3, 3, re.type.black);
busy.on();
}, (t ++) * 200);
setTimeout(function () {
busy.off();
re.board.put(3, 4, re.type.white);
busy.on();
}, (t ++) * 200);
setTimeout(function () {
busy.off();
re.board.put(4, 3, re.type.white);
busy.on();
}, (t ++) * 200);
setTimeout(function () {
busy.off();
re.board.put(4, 4, re.type.black);
busy.on();
}, (t ++) * 200);
};
// ログを記録する関数(を返す関数)
re.log = function () {
var log = []; // クロージャで配列にアクセス
var chars = {
"<": "&lt;",
">": "&gt;",
"&": "&amp;",
"\"": "&quot;"
};
return function (text, style) {
text += "";
var res;
var date = (new Date).strftime("%H:%M:%S"); // 時間を文字列で表現
date = "[" + date + "]";
// 第2引数が配列ならば、
if ((typeof style).match(/array/i)) {
style = style.join(" "); // 配列を空白で区切って連結して文字列に
}
// 未定義なら、文字列は空
else if (typeof style === "undefined") {
style = "";
}
// ログを変数に残す
log.push([text,style]);
// 実体参照に変換
text = text.replace(/[<>&"]/g, function (c) {
return chars[c];
});
// リストに、li要素を追加
res = re.$
.find("#console ul")
.append(
$.create("li")
.append(
$.create("span", date, {"className": "date"})
)
.append(
$.create("span", text, {"className": style})
)
);
// 一番下にスクロール
res = res.parent().animate({
scrollTop: res.height()
}, 1);
};
}();
// ゲーム開始の関数
re.gameStart = function () {
// busyフラグ立てる
busy.on();
// 開始フラグ立てる
isGameStarted.on();
// 初期化を行う
re.init();
// ログに記録
re.log("Game Start !!", "bold");
// playerが黒ならば、playerのターンに
if (re.user.player === re.type.black) {
isPlayerTurn.on();
}
// そうでない場合は、computerのターンに
else {
isPlayerTurn.off();
re.computerPlay();
}
};
// 石を置く関数
re.board.put = function () {
// ゲーム中でないか、またはbusyフラグが立っていれば、
// false返して終わり
if (busy.get() || !isGameStarted.get()) {
return false;
}
var arg = arguments, x, y, t;
// 引数が2つ => (y*8+x)の値で指定されたとき
if (arg.length === 2) {
arg[0] = ~~(arg[0]);
x = arg[0] % 8;
y = (arg[0] - x) / 8;
t = arg[1];
}
// 引数が3つ => x,yで指定されたとき
else if (arg.length === 3) {
x = ~~(arg[0]);
y = ~~(arg[1]);
t = arg[2];
}
else {
return false;
}
// ifにすると長いので、変数にまとめる
var res;
res = !isNaN(x) && !isNaN(y); // 計算が間違っていないことを確認
res = res && x >= 0 && x < 8; // xは正常な範囲か
res = res && y >= 0 && y < 8; // yは正常な範囲か
// なし、黒、白のいずれかが指定されているか
res = res && (t === re.type.none || t === re.type.black || t === re.type.white);
if (res) {
// 指定された場所に、classを追加
re.$_
.eq(x + (y * 8))
.attr("class", "")
.addClass(re.type.getClass(t));
// 配列にも、データを追加
re.board[x][y] = t;
}
};
re.clickAction = function (index) {
index -= 0;
var x = index % 8;
var y = (index - x) / 8;
if (x < 0 || x >= 8 || y < 0 || y >= 8) {
return false;
}
if (isPlayerTurn.get()) {
re.playerPlay(x, y);
}
};
re.computerPlay = function () {
var a, b, res;
if (re.isEnd(re.type.computer)) {
return;
}
if (!re.countCanPut(re.user.computer)) {
isPlayerTurn.on();
re.log("passed;");
return;
}
for (a = 0; a < 8; a ++) {
for (b = 0; b < 8; b ++) {
busy.off();
res = re.board.putAndTurn(a, b, re.user.computer);
busy.on();
if (res) {
if (re.countCanPut(re.user.computer)) {
isPlayerTurn.on();
re.log("ok.");
return;
}
}
}
}
};
re.playerPlay = function (x, y) {
var res;
if (isGameStarted.get()) {
re.log(re.t("x = ", x, ", y = ", y, ";"));
busy.off();
res = re.board.putAndTurn(x, y, re.user.player);
busy.on();
if (res) {
re.log("ok!");
isPlayerTurn.off();
setTimeout(function () {
re.computerPlay();
}, 500);
} else {
re.log("cannot put!");
}
}
};
// 石を置いて返す関数
// notPutをtrueにすると、置けるかどうかだけを返す
re.board.putAndTurn = function (x, y, type, notPut) {
var posX, posY,
dX, dY,
tX, tY,
count = 0, _count = 0,
_type = re.type.reverse(type);
notPut = notPut ? true : false;
// そこが空の場合 => 置ける可能性あり
if (re.board[x][y] === re.type.none) {
// 全部の方向に向かって探索
for (dX = -1; dX <= 1; dX ++) { // 右、左、真中
for (dY = -1; dY <= 1; dY ++) { // 上、下、真中
if (dX || dY) { // 真中と真中の時以外
posX = x;
posY = y;
_count = 0;
// 盤をはみ出さないように
while (true) {
posX += dX;
posY += dY;
if (posX < 0 || posY < 0 || posX >= 8 || posY >= 8) {
break;
}
// そこが空でなければ
if (re.board[posX][posY] !== re.type.none) {
// そして自分の石ならば
if (re.board[posX][posY] === type) {
// 仮のカウンターをカウンターに加える
count += _count;
// notPutがtrueでなければ、石を返す
if (!notPut) {
tX = x;
tY = y;
for (var a = 0; a < _count; a ++) {
if (!a) {
re.board.put(x, y, type);
}
tX += dX;
tY += dY;
re.board.put(tX, tY, type);
}
}
break;
}
// 相手の石だったら、仮のカウンターに加算
else {
_count ++;
}
} else { // そこが空ならば、ループ終わり
break;
}
}
}
}
}
}
// 取れる石の数(=カウンター)を返す
return count;
};
re.countCanPut = function (type) {
var a , b, res = 0;
for (a = 0; a < 8; a ++) {
for (b = 0; b < 8; b ++) {
res += re.board.putAndTurn(a, b, type, true);
}
}
return res;
};
re.board.count = function (type) {
var count = 0;
for (var b = 0; b < 8; b ++) {
for (var c = 0; c < 8; c ++) {
if (re.board[a][b] === type) {
count ++;
}
}
}
return count;
};
re.isEnd = function (type) {
if (re.countCanPut(type) || !re.countCanPut(re.type.reverse(type))) {
return false;
} else {
isGameStarted.off();
re.log("end");
busy.on();
return true;
}
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment