533 lines
14 KiB
JavaScript
533 lines
14 KiB
JavaScript
// Generated by CoffeeScript 1.6.3
|
|
var BAKAZE_TO_STR, TSUPAIS, TSUPAI_TO_IMAGE_NAME, cloneBoard, comparePais, currentActionId, currentKyokuId, currentViewpoint, deleteTehai, dumpBoard, getCurrentKyoku, goBack, goNext, initPlayers, kyokus, loadAction, paiToImageUrl, parsePai, playerInfos, removeRed, renderAction, renderCurrentAction, renderHo, renderPai, renderPais, ripai, sortPais, _base, _base1;
|
|
|
|
window.console || (window.console = {});
|
|
|
|
(_base = window.console).log || (_base.log = function() {});
|
|
|
|
(_base1 = window.console).error || (_base1.error = function() {});
|
|
|
|
TSUPAIS = [null, "E", "S", "W", "N", "P", "F", "C"];
|
|
|
|
TSUPAI_TO_IMAGE_NAME = {
|
|
"E": "ji_e",
|
|
"S": "ji_s",
|
|
"W": "ji_w",
|
|
"N": "ji_n",
|
|
"P": "no",
|
|
"F": "ji_h",
|
|
"C": "ji_c"
|
|
};
|
|
|
|
BAKAZE_TO_STR = {
|
|
"E": "東",
|
|
"S": "南",
|
|
"W": "西",
|
|
"N": "北"
|
|
};
|
|
|
|
kyokus = [];
|
|
|
|
currentKyokuId = 0;
|
|
|
|
currentActionId = 0;
|
|
|
|
currentViewpoint = 0;
|
|
|
|
playerInfos = [{}, {}, {}, {}];
|
|
|
|
parsePai = function(pai) {
|
|
if (pai.match(/^([1-9])(.)(r)?$/)) {
|
|
return {
|
|
type: RegExp.$2,
|
|
number: parseInt(RegExp.$1),
|
|
red: RegExp.$3 ? true : false
|
|
};
|
|
} else {
|
|
return {
|
|
type: "t",
|
|
number: TSUPAIS.indexOf(pai),
|
|
red: false
|
|
};
|
|
}
|
|
};
|
|
|
|
comparePais = function(lhs, rhs) {
|
|
var lhsRep, parsedLhs, parsedRhs, rhsRep;
|
|
parsedLhs = parsePai(lhs);
|
|
lhsRep = parsedLhs.type + parsedLhs.number + (parsedLhs.red ? "1" : "0");
|
|
parsedRhs = parsePai(rhs);
|
|
rhsRep = parsedRhs.type + parsedRhs.number + (parsedRhs.red ? "1" : "0");
|
|
if (lhsRep < rhsRep) {
|
|
return -1;
|
|
} else if (lhsRep > rhsRep) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
sortPais = function(pais) {
|
|
return pais.sort(comparePais);
|
|
};
|
|
|
|
paiToImageUrl = function(pai, pose) {
|
|
var ext, name, parsedPai, redSuffix;
|
|
if (pai) {
|
|
if (pai === "?") {
|
|
name = "bk";
|
|
ext = "gif";
|
|
} else {
|
|
parsedPai = parsePai(pai);
|
|
if (parsedPai.type === "t") {
|
|
name = TSUPAI_TO_IMAGE_NAME[pai];
|
|
} else {
|
|
redSuffix = parsedPai.red ? "r" : "";
|
|
name = "" + parsedPai.type + "s" + parsedPai.number + redSuffix;
|
|
}
|
|
ext = parsedPai.red ? "png" : "gif";
|
|
}
|
|
if (pose === void 0) {
|
|
pose = 1;
|
|
}
|
|
return "files/images/p_" + name + "_" + pose + "." + ext;
|
|
} else {
|
|
return "files/images/blank.png";
|
|
}
|
|
};
|
|
|
|
cloneBoard = function(board) {
|
|
var bk, bv, newBoard, newPlayer, pk, player, pv, _i, _len;
|
|
newBoard = {};
|
|
for (bk in board) {
|
|
bv = board[bk];
|
|
if (bk === "players") {
|
|
newBoard[bk] = [];
|
|
for (_i = 0, _len = bv.length; _i < _len; _i++) {
|
|
player = bv[_i];
|
|
newPlayer = {};
|
|
for (pk in player) {
|
|
pv = player[pk];
|
|
newPlayer[pk] = pv;
|
|
}
|
|
newBoard[bk].push(newPlayer);
|
|
}
|
|
} else {
|
|
newBoard[bk] = bv;
|
|
}
|
|
}
|
|
return newBoard;
|
|
};
|
|
|
|
initPlayers = function(board) {
|
|
var player, _i, _len, _ref, _results;
|
|
_ref = board.players;
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
player = _ref[_i];
|
|
player.tehais = null;
|
|
player.furos = [];
|
|
player.ho = [];
|
|
player.reach = false;
|
|
_results.push(player.reachHoIndex = null);
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
removeRed = function(pai) {
|
|
if (!pai) {
|
|
return null;
|
|
}
|
|
if (pai.match(/^(.+)r$/)) {
|
|
return RegExp.$1;
|
|
} else {
|
|
return pai;
|
|
}
|
|
};
|
|
|
|
loadAction = function(action) {
|
|
var actorPlayer, board, furos, i, kyoku, pai, prevBoard, targetPlayer, _i, _j, _k, _l, _len, _len1, _m, _n, _o, _ref, _ref1, _ref2;
|
|
if (kyokus.length > 0) {
|
|
kyoku = kyokus[kyokus.length - 1];
|
|
board = cloneBoard(kyoku.actions[kyoku.actions.length - 1].board);
|
|
} else {
|
|
kyoku = null;
|
|
board = null;
|
|
}
|
|
if (board && ("actor" in action)) {
|
|
actorPlayer = board.players[action.actor];
|
|
} else {
|
|
actorPlayer = null;
|
|
}
|
|
if (board && ("target" in action)) {
|
|
targetPlayer = board.players[action.target];
|
|
} else {
|
|
targetPlayer = null;
|
|
}
|
|
switch (action.type) {
|
|
case "start_game":
|
|
for (i = _i = 0; _i < 4; i = ++_i) {
|
|
playerInfos[i].name = action.names[i];
|
|
}
|
|
break;
|
|
case "end_game":
|
|
null;
|
|
break;
|
|
case "start_kyoku":
|
|
kyoku = {
|
|
actions: [],
|
|
bakaze: action.bakaze,
|
|
kyokuNum: action.kyoku,
|
|
honba: action.honba
|
|
};
|
|
kyokus.push(kyoku);
|
|
prevBoard = board;
|
|
board = {
|
|
players: [{}, {}, {}, {}],
|
|
doraMarkers: [action.dora_marker]
|
|
};
|
|
initPlayers(board);
|
|
for (i = _j = 0; _j < 4; i = ++_j) {
|
|
board.players[i].tehais = action.tehais[i];
|
|
if (prevBoard) {
|
|
board.players[i].score = prevBoard.players[i].score;
|
|
} else {
|
|
board.players[i].score = 25000;
|
|
}
|
|
}
|
|
break;
|
|
case "end_kyoku":
|
|
null;
|
|
break;
|
|
case "tsumo":
|
|
actorPlayer.tehais = actorPlayer.tehais.concat([action.pai]);
|
|
break;
|
|
case "dahai":
|
|
deleteTehai(actorPlayer, action.pai);
|
|
actorPlayer.ho = actorPlayer.ho.concat([action.pai]);
|
|
break;
|
|
case "reach":
|
|
actorPlayer.reachHoIndex = actorPlayer.ho.length;
|
|
break;
|
|
case "reach_accepted":
|
|
actorPlayer.reach = true;
|
|
break;
|
|
case "chi":
|
|
case "pon":
|
|
case "daiminkan":
|
|
targetPlayer.ho = targetPlayer.ho.slice(0, targetPlayer.ho.length - 1);
|
|
_ref = action.consumed;
|
|
for (_k = 0, _len = _ref.length; _k < _len; _k++) {
|
|
pai = _ref[_k];
|
|
deleteTehai(actorPlayer, pai);
|
|
}
|
|
actorPlayer.furos = actorPlayer.furos.concat([
|
|
{
|
|
type: action.type,
|
|
taken: action.pai,
|
|
consumed: action.consumed,
|
|
target: action.target
|
|
}
|
|
]);
|
|
break;
|
|
case "ankan":
|
|
_ref1 = action.consumed;
|
|
for (_l = 0, _len1 = _ref1.length; _l < _len1; _l++) {
|
|
pai = _ref1[_l];
|
|
deleteTehai(actorPlayer, pai);
|
|
}
|
|
actorPlayer.furos = actorPlayer.furos.concat([
|
|
{
|
|
type: action.type,
|
|
consumed: action.consumed
|
|
}
|
|
]);
|
|
break;
|
|
case "kakan":
|
|
deleteTehai(actorPlayer, action.pai);
|
|
actorPlayer.furos = actorPlayer.furos.concat([]);
|
|
furos = actorPlayer.furos;
|
|
for (i = _m = 0, _ref2 = furos.length; 0 <= _ref2 ? _m < _ref2 : _m > _ref2; i = 0 <= _ref2 ? ++_m : --_m) {
|
|
if (furos[i].type === "pon" && removeRed(furos[i].taken) === removeRed(action.pai)) {
|
|
furos[i] = {
|
|
type: "kakan",
|
|
taken: action.pai,
|
|
consumed: action.consumed,
|
|
target: furos[i].target
|
|
};
|
|
}
|
|
}
|
|
break;
|
|
case "hora":
|
|
case "ryukyoku":
|
|
null;
|
|
break;
|
|
case "dora":
|
|
board.doraMarkers = board.doraMarkers.concat([action.dora_marker]);
|
|
break;
|
|
case "error":
|
|
null;
|
|
break;
|
|
default:
|
|
throw "unknown action: " + action.type;
|
|
}
|
|
if (action.scores) {
|
|
for (i = _n = 0; _n < 4; i = ++_n) {
|
|
board.players[i].score = action.scores[i];
|
|
}
|
|
}
|
|
if (kyoku) {
|
|
for (i = _o = 0; _o < 4; i = ++_o) {
|
|
if (action.actor !== void 0 && i !== action.actor) {
|
|
ripai(board.players[i]);
|
|
}
|
|
}
|
|
action.board = board;
|
|
return kyoku.actions.push(action);
|
|
}
|
|
};
|
|
|
|
deleteTehai = function(player, pai) {
|
|
var idx;
|
|
player.tehais = player.tehais.concat([]);
|
|
idx = player.tehais.lastIndexOf(pai);
|
|
if (idx < 0) {
|
|
idx = player.tehais.lastIndexOf("?");
|
|
}
|
|
if (idx < 0) {
|
|
throw "pai not in tehai";
|
|
}
|
|
return player.tehais[idx] = null;
|
|
};
|
|
|
|
ripai = function(player) {
|
|
var pai;
|
|
if (player.tehais) {
|
|
player.tehais = (function() {
|
|
var _i, _len, _ref, _results;
|
|
_ref = player.tehais;
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
pai = _ref[_i];
|
|
if (pai) {
|
|
_results.push(pai);
|
|
}
|
|
}
|
|
return _results;
|
|
})();
|
|
return sortPais(player.tehais);
|
|
}
|
|
};
|
|
|
|
dumpBoard = function(board) {
|
|
var consumedStr, furo, hoStr, i, player, tehaisStr, _i, _j, _len, _ref, _results;
|
|
_results = [];
|
|
for (i = _i = 0; _i < 4; i = ++_i) {
|
|
player = board.players[i];
|
|
if (player.tehais) {
|
|
tehaisStr = player.tehais.join(" ");
|
|
_ref = player.furos;
|
|
for (_j = 0, _len = _ref.length; _j < _len; _j++) {
|
|
furo = _ref[_j];
|
|
consumedStr = furo.consumed.join(" ");
|
|
tehaisStr += " [" + furo.taken + "/" + consumedStr + "]";
|
|
}
|
|
console.log("[" + i + "] tehais: " + tehaisStr);
|
|
}
|
|
if (player.ho) {
|
|
hoStr = player.ho.join(" ");
|
|
_results.push(console.log("[" + i + "] ho: " + hoStr));
|
|
} else {
|
|
_results.push(void 0);
|
|
}
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
renderPai = function(pai, view, pose) {
|
|
if (pose === void 0) {
|
|
pose = 1;
|
|
}
|
|
view.attr("src", paiToImageUrl(pai, pose));
|
|
switch (pose) {
|
|
case 1:
|
|
view.addClass("pai");
|
|
return view.removeClass("laid-pai");
|
|
case 3:
|
|
view.addClass("laid-pai");
|
|
return view.removeClass("pai");
|
|
default:
|
|
throw "unknown pose";
|
|
}
|
|
};
|
|
|
|
renderPais = function(pais, view, poses) {
|
|
var i, _i, _ref, _results;
|
|
pais || (pais = []);
|
|
poses || (poses = []);
|
|
view.resize(pais.length);
|
|
_results = [];
|
|
for (i = _i = 0, _ref = pais.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
|
_results.push(renderPai(pais[i], view.at(i), poses[i]));
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
renderHo = function(player, offset, pais, view) {
|
|
var i, reachIndex, _i, _ref, _results;
|
|
if (player.reachHoIndex === null) {
|
|
reachIndex = null;
|
|
} else {
|
|
reachIndex = player.reachHoIndex - offset;
|
|
}
|
|
view.resize(pais.length);
|
|
_results = [];
|
|
for (i = _i = 0, _ref = pais.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
|
_results.push(renderPai(pais[i], view.at(i), i === reachIndex ? 3 : 1));
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
renderAction = function(action) {
|
|
var dir, displayAction, furo, furoView, ho, i, infoView, j, k, kyoku, laidPos, pais, player, poses, v, view, wanpais, _i, _j, _ref, _ref1, _ref2, _ref3;
|
|
displayAction = {};
|
|
for (k in action) {
|
|
v = action[k];
|
|
if (k !== "board" && k !== "logs") {
|
|
displayAction[k] = v;
|
|
}
|
|
}
|
|
$("#action-label").text(JSON.stringify(displayAction, null, 2));
|
|
$("#log-label").text((action.logs && action.logs[currentViewpoint]) || "");
|
|
kyoku = getCurrentKyoku();
|
|
for (i = _i = 0; _i < 4; i = ++_i) {
|
|
player = action.board.players[i];
|
|
view = Dytem.players.at((i - currentViewpoint + 4) % 4);
|
|
infoView = Dytem.playerInfos.at(i);
|
|
infoView.score.text(player.score);
|
|
infoView.viewpoint.text(i === currentViewpoint ? "+" : "");
|
|
if (!player.tehais) {
|
|
renderPais([], view.tehais);
|
|
view.tsumoPai.hide();
|
|
} else if (player.tehais.length % 3 === 2) {
|
|
renderPais(player.tehais.slice(0, player.tehais.length - 1), view.tehais);
|
|
view.tsumoPai.show();
|
|
renderPai(player.tehais[player.tehais.length - 1], view.tsumoPai);
|
|
} else {
|
|
renderPais(player.tehais, view.tehais);
|
|
view.tsumoPai.hide();
|
|
}
|
|
ho = player.ho || [];
|
|
renderHo(player, 0, ho.slice(0, 6), view.hoRows.at(0).pais);
|
|
renderHo(player, 6, ho.slice(6, 12), view.hoRows.at(1).pais);
|
|
renderHo(player, 12, ho.slice(12), view.hoRows.at(2).pais);
|
|
view.furos.resize(player.furos.length);
|
|
if (player.furos) {
|
|
j = player.furos.length - 1;
|
|
while (j >= 0) {
|
|
furo = player.furos[j];
|
|
furoView = view.furos.at(player.furos.length - 1 - j);
|
|
if (furo.type === "ankan") {
|
|
pais = ["?"].concat(furo.consumed.slice(0, 2)).concat(["?"]);
|
|
poses = [1, 1, 1, 1];
|
|
} else {
|
|
dir = (4 + furo.target - i) % 4;
|
|
if ((_ref = furo.type) === "daiminkan" || _ref === "kakan") {
|
|
laidPos = [null, 3, 1, 0][dir];
|
|
} else {
|
|
laidPos = [null, 2, 1, 0][dir];
|
|
}
|
|
pais = furo.consumed.concat([]);
|
|
poses = [1, 1, 1];
|
|
[].splice.apply(pais, [laidPos, laidPos - laidPos].concat(_ref1 = [furo.taken])), _ref1;
|
|
[].splice.apply(poses, [laidPos, laidPos - laidPos].concat(_ref2 = [3])), _ref2;
|
|
}
|
|
renderPais(pais, furoView.pais, poses);
|
|
--j;
|
|
}
|
|
}
|
|
}
|
|
wanpais = ["?", "?", "?", "?", "?", "?"];
|
|
for (i = _j = 0, _ref3 = action.board.doraMarkers.length; 0 <= _ref3 ? _j < _ref3 : _j > _ref3; i = 0 <= _ref3 ? ++_j : --_j) {
|
|
wanpais[i + 2] = action.board.doraMarkers[i];
|
|
}
|
|
return renderPais(wanpais, Dytem.wanpais);
|
|
};
|
|
|
|
getCurrentKyoku = function() {
|
|
return kyokus[currentKyokuId];
|
|
};
|
|
|
|
renderCurrentAction = function() {
|
|
return renderAction(getCurrentKyoku().actions[currentActionId]);
|
|
};
|
|
|
|
goNext = function() {
|
|
if (currentActionId === getCurrentKyoku().actions.length - 1) {
|
|
return;
|
|
}
|
|
++currentActionId;
|
|
$("#action-id-label").val(currentActionId);
|
|
return renderCurrentAction();
|
|
};
|
|
|
|
goBack = function() {
|
|
if (currentActionId === 0) {
|
|
return;
|
|
}
|
|
--currentActionId;
|
|
$("#action-id-label").val(currentActionId);
|
|
return renderCurrentAction();
|
|
};
|
|
|
|
$(function() {
|
|
var action, bakazeStr, honba, i, j, kyokuNum, label, playerInfoView, playerView, _i, _j, _k, _l, _len, _ref;
|
|
$(window).bind("mousewheel", function(e) {
|
|
e.preventDefault();
|
|
if (e.originalEvent.wheelDelta < 0) {
|
|
return goNext();
|
|
} else if (e.originalEvent.wheelDelta > 0) {
|
|
return goBack();
|
|
}
|
|
});
|
|
$("#prev-button").click(goBack);
|
|
$("#next-button").click(goNext);
|
|
$("#go-button").click(function() {
|
|
currentActionId = parseInt($("#action-id-label").val());
|
|
return renderCurrentAction();
|
|
});
|
|
$("#kyokuSelector").change(function() {
|
|
currentKyokuId = parseInt($("#kyokuSelector").val());
|
|
currentActionId = 0;
|
|
return renderCurrentAction();
|
|
});
|
|
$("#viewpoint-button").click(function() {
|
|
currentViewpoint = (currentViewpoint + 1) % 4;
|
|
return renderCurrentAction();
|
|
});
|
|
for (_i = 0, _len = allActions.length; _i < _len; _i++) {
|
|
action = allActions[_i];
|
|
loadAction(action);
|
|
}
|
|
Dytem.init();
|
|
for (i = _j = 0; _j < 4; i = ++_j) {
|
|
playerView = Dytem.players.append();
|
|
playerView.addClass("player-" + i);
|
|
for (j = _k = 0; _k < 3; j = ++_k) {
|
|
playerView.hoRows.append();
|
|
}
|
|
playerInfoView = Dytem.playerInfos.append();
|
|
playerInfoView.index.text(i);
|
|
playerInfoView.name.text(playerInfos[i].name);
|
|
}
|
|
for (i = _l = 0, _ref = kyokus.length; 0 <= _ref ? _l < _ref : _l > _ref; i = 0 <= _ref ? ++_l : --_l) {
|
|
bakazeStr = BAKAZE_TO_STR[kyokus[i].bakaze];
|
|
honba = kyokus[i].honba;
|
|
kyokuNum = kyokus[i].kyokuNum;
|
|
label = "" + bakazeStr + kyokuNum + "局 " + honba + "本場";
|
|
$("#kyokuSelector").get(0).options[i] = new Option(label, i);
|
|
}
|
|
console.log("loaded");
|
|
return renderCurrentAction();
|
|
});
|