Created
April 5, 2011 02:06
-
-
Save odiak/902893 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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 = { | |
"<": "<", | |
">": ">", | |
"&": "&", | |
"\"": """ | |
}; | |
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