From 85159420b6ed652a259484b3cf192f602d9418c0 Mon Sep 17 00:00:00 2001 From: Harishankar Date: Sat, 4 Dec 2010 14:42:43 +0530 Subject: [PATCH] First commit This is the first commit. Beginning of the menus and functionality --- .gitignore | 1 + crosswordpuzzle.py | 210 ++++++++++++++++++++++++++++++++++++++ crosswordpuzzlecreator.py | 113 ++++++++++++++++++++ getaclue | 15 +++ 4 files changed, 339 insertions(+) create mode 100644 .gitignore create mode 100644 crosswordpuzzle.py create mode 100644 crosswordpuzzlecreator.py create mode 100755 getaclue diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/crosswordpuzzle.py b/crosswordpuzzle.py new file mode 100644 index 0000000..c1f822b --- /dev/null +++ b/crosswordpuzzle.py @@ -0,0 +1,210 @@ +# Get A Clue (C) 2010 V. Harishankar +# Crossword puzzle maker program +# Licensed under the GNU GPL v3 + +# Class for the puzzle data representation + +class GridItem: + # initialize the item + def __init__ (self, item_char='.', across_start = False, down_start = False, + occupied_across = False, occupied_down = False, num = 0, + clue_across = None, clue_down = None, revealed = False): + # character in the cell + self.char = item_char + # is the cell the start of an across word? + self.across_start = across_start + # is the cell the start of a down word? + self.down_start = down_start + # is the cell occupied by a letter in an across word? + self.occupied_across = occupied_across + # is the cell occupied by a letter in a down word? + self.occupied_down = occupied_down + # numbering of the cell if it is the start of a word + self.numbered = num + # clue across if the cell is the start of an across word + self.clue_across = clue_across + # clue down if the cell is the start of a down word + self.clue_down = clue_down + # is the letter revealed or hidden? + self.revealed = revealed + +# exception for too long words +class TooLongWordException (Exception): + def __init__ (self, word, length): + self.word = word + self.length = length + +# exception for intersecting words +class IntersectWordException (Exception): + def __init__ (self, word, length): + self.word = word + self.length = length + +# exception when grid is sought to be changed when frozen +class FrozenGridException (Exception): + def __init__ (self): + self.msg = "Grid is frozen and cannot be edited" + +class CrosswordPuzzle: + # ansi color codes for grid display + BRICKRED = '\033[44;1;31m' + # bold + BOLD = '\033[33m' + # blue + BLUE = '\033[34m' + # grey + GREY = '\033[30m' + # disable colors + ENDCOL = '\033[0m' + + def __init__ (self, rows, cols): + # define number of rows and columns + self.rows = rows + self.cols = cols + + # initialize the list to hold the grid + self.data = [] + + # initial state of the grid is unfrozen + self.frozen_grid = False + + # create the grid data + for i in range (rows): + self.data.append ([]) + for j in range (cols): + self.data[i].append (GridItem ()) + + # setting a down word + def set_word_down (self, row, col, word): + # if the grid is frozen the abort + if self.frozen_grid is True: + raise FrozenGridException + + # if the word length greater than totalrows - startrow + if len(word) > self.rows - row: + raise TooLongWordException (word, len(word)) + + # is the word intersecting any other word? + for i in range (len(word)): + # on the same column + if self.data[row+i][col].occupied_down is True: + raise IntersectWordException (word, len(word)) + # on the previous column + if col > 0 and self.data[row+i][col-1].occupied_down is True: + raise IntersectWordException (word, len(word)) + # on the next column + if (col < (len(word) - 1) and + (self.data[row+i][col+1].occupied_down is True or + self.data[row+i][col+1].across_start is True)): + raise IntersectWordException (word, len(word)) + + # also check the character before and after + if (row > 0 and self.data[row-1][col].occupied_down is True + and self.data[row-1][col].occupied_across is True): + raise IntersectWordException (word, len(word)) + if (row + len(word) < self.rows and + self.data[row+len(word)][col].occupied_across is True and + self.data[row+len(word)][col].occupied_down is True): + raise IntersectWordException (word, len(word)) + + # set the down start to true + self.data[row][col].down_start = True + # set the word + for i in range (len(word)): + self.data[row+i][col].occupied_down = True + self.data[row+i][col].char = word[i].upper () + + + # setting an across word + def set_word_across (self, row, col, word): + # if the grid is frozen the abort + if self.frozen_grid is True: + raise FrozenGridException + + # is the word length greater than totalcols - startcol? + if len(word) > self.cols - col: + raise TooLongWordException (word, len(word)) + + # is the word intersecting any other word? + for i in range (len(word)): + # on the same line + if self.data[row][col+i].occupied_across is True: + raise IntersectWordException (word, len(word)) + # on a previous line except the last column + if row > 0 and self.data[row-1][col+i].occupied_across is True: + raise IntersectWordException (word, len(word)) + # on a next line except the last column + if (row < (self.rows - 1) and + (self.data[row+1][col+i].down_start is True + or self.data[row+1][col+i].occupied_across is True)): + raise IntersectWordException (word, len(word)) + + # also check the character beyond and before and after + if (col > 0 and (self.data[row][col-1].occupied_across is True or + self.data[row][col-1].occupied_down is True)): + raise IntersectWordException (word, len(word)) + if (col + len(word) < self.cols and + (self.data[row][col+len(word)].occupied_across is True or + self.data[row][col+len(word)].occupied_down is True)): + raise IntersectWordException (word, len(word)) + + # set across start to true + self.data[row][col].across_start = True + + # set the word + for i in range (len(word)): + self.data[row][col+i].char = word[i].upper () + self.data[row][col+i].occupied_across = True + + # display the grid with words + def print_grid (self, no_words=False): + # get row, col and print them (with grid number if set) + for col in range (self.cols): + # print the first row as column headers + print self.BLUE + ' ' + str (col) + self.ENDCOL, + print + + for row in range (self.rows): + for col in range (self.cols): + # print the data + # if the cell is numbered i.e. start of a word + if self.data[row][col].numbered != 0: + print self.BRICKRED + str(self.data[row][col].numbered) + self.ENDCOL, + # print a space + else: + print ' ', + # if the character is not a blank or a block + if self.data[row][col].char <> "." and self.data[row][col].char <> "#": + # if words are to be shown regardless of hidden/revealed state + if no_words is False: + print self.BOLD + self.data[row][col].char + self.ENDCOL, + else: + # display only revealed + if self.data[row][col].revealed is True: + print self.BOLD + self.data[row][col].char + self.ENDCOL, + # else print a block + else: + print self.GREY + '.' + self.ENDCOL, + else: + print self.GREY + self.data[row][col].char + self.ENDCOL, + + print ' ' + self.BLUE + str(row) + self.ENDCOL + + # freeze the grid numbers etc. + def freeze_grid (self): + # numbering + numbering = 1 + # run through the grid + for row in range (self.rows): + for col in range (self.cols): + # if grid is blank set the character to # + if (self.data[row][col].occupied_across is False + and self.data[row][col].occupied_down is False): + self.data[row][col].char = "#" + elif (self.data[row][col].across_start is True or + self.data[row][col].down_start is True): + self.data[row][col].numbered = numbering + numbering += 1 + + self.frozen_grid = True + diff --git a/crosswordpuzzlecreator.py b/crosswordpuzzlecreator.py new file mode 100644 index 0000000..ae1f8ca --- /dev/null +++ b/crosswordpuzzlecreator.py @@ -0,0 +1,113 @@ +# Get A Clue (C) 2010 V. Harishankar +# Crossword puzzle maker program +# Licensed under the GNU GPL v3 + +# Cross puzzle creator class + +import crosswordpuzzle + +class CrosswordPuzzleCreator: + # ansi color codes for grid display + BRICKRED = '\033[31m' + # bold + BOLD = '\033[33m' + # blue + BLUE = '\033[34m' + # grey + GREY = '\033[30m' + # disable colors + ENDCOL = '\033[0m' + + def __init__ (self): + self.do_main_loop () + self.current_file = None + self.puzzle = None + + # display the grid with words + def print_puzzle (self, no_words=False): + # if self.puzzle is not none + if self.puzzle: + # get row, col and print them (with grid number if set) + for col in range (self.puzzle.cols): + # print the first row as column headers + print self.BLUE + ' ' + str (col) + self.ENDCOL, + print + + for row in range (self.puzzle.rows): + for col in range (self.puzzle.cols): + # print the data + # if the cell is numbered i.e. start of a word + if self.puzzle.data[row][col].numbered != 0: + print self.BRICKRED + str(self.puzzle.data[row][col].numbered) + self.ENDCOL, + # print a space + else: + print ' ', + # if the character is not a blank or a block + if self.puzzle.data[row][col].char <> "." and self.puzzle.data[row][col].char <> "#": + # if words are to be shown regardless of hidden/revealed state + if no_words is False: + print self.BOLD + self.puzzle.data[row][col].char + self.ENDCOL, + else: + # display only revealed + if self.puzzle.data[row][col].revealed is True: + print self.BOLD + self.puzzle.data[row][col].char + self.ENDCOL, + # else print a block + else: + print self.GREY + '.' + self.ENDCOL, + else: + print self.GREY + self.puzzle.data[row][col].char + self.ENDCOL, + + print ' ' + self.BLUE + str(row) + self.ENDCOL + raw_input (self.GREY + "Press to continue" + self.ENDCOL) + + # Puzzle loop + def do_puzzle_loop (self): + # there is a current file + while True: + if self.current_file and self.puzzle: + print self.BOLD + "-----------------------------------" + print "Puzzle: " + self.current_file + print "-----------------------------------" + self.ENDCOL + print self.BLUE + "1. Display grid" + print "2. Add across word" + print "3. Add down word" + print "4. Freeze grid" + print "5. Unfreeze grid" + print "6. Save puzzle" + print "X. Exit to main menu" + self.ENDCOL + ch = raw_input (self.BRICKRED + "Your choice: " + self.ENDCOL) + if ch == "1": + self.print_puzzle () + elif ch == "X" or ch == "x": + break + + # when user chooses new puzzle + def on_new_puzzle (self): + self.current_file = raw_input ("New puzzle file name: ") + srows = raw_input ("Number of rows: ") + scols = raw_input ("Number of cols: ") + try: + rows = int (srows) + cols = int (scols) + except ValueError: + print "Invalid number of rows/columns" + return + self.puzzle = crosswordpuzzle.CrosswordPuzzle (rows, cols) + self.do_puzzle_loop () + + # Main application loop + def do_main_loop (self): + # display the menu + while True: + print + print self.BOLD + "-----------------------------------" + print "Get A Clue - Crossword Puzzle Maker" + print "-----------------------------------" + self.ENDCOL + print self.BLUE + "1. Start a new puzzle" + print "2. Open an existing puzzle" + print "X. Exit" + self.ENDCOL + ch = raw_input (self.BRICKRED + "Your choice: " + self.ENDCOL) + if ch == '1': + self.on_new_puzzle () + if ch == 'x' or ch == 'X': + break diff --git a/getaclue b/getaclue new file mode 100755 index 0000000..f950a89 --- /dev/null +++ b/getaclue @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +# Get A Clue (C) 2010 V. Harishankar +# Crossword puzzle maker program +# Licensed under the GNU GPL v3 + +# Main script + +import crosswordpuzzlecreator + +def main (): + app = crosswordpuzzlecreator.CrosswordPuzzleCreator () + +if __name__=="__main__": + main () -- 2.20.1