diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80990f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc +*.pdf +stocks/* +.idea/* diff --git a/README b/README deleted file mode 100644 index a62cd1c..0000000 --- a/README +++ /dev/null @@ -1,21 +0,0 @@ -Wordsearch generator -==================== - -Currently, this is a simple command-line script which generates a wordsearch -grid. - -Usage: - - python wordsearch.py [word...] - -The grid size, and permissible directions for words, is controlled by the -difficulty setting, which is one of easy, normal and hard. - -The output grid is displayed on stdout, and written to a pdf file. - -Much work still remains to make the output nice. - -Requirements -============ - -reportlab Python library (https://pypi.python.org/pypi/reportlab) diff --git a/README.md b/README.md new file mode 100644 index 0000000..5a4a75e --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +Wordsearch generator +==================== + +(o Generador de sopas de letras) + +Based on https://github.com/rboulton/wordsearch + +Currently, this is a simple command-line script which generates a wordsearch +grid. + +Usage: + + python wordsearch.py [word...] + +Example: + + python wordsearch.py easy duck "polar bear" dog horse rabbit + +The grid size, and permissible directions for words, is controlled by the +difficulty setting, which is one of `easy`, `normal` and `hard`. + +The output grid is displayed on stdout, and written to a pdf file called with the same name of the first word. + +Example of the generated pdf: https://github.com/jjconti/sopa-de-letras/blob/master/output_example.pdf + +Requirements +============ + +* Reportlab (https://pypi.python.org/pypi/reportlab) + +Improvements from the original version +====================================== + +* Better pdf layout +* Configurable header and footer +* Allow words with spaces (using quotes). Example: `python wordsearch.py hard word1 "word with spaces" word3` +* Allow not only ascii input (for example, words with ñ or á é í ó ú are fine) diff --git a/config.py b/config.py new file mode 100644 index 0000000..74754ad --- /dev/null +++ b/config.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +FIND_THE_WORDS = "Find the words: " +BOTTOM_TEXT = "Generated with ❤" diff --git a/output_example.pdf b/output_example.pdf new file mode 100644 index 0000000..36135dd Binary files /dev/null and b/output_example.pdf differ diff --git a/wordsearch.py b/wordsearch.py index 77ad3cc..98270d2 100644 --- a/wordsearch.py +++ b/wordsearch.py @@ -1,38 +1,22 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- import random +from config import * + # Directions are: # +. left to right # -. right to left # .+ top to bottom # .- bottom to top -def read_words(filename): - words = set() - fd = open(filename) - try: - for line in fd.readlines(): - if "'" in line: - continue - line = line.strip().lower() - if len(line) > 3 and len(line) < 7: - words.add(line) - finally: - fd.close() - return words - -all_words = read_words('/usr/share/dict/words') -explicit_words = ('fuck', 'cunt', 'piss', 'bloody', 'shit', 'boob') -for word in explicit_words: - all_words.add(word) - all_directions = ('+-', '+.', '++', '.+', '.-', '--', '-.', '-+') styles = { 'easy': ('10x10', ('+.', '.+')), 'standard': ('15x15', ('+-', '+.', '++', '.+', '.-', '-.')), - 'hard': ('20x20', all_directions), + 'hard': ('15x15', all_directions) } dirconv = { @@ -41,52 +25,67 @@ def read_words(filename): '+': 1, } -letters = "abcdefghijklmnopqrstuvwxyz" +letters = u"abcdefghijklmnñopqrstuvwxyz" class Grid(object): def __init__(self, wid, hgt): self.wid = wid - self.hgt = hgt - self.data = ['.'] * (wid * hgt) - self.used = [' '] * (wid * hgt) + self.hgt = hgt + self.data = ['.'] * (wid * hgt) + self.used = [' '] * (wid * hgt) self.words = [] def to_text(self): result = [] - for row in xrange(self.hgt): - result.append(''.join(self.data[row * self.wid : + for row in xrange(self.hgt): + result.append(''.join(self.data[row * self.wid : (row + 1) * self.wid])) - return '\n'.join(result) - + return '\n'.join(result) + def used_to_text(self): result = [] - for row in xrange(self.hgt): - result.append(''.join(self.used[row * self.wid : + for row in xrange(self.hgt): + result.append(''.join(self.used[row * self.wid : (row + 1) * self.wid])) - return '\n'.join(result) + return '\n'.join(result) - def to_pdf(self, filename): + def to_pdf(self, filename, words): from reportlab.pdfgen import canvas - from reportlab.lib.pagesizes import letter, A4 - - pagesize = A4 - paper = canvas.Canvas(filename, pagesize=pagesize) - margin = 50 - printwid, printhgt = map(lambda x: x - margin * 2, pagesize) + from reportlab.lib.pagesizes import cm, A4 + from reportlab.platypus import SimpleDocTemplate, Table, TableStyle + from reportlab.lib import colors + from reportlab.platypus.paragraph import Paragraph + from reportlab.lib.styles import ParagraphStyle + from reportlab.platypus.flowables import Spacer - gx = margin - gy = printhgt - margin - gdx = printwid / self.wid - gdy = printhgt / self.hgt - for y in xrange(self.hgt): - cy = gy - y * gdy - for x in xrange(self.wid): - cx = gx + x * gdx - p = x + self.wid * y - c = self.data[p] - paper.drawString(cx, cy, c) - paper.showPage() - paper.save() + doc = SimpleDocTemplate(filename, pagesize=A4) + data = [self.data[x: x + self.wid] for x in range(0, len(self.data), self.wid)] + l = cm * 1.25 + t=Table(data, len(data[0]) * [l], len(data) * [l]) + t.setStyle(TableStyle([('ALIGN',(0,0),(-1,-1),'CENTER'), + ('VALIGN',(0,0),(-1,-1),'TOP'), + ('BOX', (0,0), (-1,-1), 1, colors.black), + ('FONTSIZE', (0,0), (-1,-1), 20) + ])) + style = ParagraphStyle( + 'default', + fontName='Times-Roman', + fontSize=18, + leading=18, + spaceBefore=10, + spaceAfter=10, + bulletFontName='Times-Roman', + bulletFontSize=18, + bulletIndent=0, + ) + elements = [Paragraph(FIND_THE_WORDS, style, None)] + elements.append(Paragraph(", ".join(words), style)) + elements.append(Spacer(1, 0.5 * cm)) + elements.append(t) + style.fontSize = 12 + elements.append(Spacer(1, 0.5 * cm)) + elements.append(Paragraph(BOTTOM_TEXT, style, None)) + doc.build(elements) def pick_word_pos(self, wordlen, directions): xd, yd = random.choice(directions) @@ -140,9 +139,6 @@ def fill_in_letters(self): if self.data[p] == '.': self.data[p] = random.choice(letters) - def remove_bad_words(self): - return True - def make_grid(stylep="standard", words=[], tries=100): # Parse and validate the style parameter. size, directions = styles.get(stylep, (stylep, all_directions)) @@ -158,30 +154,26 @@ def make_grid(stylep="standard", words=[], tries=100): for direction in directions] while True: - while True: - grid = Grid(wid, hgt) - if grid.place_words(words, directions): - break - tries -= 1 - if tries <= 0: - return None - - grid.fill_in_letters() - if grid.remove_bad_words(): - return grid - + grid = Grid(wid, hgt) + if grid.place_words(words, directions): + break tries -= 1 if tries <= 0: return None + grid.fill_in_letters() + return grid + if __name__ == '__main__': import sys random.seed() - grid = make_grid(sys.argv[1], sys.argv[2:]) + words = sys.argv[2:] + words_to_use = [unicode("".join(w.lower().split()), 'utf-8') for w in words] + grid = make_grid(sys.argv[1], words_to_use) if grid is None: print "Can't make a grid" else: print grid.to_text() print print grid.used_to_text() - grid.to_pdf("ws.pdf") + grid.to_pdf(words_to_use[0] + ".pdf", words)