[Tutor] engines

Gregor Lingl glingl@aon.at
Fri, 19 Jul 2002 07:58:58 +0200


This is a multi-part message in MIME format.
--------------030100030702070606010305
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Marc schrieb:

>I noticed that you named variables with english/german words.
>Well, I can barely read english, let alone german.
>So, can u send me a translated version? *grin*.
>Maybe post it on list again.Im sure several people will be interested
>in your code.
>
Here it is!

Gregor

--------------030100030702070606010305
Content-Type: text/plain;
 name="esnake.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="esnake.py"

""" snake - OOP training   (V. OOP12)   - ENGLISH VERSION
    author: gregor lingl, vienna.    email:  glingl@aon.at   """
from Tkinter import *
from Canvas import Rectangle
import sys, random

class Gameboard(Canvas):
    def __init__(self, root, NX, NY, fieldwidth=12, **kwargs):
        Canvas.__init__(self, root, kwargs)
        w,h = NX*fieldwidth, NY*fieldwidth
        self.config(width=w+2, height=h+2, bg = 'yellow')
        self.grid = {}
        for row in range(NY):
            for column in range(NX):
                x0 = 2 + column * fieldwidth
                y0 = 2 + row  * fieldwidth
                x1 = x0 + fieldwidth
                y1 = y0 + fieldwidth
                r = Rectangle(self, x0, y0, x1, y1,
                              fill='yellow', outline='yellow' )
                self.grid[(column,row)] = r
    def set(self,field,colour):
        self.grid[field]['fill'] = colour

class Snake:
    def __init__(self, size):
        self.N = size
        self.food = None
        self.reset()
    def reset(self):
        self.snake= [(self.N/2,self.N/2)]
        self.food = None
        self.newFood()
        self.direction = None
        self.alive = 1         
    def newFood(self):
        while not self.food or self.food in self.snake:
            self.food = (random.randrange(self.N), random.randrange(self.N))
    def getscore(self):
        return "Score: " + str(max(0,len(self.snake)-4))        
    def cutoffTail(self):
        self.snake = self.snake[1:]
    def newHead(self,field):
        self.snake.append(field)
    def nextField(self):
        x,y = self.snake[-1]
        if self.direction == 'Up':
            y=y-1
        elif self.direction == 'Down':
            y=y+1
        elif self.direction == 'Left':
            x=x-1
        elif self.direction == 'Right':
            x=x+1
        else:
            return None
        return (x,y)
    def onBoard(self, next):
        x,y=next
        return 0 <= x < self.N and 0 <= y < self.N
    def step(self, newDirection):
        changed = {}
        if newDirection:
            if (newDirection,self.direction) not in (('Up','Down'),('Down','Up'),
                                                ('Right','Left'),('Left','Right')):
                self.direction = newDirection
        next = self.nextField()
        # Case 1: hit edge or bit herself
        if not self.onBoard(next) or next in self.snake:
            self.alive = 0
            for member in self.snake:
                changed[member]='black'
        # Fall 2: food found
        elif next == self.food:
            self.newHead(next)
            changed[next]='red'
            self.newFood()
            changed[self.food]='blue'
        # Fall 3: normal step
        else:
            if len(self.snake) > 3:
                changed[self.snake[0]]='yellow'
                self.cutoffTail()
            self.newHead(next)
            changed[next]='red'
        return changed

class SnakeEngine:
    def __init__(self, N):
        self.N = N
        root = Tk()
        root.title("SNAKE")
        root.bind('<KeyPress>', self.taste)
        self.board = Gameboard(root,N,N)
        self.board.pack()
        self.scorelabel = Label(root,width=22,text="",font=("Courier",14,"bold"),fg='red')
        self.hintlabel  = Label(root,width=22,text="",font=("Courier",14,"normal"))
        self.scorelabel.pack()
        self.hintlabel.pack()
        self.snake = Snake(N)
        self.reset()
    def taste(self,event):
        key = event.keysym
        if key == 'Return':
            sys.exit(0)
        if key in ['Up','Down','Left','Right','space']:
                self.eventlist.append(key)
    def reset(self):
        for field in self.board.grid:
            self.board.set(field,'yellow')
        self.eventlist = []
        self.state = "waiting"
        self.snake.reset()
        self.board.set(self.snake.snake[0],'red')
        self.board.set(self.snake.food,'blue')
        self.board.update()
        self.hintlabel.config(text="Control: arrow keys")
        self.scorelabel.config(text=self.snake.getscore())
    def run(self):
        changed = {}
        taste = None
        if self.eventlist:
            taste = self.eventlist[0]
            self.eventlist = self.eventlist[1:]
        if self.state == "waiting":
            if taste in ['Up','Down','Right','Left']:
                self.state = "running"
        if self.state == "running":
            if taste in ['Up','Down','Right','Left', None]:
                changed = self.snake.step(taste)
                self.scorelabel.config(text=self.snake.getscore())
            if not self.snake.alive:
                self.state="over"
                self.hintlabel.config(text="New game: space bar")
        elif self.state == "over":
            if taste == 'space':
                self.reset()
        for field in changed:
            self.board.set(field, changed[field])
        self.board.update()
        self.board.after(100, self.run)
       
SnakeEngine(21).run()
mainloop()
--------------030100030702070606010305--