|
|
gen-80x25-crossword - crossword-generator - A crossword vtv generator. |
|
|
 |
git clone git://bitreich.org/crossword-generator git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/crossword-generator (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
gen-80x25-crossword (5644B) |
|
|
|
--- |
|
|
|
1 #!/usr/bin/env python |
|
|
|
2 # coding=utf-8 |
|
|
|
3 # |
|
|
|
4 # © 2023 Christoph Lohmann <20h@r-36.net> |
|
|
|
5 # |
|
|
|
6 # This file is published under the terms of the GPLv3. |
|
|
|
7 # |
|
|
|
8 |
|
|
|
9 import os |
|
|
|
10 import sys |
|
|
|
11 import getopt |
|
|
|
12 import random |
|
|
|
13 |
|
|
|
14 def print_field(field): |
|
|
|
15 for line in field: |
|
|
|
16 for cell in line: |
|
|
|
17 print("%s" % (cell), end="") |
|
|
|
18 print("") |
|
|
|
19 |
|
|
|
20 def usage(app): |
|
|
|
21 app = os.path.basename(app) |
|
|
|
22 print("usage: %s [-h] file.txt" % (app), file=sys.stderr) |
|
|
|
23 sys.exit(1) |
|
|
|
24 |
|
|
|
25 def main(args): |
|
|
|
26 try: |
|
|
|
27 opts, largs = getopt.getopt(args[1:], "h") |
|
|
|
28 except getopt.GetoptError as err: |
|
|
|
29 print(str(err)) |
|
|
|
30 usage(args[0]) |
|
|
|
31 |
|
|
|
32 for o, a in opts: |
|
|
|
33 if o == "-h": |
|
|
|
34 usage(args[0]) |
|
|
|
35 else: |
|
|
|
36 assert False, "unhandled option" |
|
|
|
37 |
|
|
|
38 if len(largs) < 1: |
|
|
|
39 usage(args[0]) |
|
|
|
40 crossfile = largs[0] |
|
|
|
41 entries = {} |
|
|
|
42 |
|
|
|
43 with open(crossfile) as fd: |
|
|
|
44 for line in fd: |
|
|
|
45 line = line.strip() |
|
|
|
46 if len(line) == 0: |
|
|
|
47 continue |
|
|
|
48 if line[0] == "#": |
|
|
|
49 continue |
|
|
|
50 try: |
|
|
|
51 (word, hint) = line.split(" ", 1) |
|
|
|
52 except ValueError: |
|
|
|
53 continue |
|
|
|
54 entries[word] = hint |
|
|
|
55 if entries == {}: |
|
|
|
56 usage(args[0]) |
|
|
|
57 #print(entries) |
|
|
|
58 |
|
|
|
59 def check_word(field, x, y, word, vertical): |
|
|
|
60 #print("check_word(field, %s, %s, %s, %s)" % \ |
|
|
|
61 # (x, y, word, vertical)) |
|
|
|
62 if y < 1 or x < 1: |
|
|
|
63 return False |
|
|
|
64 for c in word: |
|
|
|
65 #print("check '%s' vs '%s' at (%s,%s)" % \ |
|
|
|
66 # (field[y][x], c, x, y)) |
|
|
|
67 if y > 24: |
|
|
|
68 return False |
|
|
|
69 if x > 79: |
|
|
|
70 return False |
|
|
|
71 if field[y][x] == '#': |
|
|
|
72 return False |
|
|
|
73 if field[y][x] != c and field[y][x] != '.': |
|
|
|
74 return False |
|
|
|
75 if vertical: |
|
|
|
76 y += 1 |
|
|
|
77 else: |
|
|
|
78 x += 1 |
|
|
|
79 return True |
|
|
|
80 |
|
|
|
81 def add_word(field, x, y, word, vertical): |
|
|
|
82 #print("add_word %s %s %s %s %s" % (x, y, word, len(word), |
|
|
|
83 # vertical)) |
|
|
|
84 for c in word: |
|
|
|
85 try: |
|
|
|
86 field[y][x] = c |
|
|
|
87 except IndexError: |
|
|
|
88 print("x = %s, y = %s" % (x, y)) |
|
|
|
89 sys.exit(1) |
|
|
|
90 if c not in char2pos: |
|
|
|
91 char2pos[c] = [] |
|
|
|
92 char2pos[c] += [[x, y, vertical]] |
|
|
|
93 if vertical: |
|
|
|
94 y += 1 |
|
|
|
95 else: |
|
|
|
96 x += 1 |
|
|
|
97 |
|
|
|
98 def replace_word(field, x, y, word, vertical, c): |
|
|
|
99 #print("replace_word %s %s %s %s %s %s" % (x, y, word, len(word), |
|
|
|
100 # vertical, c)) |
|
|
|
101 for b in word: |
|
|
|
102 try: |
|
|
|
103 if c == "=": |
|
|
|
104 field[y][x] = c |
|
|
|
105 elif field[y][x] != "=": |
|
|
|
106 field[y][x] = "X" |
|
|
|
107 else: |
|
|
|
108 field[y][x] = c |
|
|
|
109 except IndexError: |
|
|
|
110 print("x = %s, y = %s" % (x, y)) |
|
|
|
111 sys.exit(1) |
|
|
|
112 if vertical: |
|
|
|
113 y += 1 |
|
|
|
114 else: |
|
|
|
115 x += 1 |
|
|
|
116 |
|
|
|
117 def print_description(field, x, y, description): |
|
|
|
118 for c in description: |
|
|
|
119 try: |
|
|
|
120 field[y][x] = c |
|
|
|
121 except IndexError: |
|
|
|
122 print("x = %s, y = %s" % (x, y)) |
|
|
|
123 sys.exit(1) |
|
|
|
124 x += 1 |
|
|
|
125 if x > 78: |
|
|
|
126 break |
|
|
|
127 |
|
|
|
128 maxtries = 10 |
|
|
|
129 tries = 0 |
|
|
|
130 entriesbackup = entries.copy() |
|
|
|
131 while tries < maxtries: |
|
|
|
132 # 80x25 for term output. |
|
|
|
133 field = [] |
|
|
|
134 field.append(["#"]*80) |
|
|
|
135 for i in range(1, 24): |
|
|
|
136 field.append(["#"] + ["."]*78 + ["#"]) |
|
|
|
137 field.append(["#"]*80) |
|
|
|
138 char2pos = {} |
|
|
|
139 |
|
|
|
140 field.append(["#"]*80) |
|
|
|
141 for i in range(1, 24): |
|
|
|
142 field.append(["#"] + ["."]*78 + ["#"]) |
|
|
|
143 field.append(["#"]*80) |
|
|
|
144 |
|
|
|
145 entries = entriesbackup.copy() |
|
|
|
146 print_description(field, 45, 3, "A funny crossword from man pages.") |
|
|
|
147 print_description(field, 47, 5, "Have fun solving it!") |
|
|
|
148 print_description(field, 42, 7, "[a-z0-9] -> find the manpage") |
|
|
|
149 print_description(field, 49, 8, "X -> crossover of names") |
|
|
|
150 print_description(field, 30, 10, "= manpage description (hint: grep it)") |
|
|
|
151 outputentries = {} |
|
|
|
152 markerstr = "abcdefghijklmnopqrstuvwxyz0123456789" |
|
|
|
153 ypos = 11 |
|
|
|
154 xpos = 30 |
|
|
|
155 markeri = 0 |
|
|
|
156 for entry in entries.keys(): |
|
|
|
157 entries[entry] = [entries[entry], markerstr[markeri]] |
|
|
|
158 if ypos == 24: |
|
|
|
159 xpos = 2 |
|
|
|
160 ypos += 2 |
|
|
|
161 if ypos < len(field) - 1: |
|
|
|
162 print_description(field, xpos, ypos, \ |
|
|
|
163 "%s %s" % (entries[entry][1], \ |
|
|
|
164 entries[entry][0])) |
|
|
|
165 ypos += 1 |
|
|
|
166 markeri += 1 |
|
|
|
167 |
|
|
|
168 entry = random.choice(list(entries.keys())) |
|
|
|
169 vertical = random.choice([True, False]) |
|
|
|
170 x = 5 |
|
|
|
171 y = 12 |
|
|
|
172 #x = random.randint(0 + 5, 5 + 20 - len(entry) * int(not vertical)) |
|
|
|
173 #y = random.randint(0 + 5, 5 + 10 - len(entry) * int(vertical)) |
|
|
|
174 add_word(field, x, y, entry, vertical) |
|
|
|
175 del entries[entry] |
|
|
|
176 |
|
|
|
177 tryouts = [] |
|
|
|
178 while len(entries.keys()) > 0: |
|
|
|
179 ex = 0 |
|
|
|
180 ey = 0 |
|
|
|
181 vertical = True |
|
|
|
182 entryfound = False |
|
|
|
183 entry = random.choice(list(entries.keys())) |
|
|
|
184 #print("Trying %s ..." % (entry), end="") |
|
|
|
185 if entry in tryouts: |
|
|
|
186 #print("") |
|
|
|
187 break |
|
|
|
188 |
|
|
|
189 sentry = "".join(random.sample(entry, len(entry))) |
|
|
|
190 for c in sentry: |
|
|
|
191 if c not in char2pos: |
|
|
|
192 continue |
|
|
|
193 (beg, remain) = entry.split(c, 1) |
|
|
|
194 randpos = random.sample(char2pos[c], len(char2pos[c])) |
|
|
|
195 for pos in randpos: |
|
|
|
196 vertical = not pos[2] |
|
|
|
197 ex = pos[0] - len(beg) * int(not vertical) |
|
|
|
198 ey = pos[1] - len(beg) * int(vertical) |
|
|
|
199 if check_word(field, ex, ey, entry, vertical) == True: |
|
|
|
200 #print(" entryfound", end="") |
|
|
|
201 entryfound = True |
|
|
|
202 break |
|
|
|
203 if entryfound == True: |
|
|
|
204 break |
|
|
|
205 #print("") |
|
|
|
206 if entryfound == True: |
|
|
|
207 add_word(field, ex, ey, entry, vertical) |
|
|
|
208 outputentries[entry] = \ |
|
|
|
209 [entries[entry][0], \ |
|
|
|
210 entries[entry][1], \ |
|
|
|
211 ex, ey, vertical] |
|
|
|
212 del entries[entry] |
|
|
|
213 else: |
|
|
|
214 tryouts.append(entry) |
|
|
|
215 if len(entries) == 0: |
|
|
|
216 for entry in outputentries.keys(): |
|
|
|
217 replace_word(field, \ |
|
|
|
218 outputentries[entry][2], \ |
|
|
|
219 outputentries[entry][3], \ |
|
|
|
220 entry, \ |
|
|
|
221 outputentries[entry][4], \ |
|
|
|
222 "=") |
|
|
|
223 |
|
|
|
224 for entry in outputentries.keys(): |
|
|
|
225 replace_word(field, \ |
|
|
|
226 outputentries[entry][2], \ |
|
|
|
227 outputentries[entry][3], \ |
|
|
|
228 entry, \ |
|
|
|
229 outputentries[entry][4], \ |
|
|
|
230 outputentries[entry][1]) |
|
|
|
231 break |
|
|
|
232 tries += 1 |
|
|
|
233 |
|
|
|
234 if tries >= maxtries: |
|
|
|
235 sys.stderr.write("Crossword not possible.\n") |
|
|
|
236 #print(char2pos) |
|
|
|
237 print_field(field) |
|
|
|
238 return 1 |
|
|
|
239 |
|
|
|
240 print_field(field) |
|
|
|
241 return 0 |
|
|
|
242 |
|
|
|
243 if __name__ == "__main__": |
|
|
|
244 sys.exit(main(sys.argv)) |
|
|
|
245 |
|