URI: 
       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