Skip to content

Instantly share code, notes, and snippets.

@Marken-Foo
Last active April 20, 2020 16:21
Show Gist options
  • Save Marken-Foo/05fe3f477a80ec9f42d28791aa6c1486 to your computer and use it in GitHub Desktop.
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
# === 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