11
11
# Cursor keys : Move the cursor around the board
12
12
# Space or Enter : Toggle the contents of the cursor's position
13
13
#
14
- # TODO :
14
+ # TODO :
15
15
# Support the mouse
16
16
# Use colour if available
17
17
# Make board updates faster
@@ -26,11 +26,11 @@ class LifeBoard:
26
26
Attributes:
27
27
X,Y : horizontal and vertical size of the board
28
28
state : dictionary mapping (x,y) to 0 or 1
29
-
29
+
30
30
Methods:
31
- display(update_board) -- If update_board is true, compute the
31
+ display(update_board) -- If update_board is true, compute the
32
32
next generation. Then display the state
33
- of the board and refresh the screen.
33
+ of the board and refresh the screen.
34
34
erase() -- clear the entire board
35
35
makeRandom() -- fill the board randomly
36
36
set(y,x) -- set the given cell to Live; doesn't refresh the screen
@@ -39,90 +39,90 @@ class LifeBoard:
39
39
40
40
"""
41
41
def __init__ (self , scr , char = ord ('*' )):
42
- """Create a new LifeBoard instance.
43
-
44
- scr -- curses screen object to use for display
45
- char -- character used to render live cells (default: '*')
46
- """
47
- self .state = {} ; self .scr = scr
48
- Y , X = self .scr .getmaxyx ()
49
- self .X , self .Y = X - 2 , Y - 2 - 1
50
- self .char = char
51
- self .scr .clear ()
52
-
53
- # Draw a border around the board
54
- border_line = '+' + (self .X * '-' )+ '+'
55
- self .scr .addstr (0 , 0 , border_line )
56
- self .scr .addstr (self .Y + 1 ,0 , border_line )
57
- for y in range (0 , self .Y ):
58
- self .scr .addstr (1 + y , 0 , '|' )
59
- self .scr .addstr (1 + y , self .X + 1 , '|' )
60
- self .scr .refresh ()
61
-
62
- def set (self , y , x ):
63
- """Set a cell to the live state"""
64
- if x < 0 or self .X <= x or y < 0 or self .Y <= y :
65
- raise ValueError , "Coordinates out of range %i,%i" % (y ,x )
66
- self .state [x ,y ] = 1
67
-
68
- def toggle (self , y , x ):
69
- """Toggle a cell's state between live and dead"""
70
- if x < 0 or self .X <= x or y < 0 or self .Y <= y :
71
- raise ValueError , "Coordinates out of range %i,%i" % (y ,x )
72
- if self .state .has_key ( (x ,y ) ):
73
- del self .state [x ,y ]
74
- self .scr .addch (y + 1 , x + 1 , ' ' )
75
- else :
76
- self .state [x ,y ]= 1
77
- self .scr .addch (y + 1 , x + 1 , self .char )
78
- self .scr .refresh ()
42
+ """Create a new LifeBoard instance.
43
+
44
+ scr -- curses screen object to use for display
45
+ char -- character used to render live cells (default: '*')
46
+ """
47
+ self .state = {} ; self .scr = scr
48
+ Y , X = self .scr .getmaxyx ()
49
+ self .X , self .Y = X - 2 , Y - 2 - 1
50
+ self .char = char
51
+ self .scr .clear ()
52
+
53
+ # Draw a border around the board
54
+ border_line = '+' + (self .X * '-' )+ '+'
55
+ self .scr .addstr (0 , 0 , border_line )
56
+ self .scr .addstr (self .Y + 1 ,0 , border_line )
57
+ for y in range (0 , self .Y ):
58
+ self .scr .addstr (1 + y , 0 , '|' )
59
+ self .scr .addstr (1 + y , self .X + 1 , '|' )
60
+ self .scr .refresh ()
61
+
62
+ def set (self , y , x ):
63
+ """Set a cell to the live state"""
64
+ if x < 0 or self .X <= x or y < 0 or self .Y <= y :
65
+ raise ValueError , "Coordinates out of range %i,%i" % (y ,x )
66
+ self .state [x ,y ] = 1
67
+
68
+ def toggle (self , y , x ):
69
+ """Toggle a cell's state between live and dead"""
70
+ if x < 0 or self .X <= x or y < 0 or self .Y <= y :
71
+ raise ValueError , "Coordinates out of range %i,%i" % (y ,x )
72
+ if self .state .has_key ( (x ,y ) ):
73
+ del self .state [x ,y ]
74
+ self .scr .addch (y + 1 , x + 1 , ' ' )
75
+ else :
76
+ self .state [x ,y ]= 1
77
+ self .scr .addch (y + 1 , x + 1 , self .char )
78
+ self .scr .refresh ()
79
79
80
80
def erase (self ):
81
- """Clear the entire board and update the board display"""
82
- self .state = {}
83
- self .display (update_board = 0 )
81
+ """Clear the entire board and update the board display"""
82
+ self .state = {}
83
+ self .display (update_board = 0 )
84
84
85
85
def display (self , update_board = 1 ):
86
- """Display the whole board, optionally computing one generation"""
87
- M ,N = self .X , self .Y
88
- if not update_board :
89
- for i in range (0 , M ):
90
- for j in range (0 , N ):
91
- if self .state .has_key ( (i ,j ) ):
92
- self .scr .addch (j + 1 , i + 1 , self .char )
93
- else :
94
- self .scr .addch (j + 1 , i + 1 , ' ' )
95
- self .scr .refresh ()
96
- return
97
-
98
- d = {} ; self .boring = 1
99
- for i in range (0 , M ):
100
- L = range ( max (0 , i - 1 ), min (M , i + 2 ) )
101
- for j in range (0 , N ):
102
- s = 0
103
- live = self .state .has_key ( (i ,j ) )
104
- for k in range ( max (0 , j - 1 ), min (N , j + 2 ) ):
105
- for l in L :
106
- if self .state .has_key ( (l ,k ) ):
107
- s = s + 1
108
- s = s - live
109
- if s == 3 :
110
- # Birth
111
- d [i ,j ]= 1
112
- self .scr .addch (j + 1 , i + 1 , self .char )
113
- if not live : self .boring = 0
114
- elif s == 2 and live : d [i ,j ]= 1 # Survival
115
- elif live :
116
- # Death
117
- self .scr .addch (j + 1 , i + 1 , ' ' )
118
- self .boring = 0
119
- self .state = d
120
- self .scr .refresh ()
86
+ """Display the whole board, optionally computing one generation"""
87
+ M ,N = self .X , self .Y
88
+ if not update_board :
89
+ for i in range (0 , M ):
90
+ for j in range (0 , N ):
91
+ if self .state .has_key ( (i ,j ) ):
92
+ self .scr .addch (j + 1 , i + 1 , self .char )
93
+ else :
94
+ self .scr .addch (j + 1 , i + 1 , ' ' )
95
+ self .scr .refresh ()
96
+ return
97
+
98
+ d = {} ; self .boring = 1
99
+ for i in range (0 , M ):
100
+ L = range ( max (0 , i - 1 ), min (M , i + 2 ) )
101
+ for j in range (0 , N ):
102
+ s = 0
103
+ live = self .state .has_key ( (i ,j ) )
104
+ for k in range ( max (0 , j - 1 ), min (N , j + 2 ) ):
105
+ for l in L :
106
+ if self .state .has_key ( (l ,k ) ):
107
+ s = s + 1
108
+ s = s - live
109
+ if s == 3 :
110
+ # Birth
111
+ d [i ,j ]= 1
112
+ self .scr .addch (j + 1 , i + 1 , self .char )
113
+ if not live : self .boring = 0
114
+ elif s == 2 and live : d [i ,j ]= 1 # Survival
115
+ elif live :
116
+ # Death
117
+ self .scr .addch (j + 1 , i + 1 , ' ' )
118
+ self .boring = 0
119
+ self .state = d
120
+ self .scr .refresh ()
121
121
122
122
def makeRandom (self ):
123
- "Fill the board with a random pattern"
124
- self .state = {}
125
- for i in range (0 , self .X ):
123
+ "Fill the board with a random pattern"
124
+ self .state = {}
125
+ for i in range (0 , self .X ):
126
126
for j in range (0 , self .Y ):
127
127
if random .random () > 0.5 : self .set (j ,i )
128
128
@@ -149,7 +149,7 @@ def main(stdscr):
149
149
display_menu (stdscr , menu_y )
150
150
151
151
# Allocate a subwindow for the Life board and create the board object
152
- subwin = stdscr .subwin (stdscr_y - 3 , stdscr_x , 0 , 0 )
152
+ subwin = stdscr .subwin (stdscr_y - 3 , stdscr_x , 0 , 0 )
153
153
board = LifeBoard (subwin , char = ord ('*' ))
154
154
board .display (update_board = 0 )
155
155
@@ -158,66 +158,65 @@ def main(stdscr):
158
158
159
159
# Main loop:
160
160
while (1 ):
161
- stdscr .move (1 + ypos , 1 + xpos ) # Move the cursor
162
- c = stdscr .getch () # Get a keystroke
163
- if 0 < c < 256 :
164
- c = chr (c )
165
- if c in ' \n ' :
166
- board .toggle (ypos , xpos )
167
- elif c in 'Cc' :
168
- erase_menu (stdscr , menu_y )
169
- stdscr .addstr (menu_y , 6 , ' Hit any key to stop continuously '
170
- 'updating the screen.' )
171
- stdscr .refresh ()
172
- # Activate nodelay mode; getch() will return -1
173
- # if no keystroke is available, instead of waiting.
174
- stdscr .nodelay (1 )
175
- while (1 ):
176
- c = stdscr .getch ()
177
- if c != - 1 : break
178
- stdscr .addstr (0 ,0 , '/' ); stdscr .refresh ()
179
- board .display ()
180
- stdscr .addstr (0 ,0 , '+' ); stdscr .refresh ()
181
-
182
- stdscr .nodelay (0 ) # Disable nodelay mode
183
- display_menu (stdscr , menu_y )
184
-
185
- elif c in 'Ee' : board .erase ()
186
- elif c in 'Qq' : break
187
- elif c in 'Rr' :
188
- board .makeRandom ()
189
- board .display (update_board = 0 )
190
- elif c in 'Ss' :
191
- board .display ()
192
- else : pass # Ignore incorrect keys
193
- elif c == curses .KEY_UP and ypos > 0 : ypos = ypos - 1
194
- elif c == curses .KEY_DOWN and ypos < board .Y - 1 : ypos = ypos + 1
195
- elif c == curses .KEY_LEFT and xpos > 0 : xpos = xpos - 1
196
- elif c == curses .KEY_RIGHT and xpos < board .X - 1 : xpos = xpos + 1
197
- else : pass # Ignore incorrect keys
161
+ stdscr .move (1 + ypos , 1 + xpos ) # Move the cursor
162
+ c = stdscr .getch () # Get a keystroke
163
+ if 0 < c < 256 :
164
+ c = chr (c )
165
+ if c in ' \n ' :
166
+ board .toggle (ypos , xpos )
167
+ elif c in 'Cc' :
168
+ erase_menu (stdscr , menu_y )
169
+ stdscr .addstr (menu_y , 6 , ' Hit any key to stop continuously '
170
+ 'updating the screen.' )
171
+ stdscr .refresh ()
172
+ # Activate nodelay mode; getch() will return -1
173
+ # if no keystroke is available, instead of waiting.
174
+ stdscr .nodelay (1 )
175
+ while (1 ):
176
+ c = stdscr .getch ()
177
+ if c != - 1 : break
178
+ stdscr .addstr (0 ,0 , '/' ); stdscr .refresh ()
179
+ board .display ()
180
+ stdscr .addstr (0 ,0 , '+' ); stdscr .refresh ()
181
+
182
+ stdscr .nodelay (0 ) # Disable nodelay mode
183
+ display_menu (stdscr , menu_y )
184
+
185
+ elif c in 'Ee' : board .erase ()
186
+ elif c in 'Qq' : break
187
+ elif c in 'Rr' :
188
+ board .makeRandom ()
189
+ board .display (update_board = 0 )
190
+ elif c in 'Ss' :
191
+ board .display ()
192
+ else : pass # Ignore incorrect keys
193
+ elif c == curses .KEY_UP and ypos > 0 : ypos = ypos - 1
194
+ elif c == curses .KEY_DOWN and ypos < board .Y - 1 : ypos = ypos + 1
195
+ elif c == curses .KEY_LEFT and xpos > 0 : xpos = xpos - 1
196
+ elif c == curses .KEY_RIGHT and xpos < board .X - 1 : xpos = xpos + 1
197
+ else : pass # Ignore incorrect keys
198
198
199
199
if __name__ == '__main__' :
200
200
try :
201
- # Initialize curses
202
- stdscr = curses .initscr ()
203
- # Turn off echoing of keys, and enter cbreak mode,
204
- # where no buffering is performed on keyboard input
205
- curses .noecho () ; curses .cbreak ()
206
-
207
- # In keypad mode, escape sequences for special keys
208
- # (like the cursor keys) will be interpreted and
209
- # a special value like curses.KEY_LEFT will be returned
210
- stdscr .keypad (1 )
211
- main (stdscr ) # Enter the main loop
212
- # Set everything back to normal
213
- stdscr .keypad (0 )
214
- curses .echo () ; curses .nocbreak ()
215
- curses .endwin () # Terminate curses
201
+ # Initialize curses
202
+ stdscr = curses .initscr ()
203
+ # Turn off echoing of keys, and enter cbreak mode,
204
+ # where no buffering is performed on keyboard input
205
+ curses .noecho () ; curses .cbreak ()
206
+
207
+ # In keypad mode, escape sequences for special keys
208
+ # (like the cursor keys) will be interpreted and
209
+ # a special value like curses.KEY_LEFT will be returned
210
+ stdscr .keypad (1 )
211
+ main (stdscr ) # Enter the main loop
212
+ # Set everything back to normal
213
+ stdscr .keypad (0 )
214
+ curses .echo () ; curses .nocbreak ()
215
+ curses .endwin () # Terminate curses
216
216
except :
217
217
# In the event of an error, restore the terminal
218
- # to a sane state.
219
- stdscr .keypad (0 )
220
- curses .echo () ; curses .nocbreak ()
221
- curses .endwin ()
222
- traceback .print_exc () # Print the exception
223
-
218
+ # to a sane state.
219
+ stdscr .keypad (0 )
220
+ curses .echo () ; curses .nocbreak ()
221
+ curses .endwin ()
222
+ traceback .print_exc () # Print the exception
0 commit comments