Add routes
This commit is contained in:
parent
3c936c75a6
commit
f4b3c0a333
521
routes/mj.js
Normal file
521
routes/mj.js
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
let dict = require('./translate');
|
||||||
|
|
||||||
|
function Tile(t) {
|
||||||
|
let m = Math.floor(t / 36),
|
||||||
|
d = t % 36,
|
||||||
|
n = Math.floor(d / 4) + 1,
|
||||||
|
res;
|
||||||
|
switch (m) {
|
||||||
|
case 0:
|
||||||
|
res = 'm' + (d == 16 ? 'a' : n);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
res = 'p' + (d == 16 ? 'a' : n);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
res = 's' + (d == 16 ? 'a' : n);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
let s = Math.floor(d / 4);
|
||||||
|
switch (s) {
|
||||||
|
case 0:
|
||||||
|
res = 'tan';
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
res = 'nan';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
res = 'xia';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
res = 'pei';
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
res = 'haku';
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
res = 'hatsu';
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
res = 'chun';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Hand(h) {
|
||||||
|
return h.map(function(t) {
|
||||||
|
return Tile(t);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceTiles(trg) {
|
||||||
|
let res = trg;
|
||||||
|
for (var r = 0; r < res.rounds.length; r++) {
|
||||||
|
// обработка конечных рук
|
||||||
|
for (var f = 0; f < res.rounds[r].finish.length; f++) {
|
||||||
|
let finish = res.rounds[r].finish[f].sort(function(a, b) {
|
||||||
|
return a - b;
|
||||||
|
});
|
||||||
|
res.rounds[r].finish[f] = Hand(res.rounds[r].finish[f]).slice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeList(list, to_int, sort) {
|
||||||
|
if (typeof sort === 'undefined') sort = false;
|
||||||
|
let res = list.split(',');
|
||||||
|
res = (to_int ? res.map(function(a) {
|
||||||
|
return parseInt(a);
|
||||||
|
}) : res);
|
||||||
|
return (sort ? res.sort(function(a, b) {
|
||||||
|
return a - b;
|
||||||
|
}) : res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseScore(data, mult) {
|
||||||
|
let res = [];
|
||||||
|
for (var i = 0; i < data.length / 2; i++) {
|
||||||
|
res.push({
|
||||||
|
begin: data[2 * i] * mult,
|
||||||
|
diff: data[2 * i + 1] * mult,
|
||||||
|
end: (data[2 * i] + data[2 * i + 1]) * mult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseMeld(data) {
|
||||||
|
if (data & 0x4) {
|
||||||
|
return parse_chi(data);
|
||||||
|
} else if (data & 0x18) {
|
||||||
|
return parse_pon(data);
|
||||||
|
} else if (data & 0x20) {
|
||||||
|
return parse_nuki(data);
|
||||||
|
} else {
|
||||||
|
return parse_kan(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_chi(data) {
|
||||||
|
let t0 = (data >> 3) & 0x3,
|
||||||
|
t1 = (data >> 5) & 0x3,
|
||||||
|
t2 = (data >> 7) & 0x3,
|
||||||
|
base_and_called = data >> 10,
|
||||||
|
base = Math.floor(base_and_called / 3),
|
||||||
|
called = base_and_called - 3 * base;
|
||||||
|
base = Math.floor(base / 7) * 9 + base % 7;
|
||||||
|
return {
|
||||||
|
type: 'chi',
|
||||||
|
fromPlayer: (data & 0x3),
|
||||||
|
called: called,
|
||||||
|
tiles: [t0 + 4 * (base + 0), t1 + 4 * (base + 1), t2 + 4 * (base + 2)]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_pon(data) {
|
||||||
|
let t4 = (data >> 5) & 0x3,
|
||||||
|
arr = [
|
||||||
|
[1, 2, 3],
|
||||||
|
[0, 2, 3],
|
||||||
|
[0, 1, 3],
|
||||||
|
[0, 1, 2]
|
||||||
|
],
|
||||||
|
t0 = arr[t4][0],
|
||||||
|
t1 = arr[t4][1],
|
||||||
|
t2 = arr[t4][2],
|
||||||
|
base_and_called = data >> 9,
|
||||||
|
base = Math.floor(base_and_called / 3),
|
||||||
|
called = base_and_called - 3 * base;
|
||||||
|
if (data & 0x8) {
|
||||||
|
return {
|
||||||
|
type: 'pon',
|
||||||
|
fromPlayer: (data & 0x3),
|
||||||
|
called: called,
|
||||||
|
tiles: [t0 + 4 * base, t1 + 4 * base, t2 + 4 * base]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
type: 'chakan',
|
||||||
|
fromPlayer: (data & 0x3),
|
||||||
|
called: called,
|
||||||
|
tiles: [t0 + 4 * base, t1 + 4 * base, t2 + 4 * base, t4 + 4 * base]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_kan(data) {
|
||||||
|
let base_and_called = data >> 8,
|
||||||
|
base = Math.floor(base_and_called / 4),
|
||||||
|
called = base_and_called - 4 * base;
|
||||||
|
return {
|
||||||
|
type: 'kan',
|
||||||
|
fromPlayer: (data & 0x3),
|
||||||
|
called: called,
|
||||||
|
tiles: [4 * base, 1 + 4 * base, 2 + 4 * base, 3 + 4 * base]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_nuki(data) {
|
||||||
|
return {
|
||||||
|
type: 'nuki',
|
||||||
|
tiles: [data >> 8]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLog(namelog, file, lang) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
var fs = require('fs'),
|
||||||
|
xmlparser = require('htmlparser2');
|
||||||
|
var parser = new xmlparser.Parser({
|
||||||
|
onopentag: function(name, attribs) {
|
||||||
|
switch (true) {
|
||||||
|
case /mjloggm/.test(name):
|
||||||
|
res = {
|
||||||
|
log: namelog,
|
||||||
|
players: [],
|
||||||
|
rounds: []
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case /un/.test(name) && (typeof attribs.sx !== 'undefined'):
|
||||||
|
var sex = decodeList(attribs.sx),
|
||||||
|
dan = decodeList(attribs.dan),
|
||||||
|
rate = decodeList(attribs.rate);
|
||||||
|
[0, 1, 2, 3].forEach(function(p) {
|
||||||
|
res.players[p] = {
|
||||||
|
name: decodeURIComponent(attribs['n' + p]),
|
||||||
|
sex: sex[p],
|
||||||
|
dan: parseInt(dan[p]),
|
||||||
|
rate: parseFloat(rate[p]),
|
||||||
|
connected: true
|
||||||
|
};
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case /bye/.test(name) && (typeof attribs.who !== 'undefined'):
|
||||||
|
res.players[parseInt(attribs.who)].connected = false;
|
||||||
|
break;
|
||||||
|
case /taikyoku/.test(name) && (typeof attribs.oya !== 'undefined'):
|
||||||
|
res.diler = parseInt(attribs.oya);
|
||||||
|
break;
|
||||||
|
case /init/.test(name) && (typeof attribs.oya !== 'undefined'):
|
||||||
|
let seed = decodeList(attribs.seed);
|
||||||
|
res.rounds.push({
|
||||||
|
name: parseInt(seed[0]),
|
||||||
|
honba: parseInt(seed[1]),
|
||||||
|
riichi: {
|
||||||
|
count: parseInt(seed[2]),
|
||||||
|
player: []
|
||||||
|
},
|
||||||
|
d0: parseInt(seed[3]),
|
||||||
|
d1: parseInt(seed[4]),
|
||||||
|
dora: Hand([parseInt(seed[5])]),
|
||||||
|
uradora: [],
|
||||||
|
diler: parseInt(attribs.oya),
|
||||||
|
hands: [],
|
||||||
|
finish: [],
|
||||||
|
meld: [
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
events: [
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
cur_game = res.rounds.length - 1;
|
||||||
|
cur_player = res.rounds[cur_game].diler;
|
||||||
|
cur_event = -1;
|
||||||
|
[0, 1, 2, 3].forEach(function(p) {
|
||||||
|
res.rounds[cur_game].finish[p] = decodeList(attribs['hai' + p], true, true);
|
||||||
|
res.rounds[cur_game].hands[p] = Hand(decodeList(attribs['hai' + p], true, true));
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case /agari/.test(name) && (typeof attribs.ba !== 'undefined'):
|
||||||
|
if (!res.rounds[cur_game].win) res.rounds[cur_game].win = [];
|
||||||
|
let ten = decodeList(attribs.ten),
|
||||||
|
hand = decodeList(attribs.hai, true, true),
|
||||||
|
machi = decodeList(attribs.machi, true, false),
|
||||||
|
wintile = hand.indexOf(machi[0]),
|
||||||
|
agari = {
|
||||||
|
type: (attribs.fromwho != attribs.who ? 'ron' : 'tsumo'),
|
||||||
|
player: parseInt(attribs.who),
|
||||||
|
hand: Hand(hand),
|
||||||
|
points: parseInt(ten[1]),
|
||||||
|
fu: parseInt(ten[0]),
|
||||||
|
dora: Hand(decodeList(attribs.dorahai, true, false)),
|
||||||
|
machi: wintile
|
||||||
|
};
|
||||||
|
if (attribs.m) {
|
||||||
|
agari.melds = [];
|
||||||
|
decodeList(attribs.m, true, false).forEach(function(m) {
|
||||||
|
agari.melds.push(parseMeld(m));
|
||||||
|
});
|
||||||
|
agari.closed = [];
|
||||||
|
agari.melds.forEach(function(m) {
|
||||||
|
m.tiles = Hand(m.tiles);
|
||||||
|
if (!m.fromPlayer) {
|
||||||
|
agari.closed.push(m);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
agari.closed = true;
|
||||||
|
}
|
||||||
|
if (parseInt(ten[2]) > 0) {
|
||||||
|
agari.limit = parseInt(ten[2]);
|
||||||
|
}
|
||||||
|
if (attribs.dorahaiura) {
|
||||||
|
agari.uradora = Hand(decodeList(attribs.dorahaiura, true, false));
|
||||||
|
res.rounds[cur_game].uradora = agari.uradora;
|
||||||
|
}
|
||||||
|
if (agari.type == 'ron') {
|
||||||
|
agari.fromPlayer = parseInt(attribs.fromwho);
|
||||||
|
res.rounds[cur_game].events[agari.fromPlayer][res.rounds[cur_game].events[agari.fromPlayer].length - 1].furikomi = 1;
|
||||||
|
}
|
||||||
|
if (attribs.yaku) {
|
||||||
|
let yakus = decodeList(attribs.yaku);
|
||||||
|
agari.yakulist = [];
|
||||||
|
for (var y = 0; y < yakus.length / 2; y++) {
|
||||||
|
agari.yakulist.push({
|
||||||
|
yaku: parseInt(yakus[2 * y]),
|
||||||
|
han: parseInt(yakus[2 * y + 1])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (attribs.yakuman) {
|
||||||
|
agari.yakuman = decodeList(attribs.yakuman, true, true);
|
||||||
|
}
|
||||||
|
if (attribs.sc) {
|
||||||
|
res.rounds[cur_game].score = parseScore(decodeList(attribs.sc, true, false), 100);
|
||||||
|
}
|
||||||
|
res.rounds[cur_game].win.push(agari);
|
||||||
|
res.rounds[cur_game].finish[parseInt(attribs.who)] = [];
|
||||||
|
break;
|
||||||
|
case /ryuukyoku/.test(name) && (typeof attribs.ba !== 'undefined'):
|
||||||
|
res.rounds[cur_game].draw = {};
|
||||||
|
if (attribs.type) {
|
||||||
|
res.rounds[cur_game].draw.type = attribs.type;
|
||||||
|
}
|
||||||
|
if (attribs.sc) {
|
||||||
|
res.rounds[cur_game].score = parseScore(decodeList(attribs.sc, true, false), 100);
|
||||||
|
}
|
||||||
|
if (attribs.ba) {
|
||||||
|
let ba = decodeList(attribs.ba, true, false);
|
||||||
|
res.rounds[cur_game].draw.honba = ba[0];
|
||||||
|
res.rounds[cur_game].draw.riichi = ba[1];
|
||||||
|
}
|
||||||
|
if (res.rounds[cur_game].draw || res.rounds[cur_game].draw.type === 'nm') {
|
||||||
|
res.rounds[cur_game].draw.tenpai = [];
|
||||||
|
[0, 1, 2, 3].forEach(function(p) {
|
||||||
|
let hand = [];
|
||||||
|
if (attribs['hai' + p]) {
|
||||||
|
hand = Hand(decodeList(attribs['hai' + p], true, true));
|
||||||
|
res.rounds[cur_game].finish[p] = [];
|
||||||
|
}
|
||||||
|
res.rounds[cur_game].draw.tenpai.push(hand);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case /^[t-w]\d+/.test(name):
|
||||||
|
let draw = /^([t-w])(\d+)$/.exec(name);
|
||||||
|
cur_player = ['t', 'u', 'v', 'w'].indexOf(draw[1]);
|
||||||
|
// Проверим тайл замены при кане
|
||||||
|
if (res.rounds[cur_game].events[cur_player][cur_event] &&
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event].call &&
|
||||||
|
(res.rounds[cur_game].events[cur_player][cur_event].call.type === 'kan' ||
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event].call.type === 'chakan')
|
||||||
|
) {
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event].draw = Tile(parseInt(draw[2]));
|
||||||
|
} else {
|
||||||
|
// начало ходов начинаем с дилера
|
||||||
|
if (cur_player === res.rounds[cur_game].diler) cur_event++;
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event] = {
|
||||||
|
draw: Tile(parseInt(draw[2]))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
res.rounds[cur_game].finish[cur_player].push(parseInt(draw[2]));
|
||||||
|
break;
|
||||||
|
case /^[d-g]\d+/.test(name):
|
||||||
|
let discard = /^([d-g])(\d+)$/.exec(name);
|
||||||
|
cur_player = ['d', 'e', 'f', 'g'].indexOf(discard[1]);
|
||||||
|
// Обработка цумогири
|
||||||
|
if (!res.rounds[cur_game].events[cur_player][cur_event].call &&
|
||||||
|
!res.rounds[cur_game].events[cur_player][cur_event].reach &&
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event].draw == Tile(parseInt(discard[2]))) {
|
||||||
|
delete res.rounds[cur_game].events[cur_player][cur_event].draw;
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event].tsumogiri = Tile(parseInt(discard[2]));
|
||||||
|
} else {
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event].discard = Tile(parseInt(discard[2]));
|
||||||
|
}
|
||||||
|
// Уберем из финальной руки выкинутый тайл
|
||||||
|
if (res.rounds[cur_game].finish[cur_player].indexOf(parseInt(discard[2])) >= 0) {
|
||||||
|
res.rounds[cur_game].finish[cur_player].splice(
|
||||||
|
res.rounds[cur_game].finish[cur_player].indexOf(parseInt(discard[2])), 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case /dora/.test(name) && (typeof attribs.hai !== 'undefined'):
|
||||||
|
res.rounds[cur_game].events[cur_player][cur_event].dora = Tile(parseInt(attribs.hai));
|
||||||
|
res.rounds[cur_game].dora.push(Tile(parseInt(attribs.hai)));
|
||||||
|
break;
|
||||||
|
case /n/.test(name) && (typeof attribs.m !== 'undefined'):
|
||||||
|
let meld = parseMeld(attribs.m);
|
||||||
|
meld.player = parseInt(attribs.who);
|
||||||
|
// уберем из финальной руки сет
|
||||||
|
for (var i = 0; i < meld.tiles.length; i++) {
|
||||||
|
if (res.rounds[cur_game].finish[meld.player].indexOf(parseInt(meld.tiles[i])) >= 0) {
|
||||||
|
res.rounds[cur_game].finish[meld.player].splice(
|
||||||
|
res.rounds[cur_game].finish[meld.player].indexOf(parseInt(meld.tiles[i])), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
meld.tiles = Hand(meld.tiles);
|
||||||
|
if (meld.type != 'chakan') {
|
||||||
|
// проверим нужно ли увеличить счетчик хода
|
||||||
|
let tmp_meld = meld.player - res.rounds[cur_game].diler,
|
||||||
|
tmp_player = cur_player - res.rounds[cur_game].diler;
|
||||||
|
tmp_meld = (tmp_meld < 0 ? tmp_meld + 4 : tmp_meld);
|
||||||
|
tmp_player = (tmp_player < 0 ? tmp_player + 4 : tmp_player);
|
||||||
|
if (tmp_meld < tmp_player) {
|
||||||
|
cur_event++;
|
||||||
|
}
|
||||||
|
meld.rotate = (meld.player - cur_player + 4) % 4;
|
||||||
|
if (meld.type === 'pon') {
|
||||||
|
meld.rotate--;
|
||||||
|
} else if (meld.type === 'kan') {
|
||||||
|
meld.rotate = [4, 0, 1, 3][meld.rotate];
|
||||||
|
}
|
||||||
|
res.rounds[cur_game].events[meld.player][cur_event] = {
|
||||||
|
call: meld
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
res.rounds[cur_game].meld[meld.player].forEach(function(item, i) {
|
||||||
|
if (item.type === 'pon' && item.tiles[0] === meld.tiles[0]) {
|
||||||
|
res.rounds[cur_game].meld[meld.player].splice(i, 1);
|
||||||
|
meld.rotate = item.rotate;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res.rounds[cur_game].events[meld.player][cur_event].call = meld;
|
||||||
|
}
|
||||||
|
res.rounds[cur_game].meld[meld.player].push(meld);
|
||||||
|
cur_player = meld.player;
|
||||||
|
break;
|
||||||
|
case /reach/.test(name) && (typeof attribs.step !== 'undefined'):
|
||||||
|
if (attribs.ten && attribs.step == 2) {
|
||||||
|
res.rounds[cur_game].events[attribs.who][cur_event].reach = decodeList(attribs.ten, true, false);
|
||||||
|
res.rounds[cur_game].riichi.player.push(parseInt(attribs.who));
|
||||||
|
} else if (attribs.step == 1) {
|
||||||
|
res.rounds[cur_game].events[attribs.who][cur_event].reach = [];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onclosetag: function(tagname) {
|
||||||
|
if (tagname === 'mjloggm') {
|
||||||
|
res = replaceTiles(res);
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
xmlMode: true,
|
||||||
|
lowerCaseTags: true,
|
||||||
|
lowerCaseAttributeNames: true
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.readFile(file, function(err, data) {
|
||||||
|
if (err) reject(err);
|
||||||
|
parser.write(data);
|
||||||
|
});
|
||||||
|
parser.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function workLog(req, res) {
|
||||||
|
var url = require('url'),
|
||||||
|
qs = require('querystring'),
|
||||||
|
http = require('http'),
|
||||||
|
fs = require('fs'),
|
||||||
|
log, lang, json;
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
var urlobj = url.parse(req.body.url),
|
||||||
|
query = qs.parse(urlobj.query);
|
||||||
|
log = query.log;
|
||||||
|
lang = req.body.lang;
|
||||||
|
json = req.body.json;
|
||||||
|
} else if (req.method === 'GET') {
|
||||||
|
log = req.query.log;
|
||||||
|
lang = req.query.lang;
|
||||||
|
json = req.query.json;
|
||||||
|
}
|
||||||
|
lang = (Object.keys(dict).indexOf(lang) >= 0 ? lang : 'en');
|
||||||
|
if (!log) {
|
||||||
|
res.status(200).send('Нужно передать URL на лог игры!!!');
|
||||||
|
} else {
|
||||||
|
var options = {
|
||||||
|
host: 'e.mjv.jp',
|
||||||
|
//host: 'e0.mjv.jp',
|
||||||
|
port: 80,
|
||||||
|
//followAllRedirects: true,
|
||||||
|
path: '/0/log/plainfiles.cgi?' + log
|
||||||
|
//path: '/0/log/?' + log
|
||||||
|
},
|
||||||
|
logfile = __dirname + '/tenhou/' + log + '.xml';
|
||||||
|
if (!fs.existsSync(logfile)) {
|
||||||
|
http.get(options, function(responce) {
|
||||||
|
var body = '';
|
||||||
|
responce.on('data', function(chunk) {
|
||||||
|
body += chunk;
|
||||||
|
});
|
||||||
|
responce.on('end', function() {
|
||||||
|
let fl = fs.openSync(logfile, 'wx');
|
||||||
|
if (fl) {
|
||||||
|
fs.writeSync(fl, body);
|
||||||
|
fs.closeSync(fl);
|
||||||
|
}
|
||||||
|
if (fs.existsSync(logfile)) {
|
||||||
|
parseLog(log, logfile, lang)
|
||||||
|
.then(
|
||||||
|
result =>
|
||||||
|
(json === 1 ?
|
||||||
|
res.status(200).json(result) : res.render('paifu', {
|
||||||
|
data: result,
|
||||||
|
str: dict[lang],
|
||||||
|
lang: lang
|
||||||
|
})),
|
||||||
|
error => res.status(200).send('Error: ' + error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}).on('error', function(e) {
|
||||||
|
log.error("Got error: " + e.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
parseLog(log, logfile, lang)
|
||||||
|
.then(
|
||||||
|
result => (json == 1 ?
|
||||||
|
res.status(200).json(result) : res.render('paifu', {
|
||||||
|
data: result,
|
||||||
|
str: dict[lang],
|
||||||
|
lang: lang
|
||||||
|
})),
|
||||||
|
//res.status(200).json(result),
|
||||||
|
error => res.status(200).send('Error: ' + error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.index = function(req, res) {
|
||||||
|
if (!req.query.log) {
|
||||||
|
res.render('index', {
|
||||||
|
error: req.flash('error')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
workLog(req, res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.parse = workLog;
|
341
routes/translate.js
Normal file
341
routes/translate.js
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
module.exports = {
|
||||||
|
ru: {
|
||||||
|
title: 'Пайфу',
|
||||||
|
link: 'Прямая ссылка на пайфу',
|
||||||
|
player_info: 'Информация об игроках',
|
||||||
|
name: 'Имя',
|
||||||
|
sex: 'Пол',
|
||||||
|
rate: 'Рейтинг',
|
||||||
|
dan: 'Дан',
|
||||||
|
sexF: 'жен.',
|
||||||
|
sexM: 'муж.',
|
||||||
|
sexC: 'комп',
|
||||||
|
sex_: 'неизв.',
|
||||||
|
log: 'Лог',
|
||||||
|
dans: ['10 кю', '9 кю', '8 кю', '7 кю', '6 кю', '5 кю', '4 кю', '3 кю', '2 кю', '1 кю',
|
||||||
|
'1 дан', '2 дан', '3 дан', '4 дан', '5 дан', '6 дан', '7 дан', '8 дан', '9 дан', '10 дан'
|
||||||
|
],
|
||||||
|
rounds: ['東1', '東2', '東3', '東4', '南1', '南2', '南3', '南4',
|
||||||
|
'西1', '西2', '西3', '西4', '北1', '北2', '北3', '北4'
|
||||||
|
],
|
||||||
|
seat: ['東', '南', '西', '北'],
|
||||||
|
round: 'Раунд',
|
||||||
|
honba: 'Хонба',
|
||||||
|
reach: 'Риичи',
|
||||||
|
dora: 'Дора',
|
||||||
|
urador: 'Урадора',
|
||||||
|
start: 'Старт',
|
||||||
|
draw: 'Взято',
|
||||||
|
discard: 'Сброс',
|
||||||
|
final: 'Финал',
|
||||||
|
pon: 'Пон',
|
||||||
|
chi: 'Чи',
|
||||||
|
kan: 'Кан',
|
||||||
|
chakan: 'Кан',
|
||||||
|
nuki: 'Наки',
|
||||||
|
ron: 'Рон',
|
||||||
|
furikomi: 'Оплата',
|
||||||
|
tsumo: 'Цумо',
|
||||||
|
from: {
|
||||||
|
M: 'выиграл с',
|
||||||
|
F: 'выиграла с',
|
||||||
|
C: 'выиграл с'
|
||||||
|
},
|
||||||
|
han: 'хан',
|
||||||
|
fu: 'фу',
|
||||||
|
score: 'Очков',
|
||||||
|
yakulist: 'Список яку',
|
||||||
|
ryuukyoku: {
|
||||||
|
title: "Ничья",
|
||||||
|
tenpai: "Темпай",
|
||||||
|
noten: "Нотен",
|
||||||
|
yao9: "9 терминалов и благородных",
|
||||||
|
reach4: "Четыре риичи",
|
||||||
|
ron3: "Тройной рон",
|
||||||
|
kan4: "Четыре кана",
|
||||||
|
kaze4: "Четыре ветра в сносе",
|
||||||
|
nm: "Нагаши манган"
|
||||||
|
},
|
||||||
|
limits: ['', 'Манган', 'Ханеман', 'Байман', 'Санбайман', 'Якуман'],
|
||||||
|
yaku: ['Мензенцумо',
|
||||||
|
'Риичи',
|
||||||
|
'Иппацу',
|
||||||
|
'Чанкан',
|
||||||
|
'Риншан кайхо',
|
||||||
|
'Хайтей',
|
||||||
|
'Хотей',
|
||||||
|
'Пинфу',
|
||||||
|
'Тан-яо',
|
||||||
|
'Иипейко',
|
||||||
|
'Свой восток',
|
||||||
|
'Свой юг',
|
||||||
|
'Свой запад',
|
||||||
|
'Свой север',
|
||||||
|
'Восток раунда',
|
||||||
|
'Юг раунда',
|
||||||
|
'Запад раунда',
|
||||||
|
'Север раунда',
|
||||||
|
'Белый дракон',
|
||||||
|
'Зеленый дракон',
|
||||||
|
'Красный дракон',
|
||||||
|
'Дабл-риичи',
|
||||||
|
'Чиитойцу',
|
||||||
|
'Чанта',
|
||||||
|
'Иццу',
|
||||||
|
'Саншоку',
|
||||||
|
'Саншоку доко',
|
||||||
|
'Сууканцу',
|
||||||
|
'Тойтой',
|
||||||
|
'Сананко',
|
||||||
|
'Шосанген',
|
||||||
|
'Хонрото',
|
||||||
|
'Рянпейко',
|
||||||
|
'Джунчан',
|
||||||
|
'Хоницу',
|
||||||
|
'Чиницу',
|
||||||
|
'Ренхо',
|
||||||
|
'Тенхо',
|
||||||
|
'Чихо',
|
||||||
|
'Дайсанген',
|
||||||
|
'Сууанко',
|
||||||
|
'Сууанко танки',
|
||||||
|
'Цууисо',
|
||||||
|
'Рюисо',
|
||||||
|
'Чинрото',
|
||||||
|
'Чууренпото',
|
||||||
|
'Чууренпото 9-стор',
|
||||||
|
'Кокушимусо',
|
||||||
|
'Кокушимусо 13-стор',
|
||||||
|
'Дайсууши',
|
||||||
|
'Шосууши',
|
||||||
|
'Санканцу',
|
||||||
|
'Дора',
|
||||||
|
'Урадора',
|
||||||
|
'Акадора'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
title: 'Paifu',
|
||||||
|
link: 'Direct paifu link',
|
||||||
|
player_info: 'Player information',
|
||||||
|
name: 'Name',
|
||||||
|
sex: 'Sex',
|
||||||
|
rate: 'Rating',
|
||||||
|
dan: 'Dan',
|
||||||
|
sexF: 'female',
|
||||||
|
sexM: 'male',
|
||||||
|
sexC: 'comp',
|
||||||
|
sex_: 'NA',
|
||||||
|
log: 'Log',
|
||||||
|
dans: ['10 kyuu', '9 kyuu', '8 kyuu', '7 kyuu', '6 kyuu', '5 kyuu', '4 kyuu', '3 kyuu', '2 kyuu', '1 kyuu',
|
||||||
|
'1 dan', '2 dan', '3 dan', '4 dan', '5 dan', '6 dan', '7 dan', '8 dan', '9 dan', '10 dan'
|
||||||
|
],
|
||||||
|
rounds: ['東1', '東2', '東3', '東4', '南1', '南2', '南3', '南4',
|
||||||
|
'西1', '西2', '西3', '西4', '北1', '北2', '北3', '北4'
|
||||||
|
],
|
||||||
|
seat: ['東', '南', '西', '北'],
|
||||||
|
round: 'Round',
|
||||||
|
honba: 'Combo',
|
||||||
|
reach: 'Reach',
|
||||||
|
dora: 'Dora',
|
||||||
|
urador: 'Uradora',
|
||||||
|
start: 'Start',
|
||||||
|
draw: 'Draw',
|
||||||
|
discard: 'Drop',
|
||||||
|
final: 'Final',
|
||||||
|
pon: 'Pon',
|
||||||
|
chi: 'Chii',
|
||||||
|
kan: 'Kan',
|
||||||
|
chakan: 'Kan',
|
||||||
|
nuki: 'Nuki',
|
||||||
|
ron: 'Ron',
|
||||||
|
furikomi: 'Furikomi',
|
||||||
|
tsumo: 'Tsumo',
|
||||||
|
from: {
|
||||||
|
M: 'win from',
|
||||||
|
F: 'win from',
|
||||||
|
C: 'win from'
|
||||||
|
},
|
||||||
|
han: 'han',
|
||||||
|
fu: 'fu',
|
||||||
|
score: 'Score',
|
||||||
|
yakulist: 'Yaku list',
|
||||||
|
ryuukyoku: {
|
||||||
|
yao9: "9 ends",
|
||||||
|
reach4: "Four riichi",
|
||||||
|
ron3: "Triple ron",
|
||||||
|
kan4: "Four kans",
|
||||||
|
kaze4: "Wind discard",
|
||||||
|
nm: "Nagashi mangan"
|
||||||
|
},
|
||||||
|
limits: ['', 'Mangan', 'haneman', 'baiman', 'sanbaiman', 'yakuman'],
|
||||||
|
yaku: ['Mentsumo',
|
||||||
|
'Riichi',
|
||||||
|
'Ippatsu',
|
||||||
|
'Chankan',
|
||||||
|
'Rinshan kaihou',
|
||||||
|
'Haitei raoyue',
|
||||||
|
'Houtei raoyui',
|
||||||
|
'Pinfu',
|
||||||
|
'Tanyao',
|
||||||
|
'Iipeiko',
|
||||||
|
'Own east',
|
||||||
|
'Own south',
|
||||||
|
'Own west',
|
||||||
|
'Own north',
|
||||||
|
'Round east',
|
||||||
|
'Round south',
|
||||||
|
'Round west',
|
||||||
|
'Round north',
|
||||||
|
'White dragon',
|
||||||
|
'Green dragon',
|
||||||
|
'Red dragon',
|
||||||
|
'Daburu riichi',
|
||||||
|
'Chiitoitsu',
|
||||||
|
'Chanta',
|
||||||
|
'Ittsu',
|
||||||
|
'Sanshoku doujun',
|
||||||
|
'Sanshoku doukou',
|
||||||
|
'Sankantsu',
|
||||||
|
'Toitoi',
|
||||||
|
'Sanankou',
|
||||||
|
'Shousangen',
|
||||||
|
'Honroutou',
|
||||||
|
'Ryanpeikou',
|
||||||
|
'Junchan',
|
||||||
|
'Honitsu',
|
||||||
|
'Chinitsu',
|
||||||
|
'Renhou',
|
||||||
|
'Tenhou',
|
||||||
|
'Chihou',
|
||||||
|
'Daisangen',
|
||||||
|
'Suuankou',
|
||||||
|
'Suuankou tanki',
|
||||||
|
'Tsuuiisou',
|
||||||
|
'Ryuuiisou',
|
||||||
|
'Chinroutou',
|
||||||
|
'Chuuren pouto',
|
||||||
|
'Chuuren pouto 9-wait',
|
||||||
|
'Kokushi musou',
|
||||||
|
'Kokushi musou 13-wait',
|
||||||
|
'Daisuushi',
|
||||||
|
'Shousuushi',
|
||||||
|
'Suukantsu',
|
||||||
|
'Dora',
|
||||||
|
'Uradora',
|
||||||
|
'Akadora'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
jp: {
|
||||||
|
title: 'Paifu',
|
||||||
|
link: 'Direct paifu link',
|
||||||
|
player_info: 'Player information',
|
||||||
|
name: 'Name',
|
||||||
|
sex: 'Sex',
|
||||||
|
rate: 'Rating',
|
||||||
|
dan: 'Dan',
|
||||||
|
sexF: 'famale',
|
||||||
|
sexM: 'male',
|
||||||
|
sexC: 'comp',
|
||||||
|
sex_: 'NA',
|
||||||
|
log: 'Log',
|
||||||
|
dans: ['新人', '9級', '8級', '7級', '6級', '5級', '4級', '3級', '2級', '1級',
|
||||||
|
'初段', '二段', '三段', '四段', '五段', '六段', '七段', '八段', '九段', '十段', '天鳳位'
|
||||||
|
],
|
||||||
|
rounds: ['東1', '東2', '東3', '東4', '南1', '南2', '南3', '南4',
|
||||||
|
'西1', '西2', '西3', '西4', '北1', '北2', '北3', '北4'
|
||||||
|
],
|
||||||
|
seat: ['東', '南', '西', '北'],
|
||||||
|
round: 'Round',
|
||||||
|
honba: 'Combo',
|
||||||
|
reach: 'Reach',
|
||||||
|
dora: 'Dora',
|
||||||
|
urador: 'Uradora',
|
||||||
|
start: 'Start',
|
||||||
|
draw: 'Draw',
|
||||||
|
discard: 'Drop',
|
||||||
|
final: 'Final',
|
||||||
|
pon: 'Pon',
|
||||||
|
chi: 'Chii',
|
||||||
|
kan: 'Kan',
|
||||||
|
chakan: 'Kan',
|
||||||
|
nuki: 'Nuki',
|
||||||
|
ron: 'Ron',
|
||||||
|
furikomi: 'フリコミ',
|
||||||
|
tsumo: 'ツモ',
|
||||||
|
from: {
|
||||||
|
M: 'win from',
|
||||||
|
F: 'win from',
|
||||||
|
C: 'win from'
|
||||||
|
},
|
||||||
|
han: 'han',
|
||||||
|
fu: 'fu',
|
||||||
|
score: 'Score',
|
||||||
|
yakulist: 'Yaku list',
|
||||||
|
ryuukyoku: {
|
||||||
|
yao9: "9 ends",
|
||||||
|
reach4: "Four riichi",
|
||||||
|
ron3: "Triple ron",
|
||||||
|
kan4: "Four kans",
|
||||||
|
kaze4: "Wind discard",
|
||||||
|
nm: "Nagashi mangan"
|
||||||
|
},
|
||||||
|
limits: ['', 'Mangan', 'haneman', 'baiman', 'sanbaiman', 'yakuman'],
|
||||||
|
yaku: ['門前清自摸和',
|
||||||
|
'立直',
|
||||||
|
'一発',
|
||||||
|
'槍槓',
|
||||||
|
'嶺上開花',
|
||||||
|
'海底摸月',
|
||||||
|
'河底撈魚',
|
||||||
|
'平和',
|
||||||
|
'断幺九',
|
||||||
|
'一盃口',
|
||||||
|
'自風 東',
|
||||||
|
'自風 南',
|
||||||
|
'自風 西',
|
||||||
|
'自風 北',
|
||||||
|
'場風 東',
|
||||||
|
'場風 南',
|
||||||
|
'場風 西',
|
||||||
|
'場風 北',
|
||||||
|
'役牌 白',
|
||||||
|
'役牌 發',
|
||||||
|
'役牌 中',
|
||||||
|
'両立直',
|
||||||
|
'七対子',
|
||||||
|
'混全帯幺九',
|
||||||
|
'一気通貫',
|
||||||
|
'三色同順',
|
||||||
|
'三色同刻',
|
||||||
|
'三槓子',
|
||||||
|
'対々和',
|
||||||
|
'三暗刻',
|
||||||
|
'小三元',
|
||||||
|
'混老頭',
|
||||||
|
'二盃口',
|
||||||
|
'純全帯幺九',
|
||||||
|
'混一色',
|
||||||
|
'清一色',
|
||||||
|
'人和',
|
||||||
|
'天和',
|
||||||
|
'地和',
|
||||||
|
'大三元',
|
||||||
|
'四暗刻',
|
||||||
|
'四暗刻単騎',
|
||||||
|
'字一色',
|
||||||
|
'緑一色',
|
||||||
|
'清老頭',
|
||||||
|
'九蓮宝燈',
|
||||||
|
'純正九蓮宝燈',
|
||||||
|
'国士無双',
|
||||||
|
'国士無双13面',
|
||||||
|
'大四喜',
|
||||||
|
'小四喜',
|
||||||
|
'四槓子',
|
||||||
|
'ドラ',
|
||||||
|
'裏ドラ',
|
||||||
|
'赤ドラ]'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user