gen-80x25-crossword - crossword-generator - A crossword vtv generator.
HTML git clone git://bitreich.org/crossword-generator git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/crossword-generator
DIR Log
DIR Files
DIR Refs
DIR Tags
DIR 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