main.py 4.19 KB
Newer Older
Brady James Garvin's avatar
Brady James Garvin committed
1
from kivy.app import App
2
from kivy.uix.boxlayout import BoxLayout
Brady James Garvin's avatar
Brady James Garvin committed
3
from kivy.uix.floatlayout import FloatLayout
4
from kivy.uix.gridlayout import GridLayout
Brady James Garvin's avatar
Brady James Garvin committed
5
from kivy.uix.label import Label
6
from kivy.properties import NumericProperty, StringProperty, ListProperty
Brady James Garvin's avatar
Brady James Garvin committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from kivy.modules import inspector
from kivy.core.window import Window


class Crossword:
    def __init__(self, characters, clues):
        self.characters = characters
        self.size = len(characters)
        self.clues = clues

    def __getitem__(self, coordinates):
        row, column = coordinates
        try:
            return self.characters[row][column]
        except IndexError:
            return None

24
    def _get_clue_text(self, start_row, start_column, row_step, column_step):
Brady James Garvin's avatar
Brady James Garvin committed
25
26
27
28
29
30
31
32
        word = ''
        row, column = start_row, start_column
        while self[row, column] is not None:
            word += self[row, column]
            row += row_step
            column += column_step
        return self.clues.get(word)

33
34
    def get_across_clue_text(self, row, column):
        return self._get_clue_text(row, column, 0, 1)
Brady James Garvin's avatar
Brady James Garvin committed
35

36
37
    def get_down_clue_text(self, row, column):
        return self._get_clue_text(row, column, 1, 0)
Brady James Garvin's avatar
Brady James Garvin committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


CROSSWORD = Crossword((
    (None, None, None, None, None, None),
    (None, 'B', 'U', 'G', 'S', None),
    (None, 'U', 'N', 'I', 'T', None),
    (None, 'G', 'I', 'V', 'E', None),
    (None, 'S', 'T', 'E', 'M', None),
    (None, None, None, None, None, None),
), {
    'BUGS': 'Informal name for software faults',
    'UNIT': 'Very traceable software testing',
    'GIVE': 'To make a present of something',
    'STEM': 'Group of disciplines including SE',
})


class BoxLabel(Label):
    pass


class Box(FloatLayout):
    number = NumericProperty(None, allownone=True)
    character = StringProperty(None, allownone=True)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class Grid(GridLayout):
    cells = ListProperty([])  # elements have the shape (number, character)

    def rebuild(self):
        self.clear_widgets()
        for number, character in self.cells:
            self.add_widget(Box(number=number, character=character))

    def on_cells(self, _, __):
        self.rebuild()


class Heading(Label):
    pass


Brady James Garvin's avatar
Brady James Garvin committed
80
81
class Clue(Label):
    number = NumericProperty(0)
82
83
84
85
86
87
88
89
90
91
92
93
94
    clue_text = StringProperty('')


class Clues(BoxLayout):
    clues = ListProperty([])  # elements have the shape (number, clue text)

    def rebuild(self):
        self.clear_widgets()
        for number, clue_text in self.clues:
            self.add_widget(Clue(number=number, clue_text=clue_text))

    def on_clues(self, _, __):
        self.rebuild()
Brady James Garvin's avatar
Brady James Garvin committed
95
96
97


class CrosswordApp(App):
98
99
100
101
102
103
    row_count = NumericProperty(0)
    cells = ListProperty([])

    across_clues = ListProperty([])
    down_clues = ListProperty([])

Brady James Garvin's avatar
Brady James Garvin committed
104
105
106
    def build(self):
        inspector.create_inspector(Window, self)

107
108
109
110
111
    def display(self, crossword):
        self.row_count = crossword.size
        across_clues = []
        down_clues = []
        cells = []
Brady James Garvin's avatar
Brady James Garvin committed
112
113
114
115
116
117
118
119
120
121
122
123
124
125
        counter = 0
        for row in range(crossword.size):
            for column in range(crossword.size):
                character = crossword[row, column]
                numbered = False
                if character is not None:
                    if crossword[row, column - 1] is None and crossword[row, column + 1] is not None:
                        numbered = True
                    if crossword[row - 1, column] is None and crossword[row + 1, column] is not None:
                        numbered = True
                number = None
                if numbered:
                    counter += 1
                    number = counter
126
127
128
129
130
131
132
133
134
135
                cells.append((number, character))
                across_clue_text = crossword.get_across_clue_text(row, column)
                if across_clue_text is not None:
                    across_clues.append((number, across_clue_text))
                down_clue_text = crossword.get_down_clue_text(row, column)
                if down_clue_text is not None:
                    down_clues.append((number, down_clue_text))
        self.across_clues = across_clues
        self.down_clues = down_clues
        self.cells = cells
Brady James Garvin's avatar
Brady James Garvin committed
136
137

    def on_start(self):
138
        self.display(CROSSWORD)
Brady James Garvin's avatar
Brady James Garvin committed
139
140
141
142
143


if __name__ == '__main__':
    app = CrosswordApp()
    app.run()