1111# Cursor keys : Move the cursor around the board
1212# Space or Enter : Toggle the contents of the cursor's position
1313#
14- # TODO :
14+ # TODO :
1515# Support the mouse
1616# Use colour if available
1717# Make board updates faster
@@ -26,11 +26,11 @@ class LifeBoard:
2626 Attributes:
2727 X,Y : horizontal and vertical size of the board
2828 state : dictionary mapping (x,y) to 0 or 1
29-
29+
3030 Methods:
31- display(update_board) -- If update_board is true, compute the
31+ display(update_board) -- If update_board is true, compute the
3232 next generation. Then display the state
33- of the board and refresh the screen.
33+ of the board and refresh the screen.
3434 erase() -- clear the entire board
3535 makeRandom() -- fill the board randomly
3636 set(y,x) -- set the given cell to Live; doesn't refresh the screen
@@ -39,90 +39,90 @@ class LifeBoard:
3939
4040 """
4141 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 ()
7979
8080 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 )
8484
8585 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 ()
121121
122122 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 ):
126126 for j in range (0 , self .Y ):
127127 if random .random () > 0.5 : self .set (j ,i )
128128
@@ -149,7 +149,7 @@ def main(stdscr):
149149 display_menu (stdscr , menu_y )
150150
151151 # 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 )
153153 board = LifeBoard (subwin , char = ord ('*' ))
154154 board .display (update_board = 0 )
155155
@@ -158,66 +158,65 @@ def main(stdscr):
158158
159159 # Main loop:
160160 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
198198
199199if __name__ == '__main__' :
200200 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
216216 except :
217217 # 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