Fixed the exporter to use CRLF as newline character
[getaclue.git] / crosswordpuzzle.py
index 56807cd..694a766 100644 (file)
@@ -45,6 +45,16 @@ class FrozenGridException (Exception):
        def __init__ (self):
                self.msg = "Grid is frozen and cannot be edited"
 
        def __init__ (self):
                self.msg = "Grid is frozen and cannot be edited"
 
+# exception when no word is found at a position
+class NoWordException (Exception):
+       def __init__ (self, row, col):
+               self.pos = (row, col)
+
+# exception when no words are present in the grid
+class NoWordsException (Exception):
+       def __init__ (self):
+               self.msg = "No words in grid"
+
 class CrosswordPuzzle:
        def __init__ (self, rows, cols):
                # define number of rows and columns
 class CrosswordPuzzle:
        def __init__ (self, rows, cols):
                # define number of rows and columns
@@ -63,6 +73,154 @@ class CrosswordPuzzle:
                        for j in range (cols):
                                self.data[i].append (GridItem ())
 
                        for j in range (cols):
                                self.data[i].append (GridItem ())
 
+       # get the AcrossLite(TM) data for exporting
+       def export_acrosslite (self, title, author, copyright):
+               # don't export if grid is frozen
+               if self.frozen_grid is False:
+                       raise FrozenGridException
+
+               across_data = []
+               across_data.append ("<ACROSS PUZZLE>\r\n")
+               across_data.append ("<TITLE>\r\n")
+               across_data.append (title + "\r\n")
+               across_data.append ("<AUTHOR>\r\n")
+               across_data.append (author + "\r\n")
+               across_data.append ("<COPYRIGHT>\r\n")
+               across_data.append (copyright + "\r\n")
+               across_data.append ("<SIZE>\r\n")
+               str_size = str (self.cols) + "x" + str (self.rows)
+               across_data.append (str_size + "\r\n")
+               across_data.append ("<GRID>\r\n")
+               for row in range (self.rows):
+                       for col in range (self.cols):
+                               if (self.data[row][col].occupied_across is True or
+                                       self.data[row][col].occupied_down is True):
+                                       across_data.append (self.data[row][col].char)
+                               else:
+                                       across_data.append (".")
+                       across_data.append ("\r\n")
+
+               across_data.append ("<ACROSS>\r\n")
+               clues_across = self.get_clues_across ()
+               for word, clue in clues_across:
+                       if clue:
+                               across_data.append (clue + "\r\n")
+                       else:
+                               across_data.append ("(No clue yet)\r\n")
+
+               across_data.append ("<DOWN>\r\n")
+               clues_down = self.get_clues_down ()
+               for word, clue in clues_down:
+                       if clue:
+                               across_data.append (clue + "\r\n")
+                       else:
+                               across_data.append ("(No clue yet\r\n")
+
+               acrosslite_str = "".join (across_data)
+               return acrosslite_str
+
+       # get all the clues for across
+       def get_clues_across (self):
+               clues = []
+               # traverse the grid
+               for row in range (self.rows):
+                       for col in range (self.cols):
+                               if (self.data[row][col].occupied_across is True and
+                               self.data[row][col].across_start is True):
+                                       word_across = self.get_word_across (row, col)
+                                       clues.append ((word_across, self.data[row][col].clue_across))
+               # if no across words are found at all
+               if not clues:
+                       raise NoWordsException
+
+               return clues
+
+       # get all the clues for down
+       def get_clues_down (self):
+               clues = []
+               # traverse the grid
+               for row in range (self.rows):
+                       for col in range (self.cols):
+                               if (self.data[row][col].occupied_down is True and
+                               self.data[row][col].down_start is True):
+                                       word_down = self.get_word_down (row, col)
+                                       clues.append ((word_down, self.data[row][col].clue_down))
+               # if no down words are found at all
+               if not clues:
+                       raise NoWordsException
+
+               return clues
+
+       # getting a down word at a position
+       def get_word_down (self, row, col):
+               # if index is out of bounds
+               if row >= self.rows or col >= self.cols:
+                       raise NoWordException (row, col)
+
+               # if there is no occupied down letter at that position
+               if self.data[row][col].occupied_down is False:
+                       raise NoWordException (row, col)
+
+               # now traverse the grid to find the beginning of the word
+               i = row
+               while i >= 0:
+                       # if it is occupied down and is the beginning of the word
+                       if (self.data[i][col].occupied_down is True and
+                               self.data[i][col].down_start is True):
+                               start_row = i
+                               break
+                       i -= 1
+
+               i = start_row
+               word_chars = []
+               # now seek the end of the word
+               while i < self.rows:
+                       if self.data[i][col].occupied_down is True:
+                               word_chars.append (self.data[i][col].char)
+                       else:
+                               break
+                       i += 1
+
+               word = "".join (word_chars)
+
+               # return the word, starting row, column and length as a tuple
+               return (word, start_row, col, len(word))
+
+       # getting an across word at a position
+       def get_word_across (self, row, col):
+               # if index is out of bounds
+               if row >= self.rows or col >= self.cols:
+                       raise NoWordException (row, col)
+
+               # if there is no occupied across letter at that position
+               if self.data[row][col].occupied_across is False:
+                       raise NoWordException (row, col)
+
+               # now traverse the grid to look for the beginning of the word
+               i = col
+               while i >= 0:
+                       # if it is occupied across and is the beginning of the word
+                       if (self.data[row][i].occupied_across is True and
+                               self.data[row][i].across_start is True):
+                               start_col = i
+                               break
+                       i -= 1
+
+               i = start_col
+               word_chars = []
+               # now seek the end of the word
+               while i < self.cols:
+                       if self.data[row][i].occupied_across is True:
+                               word_chars.append (self.data[row][i].char)
+                       else:
+                               break
+                       i += 1
+
+               word = "".join (word_chars)
+
+               # return the word, starting column, row and length as a tuple
+               return (word, row, start_col, len(word))
+
        # setting a down word
        def set_word_down (self, row, col, word):
                # if the grid is frozen the abort
        # setting a down word
        def set_word_down (self, row, col, word):
                # if the grid is frozen the abort