Clues can now be entered for words
[getaclue.git] / crosswordpuzzlecreator.py
1 # Get A Clue (C) 2010 V. Harishankar
2 # Crossword puzzle maker program
3 # Licensed under the GNU GPL v3
4
5 # Cross puzzle creator class
6 import sys
7
8 import crosswordpuzzle
9
10 class CrosswordPuzzleCreator:
11 # ansi color codes for grid display
12 BRICKRED = '\033[31m'
13 # bold
14 BOLD = '\033[33m'
15 # blue
16 BLUE = '\033[34m'
17 # grey
18 GREY = '\033[30m'
19 # Black background white text
20 BLACK_BG = '\033[40;1;37m'
21 # white background black text
22 WHITE_BG = '\033[47;1;30m'
23 # white background red text
24 REDWHITE_BG = '\033[47;1;31m'
25 # disable colors
26 ENDCOL = '\033[0m'
27
28 def __init__ (self):
29 self.do_main_loop ()
30 self.current_file = None
31 self.puzzle = None
32
33 # display the grid with words
34 def print_puzzle (self, no_words=False):
35 # if self.puzzle is not none
36 if self.puzzle:
37 # get row, col and print them (with grid number if set)
38 for col in range (self.puzzle.cols):
39 # print the first row as column headers
40 sys.stdout.write (self.BLUE + ' %02d' % col + self.ENDCOL)
41 sys.stdout.write ("\n")
42
43 for row in range (self.puzzle.rows):
44 for col in range (self.puzzle.cols):
45 # print the data
46 # if the cell is numbered i.e. start of a word
47 if self.puzzle.data[row][col].numbered != 0:
48 sys.stdout.write (self.REDWHITE_BG +
49 '%02d ' % self.puzzle.data[row][col].numbered + self.ENDCOL)
50 # print spaces
51 else:
52 if self.puzzle.data[row][col].char == "#":
53 sys.stdout.write (self.BLACK_BG + ' ' + self.ENDCOL)
54 else:
55 sys.stdout.write (self.WHITE_BG + ' ' + self.ENDCOL)
56 # if the character is not a blank or a block
57 if (self.puzzle.data[row][col].char <> "." and
58 self.puzzle.data[row][col].char <> "#"):
59 # if words are to be shown regardless of hidden/revealed state
60 if no_words is False:
61 sys.stdout.write (self.WHITE_BG +
62 self.puzzle.data[row][col].char + self.ENDCOL)
63 else:
64 # display only revealed
65 if self.puzzle.data[row][col].revealed is True:
66 sys.stdout.write (self.WHITE_BG +
67 self.puzzle.data[row][col].char + self.ENDCOL)
68 # else print a blank
69 else:
70 sys.stdout.write (self.WHITE_BG + '.' + self.ENDCOL)
71 elif self.puzzle.data[row][col].char == '.':
72 sys.stdout.write (self.WHITE_BG +
73 self.puzzle.data[row][col].char + self.ENDCOL)
74 elif self.puzzle.data[row][col].char == '#':
75 sys.stdout.write (self.BLACK_BG + " " + self.ENDCOL)
76
77 sys.stdout.write (' ' + self.BLUE + "%2d" % row + self.ENDCOL + "\n")
78 raw_input (self.BRICKRED + "Press <return> to continue" + self.ENDCOL)
79
80 # set a clue to a word
81 def set_clue (self):
82 self.print_puzzle ()
83 # get the row and column
84 srow = raw_input (self.BRICKRED + "At row: " + self.ENDCOL)
85 scol = raw_input (self.BRICKRED + "At col: " + self.ENDCOL)
86 # try converting it to number
87 try:
88 row = int (srow)
89 col = int (scol)
90 except ValueError:
91 sys.stderr.write ("Invalid row or column\n")
92 return
93
94 try:
95 aword, arow, acol, alen = self.puzzle.get_word_across (row, col)
96 sys.stdout.write (self.BLUE + "Word at position: " + aword + "\n" + self.ENDCOL)
97 clue = raw_input (self.BRICKRED + "Clue for word: " + self.ENDCOL)
98 if clue:
99 self.puzzle.data[arow][acol].clue_across = clue
100 sys.stdout.write (self.BLUE + "Set clue: \n" + self.puzzle.data[arow][acol].clue_across)
101 except crosswordpuzzle.NoWordException:
102 sys.stderr.write ("No across word found at that position")
103
104 # add a word to the puzzle
105 def add_word (self, across=True):
106 # first display the grid
107 self.print_puzzle ()
108 # get the row and column
109 srow = raw_input (self.BRICKRED + "Start row: " + self.ENDCOL)
110 scol = raw_input (self.BRICKRED + "Start col: " + self.ENDCOL)
111 # try converting it to number
112 try:
113 row = int (srow)
114 col = int (scol)
115 except ValueError:
116 sys.stderr.write ("Invalid row or column\n")
117 return
118 # get the word
119 word = raw_input (self.BRICKRED + "Word: " + self.ENDCOL)
120
121 # try to add the word to the puzzle grid
122 try:
123 if across == True:
124 self.puzzle.set_word_across (row, col, word)
125 else:
126 self.puzzle.set_word_down (row, col, word)
127 except crosswordpuzzle.TooLongWordException:
128 sys.stderr.write ("Word is too long to fit in the grid! Aborting.\n")
129 except crosswordpuzzle.IntersectWordException:
130 sys.stderr.write ("Word intersects badly with another word!\n")
131 except crosswordpuzzle.FrozenGridException:
132 sys.stderr.write ("Word cannot be added to a frozen puzzle.\n")
133
134 # Puzzle loop
135 def do_puzzle_loop (self):
136 # there is a current file
137 while True:
138 if self.current_file and self.puzzle:
139 sys.stdout.write (self.BOLD + "\n-----------------------------------\n")
140 sys.stdout.write ("Puzzle: " + self.current_file + "\n")
141 sys.stdout.write ("-----------------------------------" + self.ENDCOL + "\n")
142 sys.stdout.write (self.BLUE + "1. Display grid\n")
143 sys.stdout.write ("2. Add across word\n")
144 sys.stdout.write ("3. Add down word\n")
145 sys.stdout.write ("4. Remove across word\n")
146 sys.stdout.write ("5. Remove down word\n")
147 sys.stdout.write ("6. Freeze grid\n")
148 sys.stdout.write ("7. Unfreeze grid\n")
149 sys.stdout.write ("8. Set clue for word\n")
150 sys.stdout.write ("S. Save puzzle\n")
151 sys.stdout.write ("X. Exit to main menu\n" + self.ENDCOL)
152 ch = raw_input (self.BRICKRED + "Your choice: " + self.ENDCOL)
153 if ch == "1":
154 self.print_puzzle ()
155 elif ch == "2":
156 self.add_word ()
157 elif ch == "3":
158 self.add_word (False)
159 elif ch == "6":
160 self.puzzle.freeze_grid ()
161 elif ch == "7":
162 self.puzzle.unfreeze_grid ()
163 elif ch == "8":
164 self.set_clue ()
165 elif ch == "X" or ch == "x":
166 break
167
168 # when user chooses new puzzle
169 def on_new_puzzle (self):
170 self.current_file = raw_input (self.BRICKRED + "New puzzle file name: "
171 + self.ENDCOL)
172 srows = raw_input (self.BRICKRED + "Number of rows: " + self.ENDCOL)
173 scols = raw_input (self.BRICKRED + "Number of cols: " + self.ENDCOL)
174 try:
175 rows = int (srows)
176 cols = int (scols)
177 except ValueError:
178 sys.stderr.write ("Invalid number of rows/columns")
179 return
180 self.puzzle = crosswordpuzzle.CrosswordPuzzle (rows, cols)
181 self.do_puzzle_loop ()
182
183 # Main application loop
184 def do_main_loop (self):
185 # display the menu
186 while True:
187 sys.stdout.write (self.BOLD + "\n-----------------------------------\n")
188 sys.stdout.write ("Get A Clue - Crossword Puzzle Maker\n")
189 sys.stdout.write ("-----------------------------------\n" + self.ENDCOL)
190 sys.stdout.write (self.BLUE + "1. Start a new puzzle\n")
191 sys.stdout.write ("2. Open an existing puzzle\n")
192 sys.stdout.write ("X. Exit\n" + self.ENDCOL)
193 ch = raw_input (self.BRICKRED + "Your choice: " + self.ENDCOL)
194 if ch == '1':
195 self.on_new_puzzle ()
196 if ch == 'x' or ch == 'X':
197 break