幽玄の間の棋譜をワンタッチでLizzieへ の記事で紹介した yg2lz は Python で書いています。

幽玄の間のNGFファイルをLizzie用のSGFファイルに変換するのに日本棋院の棋院エディタを使っています。Python で直接変換するコードを書いてしまったほうが早いようなことなのですが、これは、python にいろいろな仕事をさせるときの練習として、他のソフトの自動操縦をやっていようと思ったからなんですね。

以下にソースと、Windows用の実行ファイルの作り方をかかげます。
(面倒くさいからもう出来上がってるものがほしいという方は前の記事の最後を御覧くださいね)

yg2lz.py プログラムのソース

import json
import os
import sys
import subprocess
import win32gui
import win32con
import win32api
import time
from tkinter import Tk,messagebox

def main():
    root = Tk()
    root.withdraw()
    hwndLizzie = win32gui.FindWindow("SunAwtFrame",None)
    text = win32gui.GetWindowText(hwndLizzie)
    if not text.startswith("Lizzie"):
        messagebox.showerror("エラー","Lizzieが起動していません")
        sys.exit()

    try:
        f = open("yg2lz.cfg", 'r')
    except:
        messagebox.showerror("Error","設定ファイルyg2lz.cfgが読み込めません")
        sys.exit()
    try:
        cfg = json.load(f)
    except:
        messagebox.showerror("Error","設定ファイルyg2lz.cfgの書式が正しくありません")
        sys.exit()

    NgfDir = cfg["NgfDir"]
    KiinEditor = cfg["KiinEditor"]
    newfile = ""
    newtime = 0
    try:
        for filename in os.listdir(NgfDir):
            filetime = os.path.getctime(
                os.path.join(NgfDir,filename)
            )
            if(filetime > newtime):
                newtime=filetime
                newfile = filename
    except:
        messagebox.showerror("Error","幽玄の間の棋譜ファイルが読み込めません")
        sys.exit()
    
    
    NgfFile = newfile
    KiinEditorTitle = NgfFile + " - Kiin Editor"
    cmd = KiinEditor + " " + NgfDir + "\\" + NgfFile
    try:
        subprocess.Popen(cmd)
    except:
        messagebox.showerror("Error",cmd + "の起動に失敗しました")
        sys.exit()
    
    hwndKiin = win32gui.FindWindow(None,KiinEditorTitle)
    waitcount = 0
    while(hwndKiin==0):
        time.sleep(1)
        hwndKiin = win32gui.FindWindow(None,KiinEditorTitle)
        waitcount+=1
        if(waitcount>10):
            messagebox.showerror("Error","棋院エディタの起動ができませんでした")
            sys.exit()

    win32gui.SetForegroundWindow(hwndKiin)
    win32api.keybd_event(win32con.VK_CONTROL,0,0,0)
    win32api.keybd_event(ord('C'),0,0,0)
    win32api.keybd_event(ord('C'),0,win32con.KEYEVENTF_KEYUP,0)
    win32api.keybd_event(win32con.VK_CONTROL,0,win32con.KEYEVENTF_KEYUP,0)
    time.sleep(1)
    win32gui.SendMessage(hwndKiin,win32con.WM_CLOSE,0,0)

    win32gui.SetForegroundWindow(hwndLizzie)
    win32api.keybd_event(win32con.VK_CONTROL,0,0,0)
    win32api.keybd_event(ord('V'),0,0,0)
    win32api.keybd_event(ord('V'),0,win32con.KEYEVENTF_KEYUP,0)
    win32api.keybd_event(win32con.VK_CONTROL,0,win32con.KEYEVENTF_KEYUP,0)
    

    win32api.keybd_event(win32con.VK_END,0,0,0)
    win32api.keybd_event(win32con.VK_END,0,win32con.KEYEVENTF_KEYUP,0)

    
if __name__ == '__main__':
    main()

ざっくり解説します。さすがに Python の文法までは解説しきれないので興味のある方は勉強してください。

    root = Tk()
    root.withdraw()

これは messagebox を使うためのおまじないです。

    hwndLizzie = win32gui.FindWindow("SunAwtFrame",None)
    text = win32gui.GetWindowText(hwndLizzie)
    if not text.startswith("Lizzie"):
        messagebox.showerror("エラー","Lizzieが起動していません")
        sys.exit()

