LifeBoard   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 70
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 70
rs 10
c 0
b 0
f 0
wmc 22

10 Methods

Rating   Name   Duplication   Size   Complexity  
A set_batch() 0 4 3
A toggle() 0 2 1
A clear() 0 2 1
A step() 0 8 4
A get_neighbours() 0 5 1
A __init__() 0 5 1
A rule() 0 15 2
A wrap_edges() 0 7 3
A set() 0 5 2
A get() 0 5 4
1
#!/usr/bin/env python
2
3
import random
4
import time
5
6
import tdl
7
8
WIDTH = 80
9
HEIGHT = 40
10
11
class LifeBoard():
12
13
    def __init__(self, width, height):
14
        self.width = width
15
        self.height = height
16
        self.live_cells = set()
17
        self.wrap = True
18
19
    def set(self, x, y, value):
20
        if value:
21
            self.live_cells.add((x, y))
22
        else:
23
            self.live_cells.discard((x, y))
24
25
    def set_batch(self, x, y, batch):
26
        for y_, line in enumerate(batch):
27
            for x_, char in enumerate(line):
28
                self.set(x + x_, y + y_, char != ' ')
29
30
    def get(self, x, y):
31
        if(self.wrap is False
32
           and not (0 <= x < self.width and 0 <= y < self.height)):
33
            return False
34
        return (x % self.width, y % self.height) in self.live_cells
35
36
    def clear(self):
37
        self.live_cells.clear()
38
39
    def toggle(self, x, y):
40
        self.live_cells.symmetric_difference_update([(x, y)])
41
42
    def wrap_edges(self):
43
        for x in range(-1, self.width + 1):
44
            self.set(x, -1, self.get(x, -1))
45
            self.set(x, self.height, self.get(x, self.height))
46
        for y in range(self.height):
47
            self.set(-1, y, self.get(-1, y))
48
            self.set(self.width, y, self.get(self.width, y))
49
50
51
    def get_neighbours(self, x, y):
52
        return len(self.live_cells & {(x - 1, y - 1), (x, y - 1),
53
                                      (x + 1,y - 1), (x + 1, y),
54
                                      (x + 1, y + 1), (x, y + 1),
55
                                      (x - 1, y + 1), (x - 1, y)})
56
57
    def rule(self, is_alive, neighbours):
58
        """
59
        1. Any live cell with fewer than two live neighbours dies, as if caused
60
           by under-population.
61
        2. Any live cell with two or three live neighbours lives on to the next
62
           generation.
63
        3. Any live cell with more than three live neighbours dies, as if by
64
           overcrowding.
65
        4. Any dead cell with exactly three live neighbours becomes a live
66
           cell, as if by reproduction.
67
        """
68
        if is_alive:
69
            return 2 <= neighbours <= 3
70
        else:
71
            return neighbours == 3
72
73
    def step(self):
74
        self.wrap_edges()
75
        next_generation = set()
76
        for x in range(self.width):
77
            for y in range(self.height):
78
                if self.rule(self.get(x, y), self.get_neighbours(x, y)):
79
                    next_generation.add((x, y))
80
        self.live_cells = next_generation
81
82
def main():
83
    console = tdl.init(WIDTH, HEIGHT)
84
    board = LifeBoard(WIDTH, HEIGHT - 1)
85
    # The R-pentomino
86
    #board.set_batch(WIDTH // 2 - 2,HEIGHT // 2 - 2,
87
    #                [' **',
88
    #                 '** ',
89
    #                 ' * '])
90
91
    # Diehard
92
    #board.set_batch(WIDTH // 2 - 5,HEIGHT // 2 - 2,
93
    #                ['      * ',
94
    #                 '**      ',
95
    #                 ' *   ***'])
96
97
    # Gosper glider gun
98
    board.set_batch(1, 1,
99
                    ['                                    ',
100
                     '                        *           ',
101
                     '                      * *           ',
102
                     '            **      **            **',
103
                     '           *   *    **            **',
104
                     '**        *     *   **              ',
105
                     '**        *   * **    * *           ',
106
                     '          *     *       *           ',
107
                     '           *   *                    ',
108
                     '            **                      '])
109
110
    play = False
111
    redraw = True
112
    mouse_drawing = None
113
    mouse_x = -1
114
    mouse_y = -1
115
    while True:
116
        for event in tdl.event.get():
117
            if event.type == 'QUIT':
118
                return
119
            elif event.type == 'KEYDOWN':
120
                if event.key == 'SPACE':
121
                    play = not play
122
                    redraw = True
123
                elif event.char.upper() == 'S':
124
                    board.step()
125
                    redraw = True
126
                elif event.char.upper() == 'C':
127
                    board.clear()
128
                    redraw = True
129
                elif event.char.upper() == 'W':
130
                    board.wrap = not board.wrap
131
                    redraw = True
132
            elif event.type == 'MOUSEDOWN':
133
                x, y, = event.cell
134
                board.toggle(x, y)
135
                mouse_drawing = event.cell
136
                redraw = True
137
            elif event.type == 'MOUSEUP':
138
                mouse_drawing = None
139
            elif event.type == 'MOUSEMOTION':
140
                if(mouse_drawing and mouse_drawing != event.cell):
141
                    x, y = mouse_drawing = event.cell
142
                    board.toggle(x, y)
143
                mouse_x, mouse_y = event.cell
144
                redraw = True
145
        if play and mouse_drawing is None:
146
            board.step()
147
            redraw = True
148
        if redraw:
149
            redraw = False
150
            console.clear()
151
            for x, y in board.live_cells:
152
                console.draw_char(x, y, '*')
153
            #console.draw_rect(0, -1, None, None, None, bg=(64, 64, 80))
154
            console.draw_rect(0, -1, None, None, None, bg=(64, 64, 80))
155
            console.draw_str(0, -1, "Mouse:Toggle Cells, Space:%5s, [S]tep, [C]lear, [W]rap Turn %s" % (['Play', 'Pause'][play], ['On', 'Off'][board.wrap]), None, None)
156
            if (mouse_x, mouse_y) in console:
157
                console.draw_char(mouse_x, mouse_y,
158
                                  None, (0, 0, 0), (255, 255, 255))
159
        else:
160
            time.sleep(0.01)
161
        tdl.flush()
162
        tdl.set_title("Conway's Game of Life - %i FPS" % tdl.get_fps())
163
164
165
if __name__ == '__main__':
166
    main()
167
168