検索条件
全32件
(1/7ページ)
【東北楽天 vs 埼玉西武 第3回戦】 (2024年03月31日/楽天モバイルパーク宮城) 埼玉西武 0 0 3 0 0 0 0 0 0 0 0 3 東北楽天 0 0 3 0 0 0 0 0 0 0 1x 4 [勝] 渡辺翔 1勝0敗0S [敗] 糸川 0勝1敗0S今年もラブライブ!コラボが発表されました 。
【東北楽天 vs 埼玉西武 第2回戦】 (2024年03月30日/楽天モバイルパーク宮城) 埼玉西武 1 0 3 1 0 0 0 1 2 8 東北楽天 0 2 0 0 0 0 0 0 0 2 [勝] 隅田 1勝0敗0S [敗] 荘司 0勝1敗0S [本塁打] 4回表 古賀 1号 ソロ (荘司)ライオンズ先発の隅田は立ち上がりからピリッとしませんでした。初回は2アウト満塁のピンチをしのぎましたが、2回には太田と阿部のタイムリーで2点を失い逆転を許します。しかし、その後はどうにか踏ん張って5回2/3を2失点。ストレートの制球に苦しんでいたせいもあるのでしょうが、変化球頼みの苦しいピッチングでしたが、それでもゲームは作ってくれました。
const NAMEPREF = 1
を const NAMEPREF = 0
に書き換えてください。//
を追加する)し、37~40行目のうち対象の行(たとえば、頂上決戦でない半荘戦は37行目)をアンコメント(行頭の //
を削除する)すると、魂珠の増減数を解析できます。// Copyright 2021-2024 HASEBA Junya // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ==UserScript== // @name soul2naga // @namespace lions.blue // @icon http://1.gravatar.com/avatar/6fa3836d10d691125749472297cf516a // @version 2.0.0 // @description downloadlogsで保存する牌譜をNAGAで解析可能な形式に変換する。 // @include https://mahjongsoul.game.yo-star.com/* // @include https://game.mahjongsoul.com/* // @include https://majsoul.union-game.com/0/* // ==/UserScript== (function() { /** * @type {string} 順位点配分・素点倍率を固定値で指定する際のパラメーター。 * * nullを指定した場合は、段位と卓のレベルに応じた順位点配分・素点倍率を使用する。 * このとき、パラメーターの都合上、魂天は雀聖3として扱う。 * * パラメーターの記述ルールは公式の説明( https://twitter.com/NAGA025/status/1768508358179615190 )を参照のこと。 * 魂天視点で解析する場合は、36行目をコメントアウトし、37~40行目の該当行を有効化すると魂珠の増減数がパラメーターになる。 */ const CUSTOM_PARAMETER = null; // const CUSTOM_PARAMETER = "[0.5, 0.2, -0.2, -0.5], [0.5, 0.2, -0.2, -0.5], [0.5, 0.2, -0.2, -0.5], [0.5, 0.2, -0.2, -0.5], 0"; // 魂天・半荘の場合 // const CUSTOM_PARAMETER = "[1.0, 0.4, -0.4, -1.0], [1.0, 0.4, -0.4, -1.0], [1.0, 0.4, -0.4, -1.0], [1.0, 0.4, -0.4, -1.0], 0"; // 魂天・半荘・頂上決戦の場合 // const CUSTOM_PARAMETER = "[0.3, 0.1, -0.1, -0.3], [0.3, 0.1, -0.1, -0.3], [0.3, 0.1, -0.1, -0.3], [0.3, 0.1, -0.1, -0.3], 0"; // 魂天・東風の場合 // const CUSTOM_PARAMETER = "[0.6, 0.2, -0.2, -0.6], [0.6, 0.2, -0.2, -0.6], [0.6, 0.2, -0.2, -0.6], [0.6, 0.2, -0.2, -0.6], 0"; // 魂天・東風・頂上決戦の場合 /** @type {string} ダウンロードリンクのhref属性において、牌譜データに先行する部分の文字列。 */ const DOWNLOAD_HREF_PREFIX = "data:text/plain;charset=utf-8,"; /** @type {string} 天鳳牌譜エディタのURLにおいて、牌譜データに先行する部分の文字列。 */ const EDITOR_URL_PREFIX = "https://tenhou.net/6/#json="; // ダウンロードイベントの前に割り込んで牌譜データを書き換える。 document.addEventListener("click", function(e) { const links = document.body.getElementsByTagName("a"); for (let i = 0; i < links.length; i++) { if (isDownloadLink(links[i])) { const soulJson = fetchSoulJson(links[i]); const urls = convertToViewerUrls(soulJson); links[i].href = buildDownloadHref(urls); links[i].download = buildFileName(links[i].download); break; } } }, {capture: true}); /** * ダウンロードリンクか否かを判定する。 * * @param {HTMLElement} element 判定対象の要素を指定する。 * @returns {boolean} ダウンロードリンクの場合はtrue、それ以外の場合はfalseを返す。 */ function isDownloadLink(element) { // href属性の先頭部分で判定する。 return element.href.startsWith(DOWNLOAD_HREF_PREFIX); } /** * ダウンロードリンクから雀魂の牌譜JSONを抽出する。 * * @param {HTMLElement} element ダウンロードリンクを指定する。 * @returns {string} 雀魂の牌譜JSONを返す。 */ function fetchSoulJson(element) { // href属性から牌譜JSONを抽出する。 return decodeURIComponent(element.href.replace(DOWNLOAD_HREF_PREFIX, "")); } /** * 雀魂の牌譜JSONを牌譜エディタのURL群に変換する。 * * @param {string} soulJson 雀魂の牌譜JSONを指定する。 * @returns {Array<string>} 牌譜エディタのURL群を返す。 */ function convertToViewerUrls(soulJson) { // 雀魂の牌譜JSONをオブジェクトに変換する。 const soulPaifu = JSON.parse(soulJson); // title内の卓名を雀魂っぽく変換し、順位点配分・素点倍率を付与する。 const title = structuredClone(soulPaifu.title); title[0] = toSoulRoom(title[0]); title[1] = buildPtEVParameter(title[0], soulPaifu.dan); // プレイヤー名をエンコードする。 const name = structuredClone(soulPaifu.name); const encodedName = name.map(function(v) { return encodeURIComponent(v); }); // rule内の卓名を雀魂っぽく変換する。 // // 変換前のrule: // "rule": { "disp": "玉の間南喰赤", "aka53": 1, "aka52": 1, "aka51": 1 } // 変換後のrule: // "rule": { "disp": "玉の間四人南", "aka53": 1, "aka52": 1, "aka51": 1 } const rule = structuredClone(soulPaifu.rule); rule.disp = toSoulRoom(rule.disp); // logを局ごとのデータに分割し、牌譜エディタのURL群として返す。 return soulPaifu.log.map(function(v) { return EDITOR_URL_PREFIX + JSON.stringify({ "title": title, "name": encodedName, "rule": rule, "log": [toNagaLog(v)], }); }); } /** * 卓名を雀魂っぽく変換する。 * * @param {string} tenhouRoom 天鳳っぽい卓名を指定する。 * @returns {string} 雀魂っぽい卓名を返す。 */ function toSoulRoom(tenhouRoom) { // 卓名を雀魂っぽく変換する。 // // 半荘: ○の間四人南 // 東風: ○の間四人東 return tenhouRoom.replace(/(.)喰赤/, "四人$1"); } /** * 順位点配分・素点倍率を組み立てる。 * * @param {string} room 卓名を指定する。 * @param {Array<string>} dan プレイヤーの段位を指定する。 * @returns {string} 順位点配分・素点倍率を返す。 */ function buildPtEVParameter(room, dan) { // カスタムパラメーターが指定されている場合はそのまま利用する。 if (CUSTOM_PARAMETER !== null) { return CUSTOM_PARAMETER; } // 順位点配分・素点倍率を組み立てる。 const pointTable = fetchPointTable(room); if (pointTable !== null) { return JSON.stringify(dan.map(function(v) { const rank = v.startsWith("魂天") ? "雀聖★3" : v; return pointTable[0].concat(pointTable[1][rank]); }).concat(1)).match(/^\[(.+)\]$/)[1]; } else { return ""; } } /** * 卓に応じた順位点配分テーブルを取得する。 * * @param {string} room 卓名を指定する。 * @returns {Array<Array<number>, object>} 順位配分点テーブルを返す。 */ function fetchPointTable(room) { // 卓に応じた順位点配分テーブルを返す。 // // 参考URL: // https://mahjongsoul.info/how_to_enjoy1/ switch (room) { case "銅の間四人南": return [ [35, 15, -5], { "初心★1": -15, "初心★2": -15, "初心★3": -15, "雀士★1": -35, "雀士★2": -55, "雀士★3": -75, }, ]; case "銀の間四人南": return [ [55, 25, -5], { "雀士★1": -35, "雀士★2": -55, "雀士★3": -75, "雀傑★1": -95, "雀傑★2": -115, "雀傑★3": -135, }, ]; case "金の間四人南": return [ [95, 45, -5], { "雀傑★1": -95, "雀傑★2": -115, "雀傑★3": -135, "雀豪★1": -180, "雀豪★2": -195, "雀豪★3": -210, }, ] case "玉の間四人南": return [ [125, 60, -5], { "雀豪★1": -180, "雀豪★2": -195, "雀豪★3": -210, "雀聖★1": -225, "雀聖★2": -240, "雀聖★3": -255, }, ]; case "王座の間四人南": return [ [135, 65, -5], { "雀聖★1": -225, "雀聖★2": -240, "雀聖★3": -255, }, ]; case "銅の間四人東": return [ [25, 10, -5], { "初心★1": -15, "初心★2": -15, "初心★3": -15, "雀士★1": -25, "雀士★2": -35, "雀士★3": -45, }, ]; case "銀の間四人東": return [ [35, 15, -5], { "雀士★1": -25, "雀士★2": -35, "雀士★3": -45, "雀傑★1": -55, "雀傑★2": -65, "雀傑★3": -75, }, ]; case "金の間四人東": return [ [55, 25, -5], { "雀傑★1": -55, "雀傑★2": -65, "雀傑★3": -75, "雀豪★1": -95, "雀豪★2": -105, "雀豪★3": -115, }, ]; case "玉の間四人東": return [ [70, 35, -5], { "雀豪★1": -95, "雀豪★2": -105, "雀豪★3": -115, "雀聖★1": -125, "雀聖★2": -135, "雀聖★3": -145, }, ]; case "王座の間四人東": return [ [75, 35, -5], { "雀聖★1": -125, "雀聖★2": -135, "雀聖★3": -145, }, ]; default: return null; } } /** * logをNAGAが解析可能な形式に変換する。 * * @param {Array<Array>} soulLog 雀魂形式のlogを指定する。 * @returns {Array<Array>} NAGAで解析可能な形式のlogを返す。 */ function toNagaLog(soulLog) { // 流局のデータは変換する必要はない。 if (soulLog[16].length < 3) { return soulLog; } const nagaLog = structuredClone(soulLog); // 当該局の場風牌を算出する。 // // 数字と局の対応: // 0 => 東1局, 1 => 東2局, ... const prevalentWind = ["東", "南", "西", "北"][Math.floor(nagaLog[0][0] / 4)]; // 役名をNAGAが解析可能な表記に変換する。 // ダブロン・トリロンに対応するため複数回繰り返す。 for (let i = 1; i < nagaLog[16].length; i += 2) { // 和了者の自風牌を算出する。 // // 算出方法: // (和了者のプレイヤー番号 - 親の位置 + 4) % 4 const seatWind = ["東", "南", "西", "北"][ (nagaLog[16][i].indexOf(Math.max(...nagaLog[16][i])) - (nagaLog[0][0] % 4) + 4) % 4 ]; // 役名をNAGAが解析可能な表記に変換する。 nagaLog[16][i + 1] = nagaLog[16][i + 1].slice(0, 4).concat( nagaLog[16][i + 1].slice(4).map(function(v) { return toNagaHand(v, prevalentWind, seatWind); } )); } // 変換後のlogを返す。 return nagaLog; } /** * 役名をNAGAが解析可能な表記に変換する。 * * @param {string} hand 和了役を指定する。 * @param {string} prevalentWind 場風牌を指定する。 * @param {string} seatWind 和了者の自風牌を指定する。 * @returns {string} NAGAで解析可能な表記の役名を返す。 */ function toNagaHand(hand, prevalentWind, seatWind) { // 対応が必要な役が判明次第、随時追加する。 switch(hand) { case "役牌:場風牌(1飜)": return `場風 ${prevalentWind}(1飜)`; case "役牌:自風牌(1飜)": return `自風 ${seatWind}(1飜)`; case "ダブル立直(2飜)": return "両立直(2飜)"; default: return hand; } } /** * ダウンロードリンクのhref属性を組み立てる。 * * @param {Array<string>} urls 牌譜エディタのURL群を指定する。 * @returns {string} ダウンロードリンクのhref属性を返す。 */ function buildDownloadHref(urls) { // ダウンロードリンクのhref属性を組み立てる。 return DOWNLOAD_HREF_PREFIX + encodeURIComponent(urls.join("\n")); } /** * ダウンロードファイル名を組み立てる。 * * @param {string} baseFileName もとのダウンロードファイル名を指定する。 * @returns {string} 組み立てたダウンロードファイル名を返す。 */ function buildFileName(baseFileName) { // 卓名を雀魂っぽく変換し、拡張子を.txtに変更する。 return toSoulRoom(baseFileName).replace(".json", ".txt"); } })();
S
キーを押してください。設定が正しく行われていれば、牌譜エディタのURLが並んだテキストファイルをダウンロードできるはずです。【東北楽天 vs 埼玉西武 第1回戦】 (2024年03月29日/楽天モバイルパーク宮城) 埼玉西武 0 0 0 0 0 0 0 1 0 1 東北楽天 0 0 0 0 0 0 0 0 0 0 [勝] 今井 1勝0敗0S [S] アブレイユ 0勝0敗1S [敗] 早川 0勝1敗0S2024年の開幕戦を白星で飾りました。
順位 | チーム |
---|---|
1 | オリックスバファローズ |
2 | 埼玉西武ライオンズ |
3 | 千葉ロッテマリーンズ |
4 | 福岡ソフトバンクホークス |
5 | 北海道日本ハムファイターズ |
6 | 東北楽天ゴールデンイーグルス |