Lizzie が起動しているか調べるのに FindWindow とか GetWindowText など Windows の API をいろいろ利用して、Java で動いてるウィンドウを探して、そのタイトルが Lizzie で始まってるかどうかをみてます。
実は Lizzie 以外にも Java のプログラムが起動してるとまずいんですが(汗)、そんなことはあまりないだろうと正直ちょっと手抜きしてます。

    try:
        f = open("yg2lz.cfg", 'r')
    except:
        messagebox.showerror("Error","設定ファイルyg2lz.cfgが読み込めません")
        sys.exit()
    try:
        cfg = json.load(f)
    except:
        messagebox.showerror("Error","設定ファイルyg2lz.cfgの書式が正しくありません")
        sys.exit()

    NgfDir = cfg["NgfDir"]
    KiinEditor = cfg["KiinEditor"]

設定ファイル yg2lz.cfg (JSON形式です)から、幽玄の間の棋譜ファイル保存フォルダと、棋院エディタがどこにあるかを読み込んでます。

yg2lz.cfg

{
    "NgfDir":"C:\\Program Files (x86)\\Nihonkiin\\Kifu",
    "KiinEditor":"C:\\Program Files (x86)\\Kiin\\KiinEditor\\KiinEditor.exe"
}

    newfile = ""
    newtime = 0
    try:
        for filename in os.listdir(NgfDir):
            filetime = os.path.getctime(
                os.path.join(NgfDir,filename)
            )
            if(filetime > newtime):
                newtime=filetime
                newfile = filename
    except:
        messagebox.showerror("Error","幽玄の間の棋譜ファイルが読み込めません")
        sys.exit()

幽玄の間の棋譜フォルダにある最新のファイルを、ファイル1つ1つのタイムスタンプを比較しながら探しています。
(もっとスマートな方法がありそうな気はします)

    NgfFile = newfile
    KiinEditorTitle = NgfFile + " - Kiin Editor"
    cmd = KiinEditor + " " + NgfDir + "\\" + NgfFile
    try:
        subprocess.Popen(cmd)
    except:
        messagebox.showerror("Error",cmd + "の起動に失敗しました")
        sys.exit()

幽玄の間の最新棋譜ファイルを棋譜エディタで読み込ませて起動します。
また起動後、棋譜エディタのウィンドウを探すのに必要なタイトルテキストを設定しておきます。

    hwndKiin = win32gui.FindWindow(None,KiinEditorTitle)
    waitcount = 0
    while(hwndKiin==0):
        time.sleep(1)
        hwndKiin = win32gui.FindWindow(None,KiinEditorTitle)
        waitcount+=1
        if(waitcount>10):
            messagebox.showerror("Error","棋院エディタの起動ができませんでした")
            sys.exit()

棋院エディタのウィンドウを探してます。起動に時間がかかるかもしれないので、1秒おきにチェックしてます。10秒まってだめならあきらめる。

    win32gui.SetForegroundWindow(hwndKiin)
    win32api.keybd_event(win32con.VK_CONTROL,0,0,0)
    win32api.keybd_event(ord('C'),0,0,0)
    win32api.keybd_event(ord('C'),0,win32con.KEYEVENTF_KEYUP,0)
    win32api.keybd_event(win32con.VK_CONTROL,0,win32con.KEYEVENTF_KEYUP,0)
    time.sleep(1)
    win32gui.SendMessage(hwndKiin,win32con.WM_CLOSE,0,0)

棋院エディタの操作です。ウィンドウを前面にもってきて Ctrl-C で棋譜をクリップボードにコピーして、棋院エディタを閉じています。
Ctrl-C を動作させるのにいろいろ試行錯誤しました。正直よくわかってません。

    win32gui.SetForegroundWindow(hwndLizzie)
    win32api.keybd_event(win32con.VK_CONTROL,0,0,0)
    win32api.keybd_event(ord('V'),0,0,0)
    win32api.keybd_event(ord('V'),0,win32con.KEYEVENTF_KEYUP,0)
    win32api.keybd_event(win32con.VK_CONTROL,0,win32con.KEYEVENTF_KEYUP,0)

Lizzieの操作です。ウィンドウを前面にもってきて、Ctrl-V で棋譜を貼り付けて、End キーで最終局面に移動しています。

ざっと以上です。

WindowsのAPIについては、昔、Windowsソフトの開発をしていたので土地勘があって助かりました。

Python はいろいろ便利なライブラリも揃っているし、こういうふうな「定形作業の自動化」には大いに効力を発揮してくれそうですね。

補足

win32gui など入れるには

pip install pywin32

です。

python yg2lz.py でうまく動くことが確認できたら pyinstallerを使って exe ファイルを作ります。

pip install pyinstaller
pyinstaller yg2lz.py --onfile

なお、pyinstaller は Python 3.8 は未対応で最後エラーになるので Python 3.7 を使います。