life.py :  » Language-Interface » ChinesePython » chinesepython2.1.3-0.4 » Demo » curses » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Language Interface » ChinesePython 
ChinesePython » chinesepython2.1.3 0.4 » Demo » curses » life.py
#!/usr/bin/env python
# life.py -- A curses-based version of Conway's Game of Life.
# Contributed by A.M. Kuchling <amk1@bigfoot.com>
#
# An empty board will be displayed, and the following commands are available:
#  E : Erase the board
#  R : Fill the board randomly
#  S : Step for a single generation
#  C : Update continuously until a key is struck
#  Q : Quit
#  Cursor keys :  Move the cursor around the board
#  Space or Enter : Toggle the contents of the cursor's position
#
# TODO : 
#   Support the mouse
#   Use colour if available
#   Make board updates faster
#

class LifeBoard:
    """Encapsulates a Life board

    Attributes:
    X,Y : horizontal and vertical size of the board
    state : dictionary mapping (x,y) to 0 or 1
    
    Methods:
    display(update_board) -- If update_board is true, compute the 
                             next generation.  Then display the state
           of the board and refresh the screen.
    erase() -- clear the entire board
    makeRandom() -- fill the board randomly
    set(y,x) -- set the given cell to Live; doesn't refresh the screen
    toggle(y,x) -- change the given cell from live to dead, or vice
                   versa, and refresh the screen display

    """
    def __init__(self, scr, char=ord('*')):
  """Create a new LifeBoard instance.

  scr -- curses screen object to use for display
  char -- character used to render live cells (default: '*')
  """
  self.state={} ; self.scr=scr
  Y, X = self.scr.getmaxyx()
  self.X, self.Y = X-2, Y-2-1
  self.char = char
  self.scr.clear()  

  # Draw a border around the board
  border_line='+'+(self.X*'-')+'+'
  self.scr.addstr(0, 0, border_line)
  self.scr.addstr(self.Y+1,0, border_line)
  for y in range(0, self.Y): 
      self.scr.addstr(1+y, 0, '|') 
      self.scr.addstr(1+y, self.X+1, '|')
  self.scr.refresh()

    def set(self, y, x): 
  """Set a cell to the live state"""
  if x<0 or self.X<=x or y<0 or self.Y<=y:
      raise ValueError, "Coordinates out of range %i,%i"% (y,x)
  self.state[x,y] = 1

    def toggle(self, y, x): 
  """Toggle a cell's state between live and dead"""
  if x<0 or self.X<=x or y<0 or self.Y<=y:
      raise ValueError, "Coordinates out of range %i,%i"% (y,x)
  if self.state.has_key( (x,y) ): 
      del self.state[x,y]
      self.scr.addch(y+1, x+1, ' ')
  else:
      self.state[x,y]=1
      self.scr.addch(y+1, x+1, self.char)
  self.scr.refresh()

    def erase(self):
  """Clear the entire board and update the board display"""
  self.state={}
  self.display(update_board=0)

    def display(self, update_board=1):
  """Display the whole board, optionally computing one generation"""
  M,N = self.X, self.Y 
  if not update_board:
      for i in range(0, M):
    for j in range(0, N):
      if self.state.has_key( (i,j) ): 
          self.scr.addch(j+1, i+1, self.char)
      else:
          self.scr.addch(j+1, i+1, ' ')
      self.scr.refresh()
      return

  d={} ; self.boring=1
  for i in range(0, M):
      L=range( max(0, i-1), min(M, i+2) )
      for j in range(0, N):
    s=0
    live=self.state.has_key( (i,j) )
    for k in range( max(0, j-1), min(N, j+2) ):
        for l in L:
      if self.state.has_key( (l,k) ):
          s=s+1
    s=s-live
    if s==3: 
        # Birth
        d[i,j]=1 
        self.scr.addch(j+1, i+1, self.char)
        if not live: self.boring=0  
    elif s==2 and live: d[i,j]=1       # Survival
    elif live: 
        # Death
        self.scr.addch(j+1, i+1, ' ')
        self.boring=0
  self.state=d
  self.scr.refresh()

    def makeRandom(self):
  "Fill the board with a random pattern"
  import whrandom
  self.state={}
  for i in range(0, self.X): 
            for j in range(0, self.Y):
    if whrandom.random()*10>5.0: self.set(j,i)


