1816ff62a57f0ebc84689b4f6254bbf2927580a9
1 # Get A Clue (C) 2010 V. Harishankar
2 # Crossword puzzle maker program
3 # Licensed under the GNU GPL v3
5 # Cross puzzle creator class
10 import crosswordpuzzle
12 class CrosswordPuzzleCreator
:
13 # ansi color codes for grid display
21 # Black background white text
22 BLACK_BG
= '\033[40;1;37m'
23 # white background black text
24 WHITE_BG
= '\033[47;1;30m'
25 # white background red text
26 REDWHITE_BG
= '\033[47;1;31m'
32 self
.current_file
= None
36 def save_puzzle (self
):
38 fpuzzle
= open (self
.current_file
, "wb")
39 cPickle
.dump (self
.puzzle
, fpuzzle
, cPickle
.HIGHEST_PROTOCOL
)
40 sys
.stdout
.write (self
.BLUE
+ "Puzzle saved to: " +
41 self
.current_file
+ "\n" + self
.ENDCOL
)
44 def load_puzzle (self
):
46 fpuzzle
= open (self
.current_file
, "rb")
47 self
.puzzle
= cPickle
.load (fpuzzle
)
49 # display the grid with words
50 def print_puzzle (self
, no_words
=False):
51 # if self.puzzle is not none
53 # get row, col and print them (with grid number if set)
54 for col
in range (self
.puzzle
.cols
):
55 # print the first row as column headers
56 sys
.stdout
.write (self
.BLUE
+ ' %02d' % col
+ self
.ENDCOL
)
57 sys
.stdout
.write ("\n")
59 for row
in range (self
.puzzle
.rows
):
60 for col
in range (self
.puzzle
.cols
):
62 # if the cell is numbered i.e. start of a word
63 if self
.puzzle
.data
[row
][col
].numbered
!= 0:
64 sys
.stdout
.write (self
.REDWHITE_BG
+
65 '%02d ' % self
.puzzle
.data
[row
][col
].numbered
+ self
.ENDCOL
)
68 if self
.puzzle
.data
[row
][col
].char
== "#":
69 sys
.stdout
.write (self
.BLACK_BG
+ ' ' + self
.ENDCOL
)
71 sys
.stdout
.write (self
.WHITE_BG
+ ' ' + self
.ENDCOL
)
72 # if the character is not a blank or a block
73 if (self
.puzzle
.data
[row
][col
].char
<> "." and
74 self
.puzzle
.data
[row
][col
].char
<> "#"):
75 # if words are to be shown regardless of hidden/revealed state
77 sys
.stdout
.write (self
.WHITE_BG
+
78 self
.puzzle
.data
[row
][col
].char
+ self
.ENDCOL
)
80 # display only revealed
81 if self
.puzzle
.data
[row
][col
].revealed
is True:
82 sys
.stdout
.write (self
.WHITE_BG
+
83 self
.puzzle
.data
[row
][col
].char
+ self
.ENDCOL
)
86 sys
.stdout
.write (self
.WHITE_BG
+ '.' + self
.ENDCOL
)
87 elif self
.puzzle
.data
[row
][col
].char
== '.':
88 sys
.stdout
.write (self
.WHITE_BG
+
89 self
.puzzle
.data
[row
][col
].char
+ self
.ENDCOL
)
90 elif self
.puzzle
.data
[row
][col
].char
== '#':
91 sys
.stdout
.write (self
.BLACK_BG
+ " " + self
.ENDCOL
)
93 sys
.stdout
.write (' ' + self
.BLUE
+ "%2d" % row
+ self
.ENDCOL
+ "\n")
94 raw_input (self
.BRICKRED
+ "Press <return> to continue" + self
.ENDCOL
)
96 # display existing clues
97 def on_display_clues (self
):
99 aclues
= self
.puzzle
.get_clues_across ()
100 sys
.stdout
.write (self
.BOLD
+ "\n------------\n")
101 sys
.stdout
.write ("Across words\n")
102 sys
.stdout
.write ("------------\n" + self
.ENDCOL
)
104 for word
, clue
in aclues
:
105 sys
.stdout
.write (self
.BOLD
+ word
[0] + ": " + self
.ENDCOL
)
107 sys
.stdout
.write (self
.BLUE
+ clue
+ "\n" + self
.ENDCOL
)
109 sys
.stdout
.write (self
.BLUE
+ "(No clue yet)\n" + self
.ENDCOL
)
110 except crosswordpuzzle
.NoWordsException
:
111 sys
.stderr
.write ("No words across\n")
114 dclues
= self
.puzzle
.get_clues_down ()
115 sys
.stdout
.write (self
.BOLD
+ "\n----------\n")
116 sys
.stdout
.write ("Down words\n")
117 sys
.stdout
.write ("----------\n" + self
.ENDCOL
)
119 for word
, clue
in dclues
:
120 sys
.stdout
.write (self
.BOLD
+ word
[0] + ": " + self
.ENDCOL
)
122 sys
.stdout
.write (self
.BLUE
+ clue
+ "\n" + self
.ENDCOL
)
124 sys
.stdout
.write (self
.BLUE
+ "(No clue yet)\n" + self
.ENDCOL
)
125 except crosswordpuzzle
.NoWordsException
:
126 sys
.stderr
.write ("No words down\n")
128 raw_input (self
.BRICKRED
+ "Press <return> to continue" + self
.ENDCOL
)
130 # set a clue to a word
131 def on_set_clue (self
):
133 # get the row and column
134 srow
= raw_input (self
.BRICKRED
+ "At row: " + self
.ENDCOL
)
135 scol
= raw_input (self
.BRICKRED
+ "At col: " + self
.ENDCOL
)
136 # try converting it to number
141 sys
.stderr
.write ("Invalid row or column\n")
145 # across word set the clue if found
146 aword
, arow
, acol
, alen
= self
.puzzle
.get_word_across (row
, col
)
147 sys
.stdout
.write (self
.BLUE
+ "Across word at position: " + aword
+ "\n" + self
.ENDCOL
)
148 clue
= raw_input (self
.BRICKRED
+ "Clue for across word: " + self
.ENDCOL
)
150 self
.puzzle
.data
[arow
][acol
].clue_across
= clue
151 sys
.stdout
.write (self
.BLUE
+ "Set clue: \n" + self
.puzzle
.data
[arow
][acol
].clue_across
)
152 except crosswordpuzzle
.NoWordException
:
153 sys
.stderr
.write ("No across word found at that position\n")
156 # down word set the clue if found
157 dword
, drow
, dcol
, dlen
= self
.puzzle
.get_word_down (row
, col
)
158 sys
.stdout
.write (self
.BLUE
+ "Down word at position: " + dword
+ "\n" + self
.ENDCOL
)
159 clue
= raw_input (self
.BRICKRED
+ "Clue for down word: " + self
.ENDCOL
)
161 self
.puzzle
.data
[drow
][dcol
].clue_down
= clue
162 sys
.stdout
.write (self
.BLUE
+ "Set clue: \n" + self
.puzzle
.data
[drow
][dcol
].clue_down
)
163 except crosswordpuzzle
.NoWordException
:
164 sys
.stderr
.write ("No down word found at that position\n")
166 # add a word to the puzzle
167 def on_add_word (self
, across
=True):
168 # first display the grid
170 # get the row and column
171 srow
= raw_input (self
.BRICKRED
+ "Start row: " + self
.ENDCOL
)
172 scol
= raw_input (self
.BRICKRED
+ "Start col: " + self
.ENDCOL
)
173 # try converting it to number
178 sys
.stderr
.write ("Invalid row or column\n")
181 word
= raw_input (self
.BRICKRED
+ "Word: " + self
.ENDCOL
)
183 # try to add the word to the puzzle grid
186 self
.puzzle
.set_word_across (row
, col
, word
)
188 self
.puzzle
.set_word_down (row
, col
, word
)
189 except crosswordpuzzle
.TooLongWordException
:
190 sys
.stderr
.write ("Word is too long to fit in the grid! Aborting.\n")
191 except crosswordpuzzle
.IntersectWordException
:
192 sys
.stderr
.write ("Word intersects badly with another word!\n")
193 except crosswordpuzzle
.FrozenGridException
:
194 sys
.stderr
.write ("Word cannot be added to a frozen puzzle.\n")
196 # Export to image/HTML
197 def on_export_image (self
, solution
=False):
199 sys
.stdout
.write (self
.BLUE
+ "Exporting puzzle to image/HTML\n")
200 filename
= raw_input (self
.BRICKRED
+ "Filename (PNG): " + self
.ENDCOL
)
202 self
.puzzle
.export_image (filename
, solution
)
203 sys
.stdout
.write (self
.BLUE
+ "Successfully exported to file: " +
204 filename
+ "\n" + self
.ENDCOL
)
206 except crosswordpuzzle
.FrozenGridException
:
207 sys
.stderr
.write ("Cannot export as grid is not frozen/finalized")
209 # Export to across lite
210 def on_export_acrosslite (self
):
212 sys
.stdout
.write (self
.BLUE
+ "Exporting to AcrossLite(tm) Format\n" +
214 title
= raw_input (self
.BRICKRED
+ "Puzzle title: " + self
.ENDCOL
)
215 name
= raw_input (self
.BRICKRED
+ "Author name: " + self
.ENDCOL
)
216 copyright
= raw_input (self
.BRICKRED
+ "Copyright: " + self
.ENDCOL
)
217 exportfile
= raw_input (self
.BRICKRED
+ "Export to file: " + self
.ENDCOL
)
219 acrosslite_str
= self
.puzzle
.export_acrosslite (title
, name
, copyright
)
220 fexport
= open (exportfile
, "w")
221 fexport
.write (acrosslite_str
)
223 sys
.stdout
.write (self
.BLUE
+ "Exported AcrossLite(tm) File: " +
224 exportfile
+ "\n" + self
.ENDCOL
)
225 except crosswordpuzzle
.FrozenGridException
:
226 sys
.stderr
.write ("Cannot export as grid is not frozen/finalized\n")
227 except crosswordpuzzle
.NoWordsException
:
228 sys
.stderr
.write ("No words to export!\n")
231 def do_puzzle_loop (self
):
232 # there is a current file
233 if self
.current_file
and self
.puzzle
:
235 sys
.stdout
.write (self
.BOLD
+ "\n-----------------------------------\n")
236 sys
.stdout
.write ("Puzzle: " + self
.current_file
+ "\n")
237 sys
.stdout
.write ("-----------------------------------" + self
.ENDCOL
+ "\n")
238 sys
.stdout
.write (self
.BLUE
+ "1. Display grid\n")
239 sys
.stdout
.write ("2. Add across word\n")
240 sys
.stdout
.write ("3. Add down word\n")
241 sys
.stdout
.write ("4. Remove across word\n")
242 sys
.stdout
.write ("5. Remove down word\n")
243 sys
.stdout
.write ("6. Freeze grid\n")
244 sys
.stdout
.write ("7. Unfreeze grid\n")
245 sys
.stdout
.write ("8. Set clue for word\n")
246 sys
.stdout
.write ("9. Display clues\n")
247 sys
.stdout
.write ("S. Save puzzle\n")
248 sys
.stdout
.write ("E. Export to AcrossLite(TM) format\n")
249 sys
.stdout
.write ("H. Export puzzle as image/HTML\n")
250 sys
.stdout
.write ("I. Export solution as image\n")
251 sys
.stdout
.write ("X. Exit to main menu\n" + self
.ENDCOL
)
252 ch
= raw_input (self
.BRICKRED
+ "Your choice: " + self
.ENDCOL
)
258 self
.on_add_word (False)
260 self
.puzzle
.freeze_grid ()
262 self
.puzzle
.unfreeze_grid ()
266 self
.on_display_clues ()
267 elif ch
== "S" or ch
== "s":
269 elif ch
== "E" or ch
== "e":
270 self
.on_export_acrosslite ()
271 elif ch
== "H" or ch
== "h":
272 self
.on_export_image ()
273 elif ch
== "I" or ch
== "i":
274 self
.on_export_image (True)
275 elif ch
== "X" or ch
== "x":
278 # when user chooses new puzzle
279 def on_new_puzzle (self
):
280 self
.current_file
= raw_input (self
.BRICKRED
+ "New puzzle file name: "
282 srows
= raw_input (self
.BRICKRED
+ "Number of rows: " + self
.ENDCOL
)
283 scols
= raw_input (self
.BRICKRED
+ "Number of cols: " + self
.ENDCOL
)
288 sys
.stderr
.write ("Invalid number of rows/columns")
290 self
.puzzle
= crosswordpuzzle
.CrosswordPuzzle (rows
, cols
)
291 self
.do_puzzle_loop ()
293 # when user chooses to load puzzle
294 def on_load_puzzle (self
):
295 self
.current_file
= raw_input (self
.BRICKRED
+ "Puzzle to load: "
298 self
.do_puzzle_loop ()
300 # Main application loop
301 def do_main_loop (self
):
304 sys
.stdout
.write (self
.BOLD
+ "\n-----------------------------------\n")
305 sys
.stdout
.write ("Get A Clue - Crossword Puzzle Maker\n")
306 sys
.stdout
.write ("-----------------------------------\n" + self
.ENDCOL
)
307 sys
.stdout
.write (self
.BLUE
+ "1. Start a new puzzle\n")
308 sys
.stdout
.write ("2. Open an existing puzzle\n")
309 sys
.stdout
.write ("X. Exit\n" + self
.ENDCOL
)
310 ch
= raw_input (self
.BRICKRED
+ "Your choice: " + self
.ENDCOL
)
312 self
.on_new_puzzle ()
314 self
.on_load_puzzle ()
315 if ch
== 'x' or ch
== 'X':