This repository has been archived by the owner on Dec 6, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmkxwordltx.py
164 lines (141 loc) · 5.77 KB
/
mkxwordltx.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import csv
import itertools
import random
import sys
import uuid
from pathlib import Path
from xwordgen_bh import Crossword
_crossword_uuid = uuid.uuid4()
word_list_path = Path(__file__).parent / "words.csv"
output_path = Path(__file__).parent / f"{_crossword_uuid.hex}.tex"
ltx_doc_start = \
"""% !TEX TS-program = pdflatex
\\documentclass[12pt]{{article}}
\\usepackage{{ltxcrossword}}
\\pagestyle{{fancy}}
\\makeheadersandfooters{{USWACS Crossword: {_crossword_uuid}}}
\\begin{{document}}
""".format(_crossword_uuid=_crossword_uuid)
ltx_doc_end = "\\end{document}\n"
def make_ltxtable():
return "\\begin{table}[h!]\n" \
"\\centering\\ttfamily\\tiny\n" \
"\\setlength{\\tabcolsep}{2pt}\n" \
"\\newlength{\\rowh}\n" \
"\\setlength{\\rowh}{0.02\\textwidth}\n", \
"\\end{table}\n"
def make_ltxtabularx(xword_grid):
def xwordcell_to_ltxcell(cell):
if cell == "-":
return "\\cellcolor{black!5}"
elif cell == "w":
return "\\cellcolor{white}"
else:
return cell
tabularx_init = "\\begin{tabularx}{1\\textwidth}{*{25}{|X}|}\n" \
"\\arrayrulecolor{fader-gray}\n" \
"\\hline\n"
rows = []
# Split the xword grid into individual rows
# Hack: Remove the last row that is unfilled due to a bug in xwordgen_bh
xword_rows = xword_grid.splitlines()[0:-1]
# print(len(xword_rows))
for xword_row in xword_rows:
# Split the xword row into cells, removing the empty string at the end
# Hack, remove the last column - it is unfilled by xwordgen_bh
cells = xword_row.split(" ")
cells = cells[0:-2]
# print(cells)
# print(len(cells))
# Convert xword cells into LaTeX cells
cells = map(xwordcell_to_ltxcell, cells)
# Join the LaTex cells together to make a LaTeX row data
row_data = " & ".join(cells)
# Create the full row and append to rows
row = f"{row_data} \\tabularnewline[\\rowh] \\hline"
rows.append(row)
all_rows = "\n".join(rows)
tabularx_end = "\n\\end{tabularx}\n"
return f"{tabularx_init}{all_rows}{tabularx_end}"
def make_xword_ltxtable(xword_grid):
ltxtable_init, ltxtable_end = make_ltxtable()
ltxtabularx = make_ltxtabularx(xword_grid)
return f"{ltxtable_init}{ltxtabularx}{ltxtable_end}"
def make_xword_clues(xword_legend, word_lengths):
def adjust_clue(clue):
parts = clue.split(":")
wordpos, cluetext = parts[0], parts[1].lstrip()
wordnum = wordpos.split(".")[0]
wlens = word_lengths[cluetext]
ltx_clue_text = f"\\textbf{{{wordnum}.}} \\textit{{{wlens}:}} {cluetext}"
return ltx_clue_text
clues = ["\\pagebreak\n",
"\\centering\n"]
mpla = ["\\begin{minipage}[t]{0.47\\linewidth}\n",
"\\vspace{0pt}\n",
"{\\Centering\\underline{\\textsc{Across}}\\\\~\\\\}\n",
"\\RaggedRight\n",
"\\fontsize{10pt}{10pt}\\selectfont\n"]
mprd = ["\\begin{minipage}[t]{0.47\\linewidth}\n",
"\\vspace{0pt}\n",
"{\\Centering\\underline{\\textsc{Down}}\\\\~\\\\}\n",
"\\RaggedRight\n",
"\\fontsize{10pt}{10pt}\\selectfont\n"]
for clue in xword_legend.splitlines():
position = clue.split(":")[0]
if "across" in position:
mpla.append(f"{adjust_clue(clue)}\\\\\n")
elif "down" in position:
adjust_clue(clue)
mprd.append(f"{adjust_clue(clue)}\\\\\n")
else:
raise Exception(f"Bad clue position '{position}' not across or down!")
mpla.append("\\end{minipage}")
mprd.append("\\end{minipage}")
parts = itertools.chain(clues, mpla,
["\\hspace{4mm}\\textcolor{gray}{\\vline width 0.1mm}\\hspace{3mm}~\n"],
mprd, ["\\\\\n"])
return "".join(parts)
def filter_word_randomly(word):
return random.choice([True, True, False])
if __name__ == '__main__':
print("Loading word list from file...")
word_list = []
word_lengths = {}
with word_list_path.open(mode="r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
answer, clue = row["answer"], row["clue"]
nsanswer = answer.replace(" ","")
words = answer.split(" ")
for word in words:
if clue in word_lengths:
word_lengths[clue].append(len(word))
else:
word_lengths[clue] = [len(word)]
word_list.append([nsanswer, row["clue"]])
# Remove some words from the long word list at random
# This increases our chance of getting more shorter words in the crossword
word_list = list(filter(filter_word_randomly, word_list))
time = 10
print(f"Creating crossword... (takes {time} seconds)")
xword = Crossword(26, 26, "-", 5000, word_list)
xword.compute_crossword(time, spins=3)
xword_solution = xword.solution()
xword_grid = xword.display()
xword_legend = xword.legend()
print(f"Used {len(xword.current_word_list)} out of {len(word_list)} words")
print(f"Cycles: {xword.debug}")
print(xword_solution)
print("Making LaTeX table for crossword...")
ltx_xword_table = make_xword_ltxtable(xword_grid)
ltx_xword_clues = make_xword_clues(xword_legend, word_lengths)
print(f"Writing LaTeX document to {output_path}...")
with output_path.open(mode="w", encoding="utf-8") as f:
f.write(ltx_doc_start)
f.write(ltx_xword_table)
f.write(ltx_xword_clues)
f.write(ltx_doc_end)
for solution_ln in xword_solution.splitlines(keepends=True):
f.write(f"% {solution_ln}")
print(f"Finished making crossword - run .\\make.py {output_path.name} to compile!")