Last active
April 20, 2020 16:21
-
-
Save Marken-Foo/05fe3f477a80ec9f42d28791aa6c1486 to your computer and use it in GitHub Desktop.
Script to convert file containing shogi SFENs to commands for LaTeX rendering
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# === SFEN-to-LaTeX-tsumeshogi-converter === | |
# Just a quick and dirty conversion of SFEN notation from a file into LaTeX | |
# commands for rendering using the myshogi.sty package. | |
# Specifically, assumes the SFEN from the "Sfen" copy option of ShogiGUI. | |
# Example of SFEN line: | |
# position sfen 3sks3/9/4S4/9/1B7/9/+p+l+n+sg+b+r1K/9/9 b r3g3n3l17p 1 moves | |
# Example of desired output (tsume mode): | |
# | |
# \begin{minipage}[t]{0.45\linewidth} | |
# \begin{myshogi} | |
# \banmen | |
# \mochigoma{\sente}{0}{0}{0}{1}{0}{0}{0} | |
# \koma{51}{\gote}{\gyoku} | |
# \koma{41}{\gote}{\gin} | |
# \koma{61}{\gote}{\gin} | |
# \koma{53}{\sente}{\tokin} | |
# \koma{85}{\sente}{\uma} | |
# \end{myshogi} | |
# \end{minipage} | |
import argparse | |
import re | |
PATTERN_FEN_SYMBOL = re.compile(r"\d|\+\w|\w") | |
PATTERN_DROPS = re.compile(r"\d*[a-zA-Z]") # need to account for >9 pawns | |
# FEN symbol to LaTeX commands | |
SYMBOL_TO_LATEX_COMMAND = { | |
"P": "\\fu", "+P": "\\tokin", | |
"p": "\\fu", "+p": "\\tokin", | |
"L": "\\kyou", "+L": "\\narikyou", | |
"l": "\\kyou", "+l": "\\narikyou", | |
"N": "\\kei", "+N": "\\narikei", | |
"n": "\\kei", "+n": "\\narikei", | |
"S": "\\gin", "+S": "\\narigin", | |
"s": "\\gin", "+s": "\\narigin", | |
"G": "\\kin", | |
"g": "\\kin", | |
"B": "\\kaku", "+B": "\\uma", | |
"b": "\\kaku", "+b": "\\uma", | |
"R": "\\hi", "+R": "\\ryu", | |
"r": "\\hi", "+r": "\\ryu", | |
"K": "\\gyoku", | |
"k": "\\ou" | |
} | |
# FEN piece symbol to drop array indices | |
SYMBOL_TO_DROP_IDX = { | |
"R": 0, "B": 1, "G": 2, "S": 3, "N": 4, "L": 5, "P": 6, | |
"r": 0, "b": 1, "g": 2, "s": 3, "n": 4, "l": 5, "p": 6 | |
} | |
def parse_sfen_board(fen, out): | |
ranks = fen.split("/") | |
row = 1 | |
for rank in ranks: | |
col = 9 | |
symbols = PATTERN_FEN_SYMBOL.findall(rank) | |
for symbol in symbols: | |
if symbol.isdigit(): | |
col -= int(symbol) | |
else: | |
piece_side = "\\sente" if symbol.isupper() else "\\gote" | |
piece_type = SYMBOL_TO_LATEX_COMMAND[symbol] | |
out.append("\\koma{%d%d}{%s}{%s}\n" % | |
(col, row, piece_side, piece_type) | |
) | |
col -= 1 | |
row += 1 | |
return out | |
def parse_sfen_mochigoma(drops, out, is_tsume=False): | |
drop_array = [[0] * 7, [0] * 7] # sente then gote, pieces in order RBGSNLP | |
drop_list = PATTERN_DROPS.findall(drops) | |
for drop in drop_list: | |
drop_symbol = "".join(filter(str.isalpha, drop)) | |
digits = "".join(filter(str.isdigit, drop)) | |
drop_number = 1 if digits == "" else int(digits) | |
is_gote = drop_symbol.islower() | |
drop_array[int(is_gote)][SYMBOL_TO_DROP_IDX[drop_symbol]] = drop_number | |
out.append("\\mochigoma{%s}{%d}{%d}{%d}{%d}{%d}{%d}{%d}\n" % | |
tuple(["\\sente"] + drop_array[0]) | |
) | |
if not is_tsume: | |
out.append("\\mochigoma{%s}{%d}{%d}{%d}{%d}{%d}{%d}{%d}\n" % | |
tuple(["\\gote"] + drop_array[1]) | |
) | |
return out | |
# "main" function | |
# parsing command line arguments | |
parser = argparse.ArgumentParser(description="Generate .txt file containing LaTeX commands (from myshogi.sty) to render input file containing shogi FENs.") | |
parser.add_argument("input_file", type=str, help="Input text file containing one SFEN per line.") | |
parser.add_argument("output_file", type=str, nargs="?", default="shogi_latex.txt", help="Output text file. Will be created if it does not exist.") | |
parser.add_argument("-t", "--tsume", action="store_true", help="Use this flag to specify that the file contains tsumeshogi problem, suppressing gote's pocket.") | |
args = parser.parse_args() | |
# open files and read/write | |
with open(args.input_file, "r") as sepd_file: | |
with open(args.output_file, "w") as out_file: | |
for line_num, line in enumerate(sepd_file): | |
sfen = line.split(" ") | |
sfen_board = sfen[1] | |
sfen_pockets = sfen[3] | |
# actual writing to file | |
out_file.write("\\begin{minipage}[t]{0.45\\linewidth}\n" | |
"\\begin{myshogi}\n" | |
"\\banmen\n") | |
out_file.write("".join(parse_sfen_mochigoma(sfen_pockets, [], args.tsume))) | |
out_file.write("".join(parse_sfen_board(sfen_board, []))) | |
out_file.write("\\end{myshogi}\n" | |
"\\end{minipage}\n") | |
# assumes LaTeX will display 2 diagrams per row on a page | |
if line_num % 2 == 1: | |
out_file.write("\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment