Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

159 righe
4.8 KiB

  1. import argparse
  2. import os
  3. import sys
  4. from subprocess import check_call, DEVNULL, STDOUT, CalledProcessError
  5. parser = argparse.ArgumentParser(description='Convert sgf go records into a kifu format.')
  6. parser.add_argument('sgfFile')
  7. parser.add_argument('-se', "--splitevery", dest="step", type=int, default=50)
  8. parser.add_argument('-c', "--compile", action="store_true", dest="c", default=False)
  9. parser.add_argument('-o', "--open", action="store_true", dest="o", default=False)
  10. args = parser.parse_args(sys.argv[1:])
  11. filePath = args.sgfFile
  12. fileBase = ".".join(filePath.split(".")[:-1])
  13. splitBoardAt = [x for x in range(0, 400, args.step)]
  14. with open(filePath, 'r') as myfile:
  15. sgfData = myfile.read().replace("\n", "").split(";")[1:]
  16. sgfData[-1] = sgfData[-1][:-1]
  17. header = sgfData[0]
  18. moves = sgfData[1:]
  19. def get_tag_from_header(tag):
  20. eventIdxStart = header.lower().find(f"{tag.lower()}[")
  21. eventIdxEnd = -1
  22. if eventIdxStart != -1 :
  23. eventIdxEnd = header.find("]", eventIdxStart)
  24. return header[len(tag) + 1 + eventIdxStart:eventIdxEnd]
  25. return ""
  26. def extract_coordinates(move):
  27. try:
  28. firstCoordinate = move[2]
  29. secondCoordinate = ord(move[3])-96
  30. # mirror at x axis so it looks normal
  31. secondCoordinate = parsedHeader["boardSize"] - secondCoordinate + 1
  32. if ord(move[2]) >= ord("i"):
  33. firstCoordinate = chr(ord(firstCoordinate) + 1)
  34. return firstCoordinate, secondCoordinate
  35. except IndexError:
  36. # wierd move
  37. return -1,-1
  38. def generate_title():
  39. out = []
  40. if parsedHeader["event"] != "":
  41. out.extend([parsedHeader["event"], "\\\\"])
  42. out.append(parsedHeader["playerBlack"])
  43. if parsedHeader["rankBlack"] != "":
  44. out.extend(["[", parsedHeader["rankBlack"], "]"])
  45. out.extend([" - ", parsedHeader["playerWhite"]])
  46. if parsedHeader["rankWhite"] != "":
  47. out.extend(["[", parsedHeader["rankWhite"], "]"])
  48. return "".join(out)
  49. def generate_moves():
  50. finished = False
  51. outText = []
  52. for i in range(len(splitBoardAt)-1):
  53. currentSplit = splitBoardAt[i]
  54. nextSplit = splitBoardAt[i+1]
  55. outText.extend(["\n\\setcounter{gomove}{0}\n", "\\begin{psgoboard}\n\t"])
  56. # old moves
  57. for j in range(currentSplit):
  58. firstCoordinate, secondCoordinate = extract_coordinates(moves[j])
  59. if not (firstCoordinate == -1 or secondCoordinate == -1):
  60. outText.append(f"\\move*{{{firstCoordinate}}}{{{secondCoordinate}}} ")
  61. if j % 5 == 4:
  62. outText.append("\n\t")
  63. elif secondCoordinate < 10: # nice spacing
  64. outText.append(" ")
  65. # new moves
  66. for j in range(nextSplit-currentSplit):
  67. firstCoordinate, secondCoordinate = extract_coordinates(moves[currentSplit+j])
  68. if not (firstCoordinate == -1 or secondCoordinate == -1):
  69. outText.append(f"\\move{{{firstCoordinate}}}{{{secondCoordinate}}} ")
  70. if j % 5 == 4:
  71. outText.append("\n\t")
  72. elif secondCoordinate < 10: # nice spacing
  73. outText.append(" ")
  74. # was it the last move?
  75. if currentSplit+j == len(moves)-1:
  76. finished = True
  77. break
  78. outText.append("\n\\end{psgoboard}\n")
  79. if finished:
  80. break
  81. return "".join(outText)
  82. parsedHeader = {
  83. "event" : get_tag_from_header("EV"),
  84. "gameName" : get_tag_from_header("GN"),
  85. "date" : get_tag_from_header("RD"),
  86. "boardSize" : int(get_tag_from_header("SZ")),
  87. "playerBlack" : get_tag_from_header("PB"),
  88. "playerWhite" : get_tag_from_header("PW"),
  89. "rankBlack" : get_tag_from_header("BR"),
  90. "rankWhite" : get_tag_from_header("WR"),
  91. "komi" : get_tag_from_header("KM"),
  92. "result" : get_tag_from_header("RE")
  93. }
  94. title = generate_title()
  95. date = parsedHeader["date"]
  96. moves = generate_moves()
  97. result = parsedHeader["result"]
  98. outText = f"""
  99. \\documentclass[a4paper]{{article}}
  100. \\usepackage{{psgo}}
  101. \\usepackage[ngerman]{{babel}}
  102. \\usepackage[margin=2cm,nohead]{{geometry}}
  103. \\setgounit{{0.5cm}}
  104. \\author{{}}
  105. \\title{{{title}}}
  106. \\date{{{date}}}
  107. \\begin{{document}}
  108. \\maketitle
  109. \\vspace{{3.5cm}}
  110. \\begin{{center}}
  111. {moves}
  112. \\textbf{{{result}}}
  113. \\end{{center}}
  114. \\end{{document}}
  115. """
  116. with open(f"{fileBase}.tex", 'w') as outFile:
  117. outFile.write(outText)
  118. # should be compiled to pdf?
  119. if args.c:
  120. try:
  121. check_call(['latex', f"{fileBase}.tex"], stdout=DEVNULL, stderr=STDOUT)
  122. check_call(['dvips', f"{fileBase}.dvi", "-P", "pdf"], stdout=DEVNULL, stderr=STDOUT)
  123. check_call(['ps2pdf', f"{fileBase}.ps"], stdout=DEVNULL, stderr=STDOUT)
  124. except CalledProcessError:
  125. print("error")
  126. else:
  127. if args.o:
  128. os.system(f'"{fileBase}.pdf"')