From 8a944c9d51bc39c9293cfd6f9d1faadd7d31b1d8 Mon Sep 17 00:00:00 2001 From: Abdul Muqeet Mohammed Date: Sat, 18 Mar 2023 21:21:49 -0400 Subject: [PATCH] Added JSON, CSV, and Text; Enlarged Border; Warnings on Incorrect Filetype --- README.rst | 28 ++++++++--- genxword/calculate.py | 112 ++++++++++++++++++++++++++++++++++++++---- genxword/cli.py | 9 +++- 3 files changed, 131 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index fc56209..914106b 100644 --- a/README.rst +++ b/README.rst @@ -41,20 +41,36 @@ Use Please read the `wiki `_ for information about how to use genxword. -Installation ------------- +GUI Installation +---------------- To install genxword (add *sudo* to the command, or run as root, -if you are using Linux): :: +if you are using Linux): pip3 install genxword +Next, ensure you have installed all the necessary dependencies under #Dependencies. + +Lite Installation +----------------- + +Simply run: + + pip3 install genxword --no-deps + +Everything will work fine. However, you will only be able to export to: + t: Text, + z: IPUZ, + c: CSV, + j: Simplified JSON Representation + Dependencies ------------ -Genxword depends on pycairo (python-cairo), pygobject (python-gobject or python-gi), -python-gi-cairo (if you are using a Debian-based system), pango (gir1.2-pango-1.0), -gtksourceview3 (gir1.2-gtksource-3.0) and gettext. +Genxword requires pycairo (python-cairo), pygobject (python-gobject or python-gi), +python-gi-cairo (if you are using a Debian-based system), and pango (gir1.2-pango-1.0). + +If you would like to use the GUI, install gtksourceview3 (gir1.2-gtksource-3.0) and gettext. These dependencies can easily be installed on Linux by using your package manager, and with most distributions, they will already be installed. diff --git a/genxword/calculate.py b/genxword/calculate.py index d79c7ab..82d6064 100644 --- a/genxword/calculate.py +++ b/genxword/calculate.py @@ -19,12 +19,22 @@ # You should have received a copy of the GNU General Public License # along with genxword. If not, see . -import gi -gi.require_version('PangoCairo', '1.0') -gi.require_version('Pango', '1.0') - -from gi.repository import Pango, PangoCairo -import random, time, cairo, json +NOGTK = False +try: + import gi + gi.require_version('PangoCairo', '1.0') + gi.require_version('Pango', '1.0') + + from gi.repository import Pango, PangoCairo + import cairo +except ImportError as e: + NOGTK = True + print("MISSING DEPENDENCIES!") + print("IGNORE IF LITE VERSION WAS INTENTIONALLY INSTALLED!") + print(e) + print() + +import random, time, json, csv from operator import itemgetter from collections import defaultdict @@ -188,12 +198,12 @@ def draw_img(self, name, context, px, xoffset, yoffset, RTL): for r in range(self.rows): for i, c in enumerate(self.grid[r]): if c != self.empty: - context.set_line_width(1.0) - context.set_source_rgb(0.5, 0.5, 0.5) + context.set_line_width(3.0) + context.set_source_rgb(0.3, 0.3, 0.3) context.rectangle(xoffset+(i*px), yoffset+(r*px), px, px) context.stroke() - context.set_line_width(1.0) - context.set_source_rgb(0, 0, 0) + context.set_line_width(3.0) + context.set_source_rgb(0.3, 0.3, 0.3) context.rectangle(xoffset+1+(i*px), yoffset+1+(r*px), px-2, px-2) context.stroke() if '_key.' in name: @@ -277,6 +287,15 @@ def create_files(self, name, save_format, lang, message): else: RTL = False img_files = '' + if 't' in save_format: + self.write_text(name, name + '.txt', lang) + img_files += name + '.txt' + if 'j' in save_format: + self.write_json(name, name + '.json', lang) + img_files += name + '.json' + if 'c' in save_format: + self.write_csv(name, name + '.csv', lang) + img_files += name + '.csv' if 'p' in save_format: self.export_pdf(name, '_grid.pdf', lang, RTL) self.export_pdf(name, '_key.pdf', lang, RTL) @@ -375,3 +394,76 @@ def write_ipuz(self, name, filename, lang): with open(filename, 'w') as fp: json.dump(data, fp, indent=4) + + def write_json(self, name, filename, lang): + # Generate the clue numbers if we haven't already + if len(self.wordlist[0]) < 6: + self.order_number_words() + + # Generate some data structures for the final output + data = { + "name": name, + 'dimensions': { + 'width': self.cols, + 'height': self.rows + }, + 'puzzle': [] + } + # Iterate the clues to calculate the main data + for clue in self.wordlist: + word, clue_text, row, col, vertical, num = clue[:6] + c = { + "ans": word, + "clue": clue_text, + "row": row, + "col": col, + "vspan": bool(vertical) # if Vertical + } + data["puzzle"].append(c) + + with open(filename, 'w') as fp: + json.dump(data, fp) + + + def write_text(self, name, filename, lang): + # Generate the clue numbers if we haven't already + if len(self.wordlist[0]) < 6: + self.order_number_words() + + # Generate some data structures format the final output + puzzle = [["##"] * self.cols for row in range(self.rows)] + clues = {'Across': [], 'Down': []} + solution = [['#' if col == '-' else col for col in row] for row in self.grid] + + # Iterate the clues to calculate the main data + for clue in self.wordlist: + word, clue_text, row, col, vertical, num = clue[:6] + puzzle[row][col] = str(num) if num > 9 else "0" + str(num) + + puz_clue = [num, clue_text] + if vertical: + clues['Down'].append(puz_clue) + for i in range(len(word)): + if puzzle[row + i][col] == "##": + puzzle[row + i][col] = " " + else: + clues['Across'].append(puz_clue) + for i in range(len(word)): + if puzzle[row][col + i] == "##": + puzzle[row][col + i] = " " + + with open(filename, 'w') as fp: + fp.write(name + "\n\n") + for row in puzzle: + fp.write(' '.join(row) + '\n') + fp.write('\n') + for (dir, cluelist) in clues.items(): + fp.write(dir + ":\n") + for clue in cluelist: + fp.write('{:2d}'.format(clue[0]) + ": " + clue[1] + '\n') + + def write_csv(self, name, filename, lang): + with open(filename, 'w') as fp: + fieldnames = ["word", "clue", "row", "col", "vertical", "num"] + writer = csv.writer(fp) + writer.writerows(self.wordlist) \ No newline at end of file diff --git a/genxword/cli.py b/genxword/cli.py index 7511930..2a2d180 100644 --- a/genxword/cli.py +++ b/genxword/cli.py @@ -27,13 +27,18 @@ def main(): parser = argparse.ArgumentParser(description=_('Crossword generator.'), prog='genxword', epilog=usage_info) parser.add_argument('infile', help=_('Name of word list file.')) - parser.add_argument('saveformat', help=_('Save files as A4 pdf (p), letter size pdf (l), png (n), svg(s) and/or ' - 'ipuz(z).')) + filetypes = [c for c in 'plnszcjt'] + parser.add_argument('saveformat', help=_('Save files as A4 PDF (p), Letter Size PDF (l), PNG (n), SVG (s), IPUZ (z),' + 'Plain Text (t), CSV (c), and/or JSON (j).')) parser.add_argument('-a', '--auto', dest='auto', action='store_true', help=_('Automated (non-interactive) option.')) parser.add_argument('-m', '--mix', dest='mixmode', action='store_true', help=_('Create anagrams for the clues')) parser.add_argument('-n', '--number', dest='nwords', type=int, default=50, help=_('Number of words to be used.')) parser.add_argument('-o', '--output', dest='output', default='Gumby', help=_('Name of crossword.')) args = parser.parse_args() + if not any([f in args.saveformat for f in filetypes]): + # If none of the filetypes matched + print("ERROR: Unrecognized File Type!") + quit(1) gen = Genxword(args.auto, args.mixmode) with open(args.infile) as infile: gen.wlist(infile, args.nwords)