Made some logic changes to word intersection code
[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 # add a word to the puzzle
81 def add_word (self, across=True):
82 # first display the grid
83 self.print_puzzle ()
84 # get the row and column
85 srow = raw_input (self.BRICKRED + "Start row: " + self.ENDCOL)
86 scol = raw_input (self.BRICKRED + "Start col: " + self.ENDCOL)
87 # try converting it to number
88 try:
89 row = int (srow)
90 col = int (scol)
91 except ValueError:
92 sys.stderr.write ("Invalid row or column\n")
93 return
94 # get the word
95 word = raw_input (self.BRICKRED + "Word: " + self.ENDCOL)
96
97 # try to add the word to the puzzle grid
98 try:
99 if across == True:
100 self.puzzle.set_word_across (row, col, word)
101 else:
102 self.puzzle.set_word_down (row, col, word)
103 except crosswordpuzzle.TooLongWordException:
104 sys.stderr.write ("Word is too long to fit in the grid! Aborting.\n")
105 except crosswordpuzzle.IntersectWordException:
106 sys.stderr.write ("Word intersects badly with another word!\n")
107 except crosswordpuzzle.FrozenGridException:
108 sys.stderr.write ("Word cannot be added to a frozen puzzle.\n")
109
110 # Puzzle loop
111 def do_puzzle_loop (self):
112 # there is a current file
113 while True:
114 if self.current_file and self.puzzle:
115 sys.stdout.write (self.BOLD + "\n-----------------------------------\n")
116 sys.stdout.write ("Puzzle: " + self.current_file + "\n")
117 sys.stdout.write ("-----------------------------------" + self.ENDCOL + "\n")
118 sys.stdout.write (self.BLUE + "1. Display grid\n")
119 sys.stdout.write ("2. Add across word\n")
120 sys.stdout.write ("3. Add down word\n")
121 sys.stdout.write ("4. Remove across word\n")
122 sys.stdout.write ("5. Remove down word\n")
123 sys.stdout.write ("6. Freeze grid\n")
124 sys.stdout.write ("7. Unfreeze grid\n")
125 sys.stdout.write ("8. Set a clue\n")
126 sys.stdout.write ("9. Remove clue\n")
127 sys.stdout.write ("S. Save puzzle\n")
128 sys.stdout.write ("X. Exit to main menu\n" + self.ENDCOL)
129 ch = raw_input (self.BRICKRED + "Your choice: " + self.ENDCOL)
130 if ch == "1":
131 self.print_puzzle ()
132 elif ch == "2":
133 self.add_word ()
134 elif ch == "3":
135 self.add_word (False)
136 elif ch == "6":
137 self.puzzle.freeze_grid ()
138 elif ch == "7":
139 self.puzzle.unfreeze_grid ()
140 elif ch == "X" or ch == "x":
141 break
142
143 # when user chooses new puzzle
144 def on_new_puzzle (self):
145 self.current_file = raw_input (self.BRICKRED + "New puzzle file name: "
146 + self.ENDCOL)
147 srows = raw_input (self.BRICKRED + "Number of rows: " + self.ENDCOL)
148 scols = raw_input (self.BRICKRED + "Number of cols: " + self.ENDCOL)
149 try:
150 rows = int (srows)
151 cols = int (scols)
152 except ValueError:
153 sys.stderr.write ("Invalid number of rows/columns")
154 return
155 self.puzzle = crosswordpuzzle.CrosswordPuzzle (rows, cols)
156 self.do_puzzle_loop ()
157
158 # Main application loop
159 def do_main_loop (self):
160 # display the menu
161 while True:
162 sys.stdout.write (self.BOLD + "\n-----------------------------------\n")
163 sys.stdout.write ("Get A Clue - Crossword Puzzle Maker\n")
164 sys.stdout.write ("-----------------------------------\n" + self.ENDCOL)
165 sys.stdout.write (self.BLUE + "1. Start a new puzzle\n")
166 sys.stdout.write ("2. Open an existing puzzle\n")
167 sys.stdout.write ("X. Exit\n" + self.ENDCOL)
168 ch = raw_input (self.BRICKRED + "Your choice: " + self.ENDCOL)
169 if ch == '1':
170 self.on_new_puzzle ()
171 if ch == 'x' or ch == 'X':
172 break