def erase_menu(stdscr, menu_y):
    "Clear the space where the menu resides"
    stdscr.move(menu_y, 0) ; stdscr.clrtoeol()
    stdscr.move(menu_y+1, 0) ; stdscr.clrtoeol()

def display_menu(stdscr, menu_y):
    "Display the menu of possible keystroke commands"
    erase_menu(stdscr, menu_y)
    stdscr.addstr(menu_y, 4,
                  'Use the cursor keys to move, and space or Enter to toggle a cell.')
    stdscr.addstr(menu_y+1, 4,
                  'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit')

def main(stdscr):
    import string, curses

    # Clear the screen and display the menu of keys
    stdscr.clear()
    stdscr_y, stdscr_x = stdscr.getmaxyx()
    menu_y=(stdscr_y-3)-1
    display_menu(stdscr, menu_y)

    # Allocate a subwindow for the Life board and create the board object
    subwin=stdscr.subwin(stdscr_y-3, stdscr_x, 0, 0) 
    board=LifeBoard(subwin, char=ord('*'))
    board.display(update_board=0)

    # xpos, ypos are the cursor's position
    xpos, ypos = board.X/2, board.Y/2

    # Main loop:
    while (1):
  stdscr.move(1+ypos, 1+xpos)     # Move the cursor
  c=stdscr.getch()    # Get a keystroke
  if 0<c<256:
      c=chr(c)
      if c in ' \n':
    board.toggle(ypos, xpos)
      elif c in 'Cc':
    erase_menu(stdscr, menu_y)
    stdscr.addstr(menu_y, 6, ' Hit any key to stop continuously '
            'updating the screen.')
    stdscr.refresh()
    # Activate nodelay mode; getch() will return -1
    # if no keystroke is available, instead of waiting.
    stdscr.nodelay(1)   
    while (1):
        c=stdscr.getch()
        if c!=-1: break
        stdscr.addstr(0,0, '/'); stdscr.refresh()
        board.display()
        stdscr.addstr(0,0, '+'); stdscr.refresh()

    stdscr.nodelay(0)  # Disable nodelay mode
    display_menu(stdscr, menu_y)

      elif c in 'Ee': board.erase()
      elif c in 'Qq': break
      elif c in 'Rr': 
    board.makeRandom()
    board.display(update_board=0)
      elif c in 'Ss':
    board.display()
      else: pass                  # Ignore incorrect keys
  elif c==curses.KEY_UP and ypos>0:        ypos=ypos-1
  elif c==curses.KEY_DOWN and ypos<board.Y-1:  ypos=ypos+1
  elif c==curses.KEY_LEFT and xpos>0:          xpos=xpos-1
  elif c==curses.KEY_RIGHT and xpos<board.X-1: xpos=xpos+1
        else: pass      # Ignore incorrect keys

if __name__=='__main__':
    import curses, traceback
    try:
  # Initialize curses
  stdscr=curses.initscr()
  # Turn off echoing of keys, and enter cbreak mode,
  # where no buffering is performed on keyboard input
  curses.noecho() ; curses.cbreak()

  # In keypad mode, escape sequences for special keys
  # (like the cursor keys) will be interpreted and
  # a special value like curses.KEY_LEFT will be returned
  stdscr.keypad(1)
  main(stdscr)      # Enter the main loop
  # Set everything back to normal
  stdscr.keypad(0)
  curses.echo() ; curses.nocbreak()
  curses.endwin()      # Terminate curses
    except:
        # In the event of an error, restore the terminal
  # to a sane state.
  stdscr.keypad(0)
  curses.echo() ; curses.nocbreak()
  curses.endwin()
  traceback.print_exc()    # Print the exception

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.