Skip to content
This repository has been archived by the owner on Feb 12, 2018. It is now read-only.

Commit

Permalink
crossword solver moved to repo
Browse files Browse the repository at this point in the history
  • Loading branch information
jtorgan committed Dec 6, 2012
1 parent 395e308 commit 6131a64
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 0 deletions.
44 changes: 44 additions & 0 deletions torgan/AbstractGrid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from Word import Word

class AbstractGrid:
""" Presents structure of a grid, contains lists of horizontal and vertical words without words"""
def __init__(self):
self.horizontal_words = []
self.vertical_words = []

def __extract_words_coordinates(self, list):
words_coordinates = []
j = 0 # index of current cell
length = len(list)
while j < length:
while j < length and list[j] == '_':
j += 1
if j != length:
x1 = j
while j < length and list[j] == '*':
j += 1
x2 = j - 1
if x2 - x1 > 1:
words_coordinates.append((x1, x2))
return words_coordinates

def parse_matrix(self, matrix):
for i in xrange(len(matrix)):
words_coordinates = self.__extract_words_coordinates(matrix[i])
for (x1, x2) in words_coordinates:
self.horizontal_words.append(Word(i, x1, x2))
for j in xrange(len(matrix[0])):
vertical_list = [list[j] for list in matrix]
words_coordinates = self.__extract_words_coordinates(vertical_list)
for (y1, y2) in words_coordinates:
self.vertical_words.append(Word(j, y1, y2))
self.__build_tree(self.horizontal_words[0], False)

def __build_tree(self, parent, is_vertical):
parent.flag = 1
cross_list = self.horizontal_words if is_vertical else self.vertical_words
for cross in cross_list:
if cross.flag != 1 and parent.check_cross(cross):
parent.children.append(self.__build_tree(cross, not is_vertical))
return parent

46 changes: 46 additions & 0 deletions torgan/Crossword.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from AbstractGrid import AbstractGrid

class Crossword(AbstractGrid):
""" Class extends empty abstract grid with ability to work with input dictionary words"""

def fill_with_words(self, word_list):
return self.__dfs(self.horizontal_words[0], word_list)

def __validate_grid(self):
for word in self.horizontal_words:
for cross in self.vertical_words:
if word.check_cross(cross):
if cross.value is not None and word.value is not None and not word.check_cross_value(cross):
return False
return True

def __dfs(self, root, available_dict):
copied_dict = available_dict[0:]
is_right = False

for word in root.get_right_words(available_dict):
root.value = word
if self.__validate_grid():
is_right = True
copied_dict.remove(word)
for child in root.children:
is_right &= self.__dfs(child, copied_dict)
filled_words = self.__get_filled_words(child)
copied_dict = [item for item in copied_dict if item not in filled_words]
if is_right:
return True
else:
copied_dict.extend(self.__get_filled_words(root))
self.__clean_up(root)
return is_right

def __clean_up(self, root):
root.value = None
for child in root.children:
self.__clean_up(child)

def __get_filled_words(self, root):
values = [root.value] if root.value is not None else []
for child in root.children:
values.extend(self.__get_filled_words(child))
return values
41 changes: 41 additions & 0 deletions torgan/Main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from Crossword import Crossword

file = open("grid.txt")
input_grid = []
for line in file.readlines():
input_grid.append(line.split())
file.close()

file = open("dict.txt")
input_dict = []
for line in file.readlines():
input_dict.extend(line.split())
file.close()

# TODO: add exception handling for: working with files, validate input - grid's format

crossword = Crossword()
crossword.parse_matrix(input_grid)
is_right = crossword.fill_with_words(input_dict)

if is_right:
for word in crossword.horizontal_words:
if word.value is not None:
input_grid[word.item][word.start : word.end + 1] = word.value
for word in crossword.vertical_words:
if word.value is not None:
for line in input_grid:
if word.start <= input_grid.index(line) <= word.end:
line[word.item] = word.value[input_grid.index(line) - word.start]
for line in input_grid:
print line
else:
print "Error! Can not fill crossword with that dictionary!"








25 changes: 25 additions & 0 deletions torgan/Word.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Word:
"""
Presents structure of a grid's word
item - row(or column) at the grid
start, end - start and end coordinates at row(column)
"""
def __init__(self, item, start, end):
self.item = item
self.start = start
self.end = end
self.value = None
self.children = []
self.flag = 0 # ony for building tree

def check_cross_value(self, word):
if self.check_cross(word) :
return self.value[word.item - self.start] == word.value[self.item - word.start]
return True

def check_cross(self, word):
return word.start <= self.item <= word.end and self.start <= word.item <= self.end

def get_right_words(self, word_list):
result = [word for word in word_list if len(word) == self.end - self.start + 1]
return result
78 changes: 78 additions & 0 deletions torgan/dict.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
also
nip
ussr
mohr
parus
fete
odin
stoma
oman
revisionary
itt
ted
aery
ethnic
phloem
axe
tulsa
plaid
nash
miens
erne
acted
fails
leg
tariff
coneys
mana
gun
ode
tridiagonal
tins
adorn
ucla
into
dotes
gamy
sass
les
haas
amor
ana
otis
lode
exact
dina
shiv
testaments
ornith
hera
sos
sent
dint
psidium
farad
nato
cliff
idol
iron
sea
dote
puma
panic
ires
sarah
slogans
yelp
snug
ufo
role
enough
semiyearly
ncaa
stat
mines
alma
rent
deg
lays
15 changes: 15 additions & 0 deletions torgan/grid.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
* * * * _ _ * * * _ _ * * * *
* * * * _ * * * * * _ * * * *
* * * * _ * * * * * _ * * * *
* * * * * * * * * * * _ * * *
_ _ _ * * * _ _ _ * * * * _ _
_ * * * * * * _ * * * * * * _
* * * _ * * * * * _ * * * * *
* * * * _ * * * * * _ * * * *
* * * * * _ * * * * * _ * * *
_ * * * * * * _ * * * * * * _
_ _ * * * * _ _ _ * * * _ _ _
* * * _ * * * * * * * * * * *
* * * * _ * * * * * _ * * * *
* * * * _ * * * * * _ * * * *
* * * * _ _ * * * _ _ * * * *

0 comments on commit 6131a64

Please sign in to comment.