将棋ウォーズの棋譜を取ってくる

f:id:komori_pyon:20200118223238j:plain

あけましておめでとうございます。 2020年の目標は12月まで生存することです。 よろしくお願いいたします。

さて、2020年1月16日にスタイリッシュ・タップ・アクションゲームこと将棋ウォーズのアップデートがありました。

アップデートにより観戦画面の見た目が変わり、 「ぴよ将棋」等でURLを指定した棋譜の取り込みができなくなってしまいました。 これでは日々の対局の振り返りを手軽に行えず、非常に困ります。

そこで、対局URLから棋譜を取り出す自分専用botを作りました。

本記事は、ネットの情報を寄せ集めただけのポエム的な生存報告です。 技術的な詳細を知りたい方は参考にしたリンク先を御覧ください。

概要

今回作ったシステムのデータの流れを雑に示すと以下のようになります。

f:id:komori_pyon:20200118222542p:plain

LINE bot棋譜URLを投げるとサーバ上でpythonスクリプトが走って、棋譜が返ってきます。

LINE bot

下記のサイトを丸パクリ参考にして、まずはLINEに投げた文章をそのまま返すbotを作りました。

Python + HerokuでLINE BOTを作ってみた - Qiita

ほぼ参考サイトの通りにコマンドを打ち込むだけでbotの動作までたどり着きました。

棋譜のパース

観戦URLで取ってきたhtmlには CSA形式っぽいjsonが埋め込まれています。 このjsonから必要なデータを取り出すことで棋譜データを作れます。

import requests
import json
from bs4 import BeautifulSoup

INIT_BOARD = """\
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI *  *  *  *  * -KA * 
P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
P4 *  *  *  *  *  *  *  *  * 
P5 *  *  *  *  *  *  *  *  * 
P6 *  *  *  *  *  *  *  *  * 
P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
P8 * +KA *  *  *  *  * +HI * 
P9+KY+KE+GI+KI+OU+KI+GI+KE+KY"""

def decode(url):
    res = requests.get(url)
    soup = BeautifulSoup(res.text, "html.parser")
    data = soup.find("div", attrs={"data-react-class": "games/Show"})
    game = json.loads(data["data-react-props"])["gameHash"]

    csatexts = ["V2.2"]
    csatexts.append("N+{}".format(game["sente"]))
    csatexts.append("N-{}".format(game["gote"]))
    csatexts.append("$EVENT:{}".format(game["name"]))
    csatexts.append(INIT_BOARD)
    csatexts.append("+")

    t = [180, 180]
    for i, move in enumerate(game["moves"]):
        csatexts.append(move["m"])

        elapsed = t[i % 2] - move["t"]
        t[i % 2] = move["t"]
        csatexts.append("T{}".format(elapsed))
    
    return "\n".join(csatexts)

上で作ったオウム返しbotを少し書き換えて、観戦URLをスクレイピングしてCSA形式に変換するスクリプトを書きました。

完成品

難しいところがほとんどないため説明をすっ飛ばしましたが、最終的に以下のようなbotができました。

f:id:komori_pyon:20200118222541j:plain

botからの返信をshogidroidやぴよ将棋に貼り付けることで、お好みのソフトで感想戦ができます。