logo       

[SPOILER] Solution to Perl 'Expert' Quiz of the Week #26: msg#00051

Subject: [SPOILER] Solution to Perl 'Expert' Quiz of the Week #26
Hi

I usually never go for the expert quiz because it's too time consuming, but 
this one sounded like fun (and didn't take that long to make :D )

I'm no physics major, so i'm still a bit confused as to the whole kinetic -> 
velocity calculation, but at least the cart gains speed when falling, and 
looses speed when climbing :)

I used python for the implementation. 

/Jimmy
--------------------------------------
#!/usr/bin/env python
#############################################
# File name     : rollercoaster.py
# Date          : Fri Oct 22 04:41:40 2004
# Author        : Jimmy Selgen Nielsen
# Email         : spamtrap1-x/claU4MwXpaa/9Udqfwiw@xxxxxxxxxxxxxxxx
# Description   :
# Changelog     :
#       Fri Oct 22 04:41:40 2004        : Initial version
#############################################

from Tkinter import *
import tkMessageBox,tkFileDialog,sys,os,math,time,tkSimpleDialog

class rollercoaster:
    '''
    Perl QOTW expert quiz #26 solution
    Opens file specified in argv[1], or file opened from menu.
    '''
    def __init__(self,args):
        self.rc_tag = None
        self.height = 400
        self.width = 600
        self.gravity = 1
        self.mass = 1
        self.time_mult = 100
        self.debug = 0
        self.wnd = None

        self.init_display()
        if(len(args)):
            self.read_rc(args[0])
        self.root.mainloop()


    def init_display(self):
        '''
        Initialize main window
        '''
        self.root = Tk()
        self.speedvar = StringVar()
        self.main_frame = Frame(self.root)
        self.main_frame.pack(fill=BOTH,expand=1)
        self.run_button = Button(self.main_frame,text="Run",command=self.run)
        self.canvas = 
Canvas(self.main_frame,width=self.width,height=self.height)
        speed_label = Label(self.main_frame,text="Velocity")
        self.speedometer = Entry(self.main_frame,textvariable=self.speedvar)
        self.run_button.pack()
        self.canvas.pack()
        speed_label.pack()
        self.speedometer.pack()
        self.mainmenu = Menu(self.root)
        self.root.config(menu=self.mainmenu)
        self.filemenu = Menu(self.mainmenu)
        self.filemenu.add_command(label="Open",command=self.open_rc_handler)
        self.filemenu.add_command(label="Run",command=self.run)
        self.filemenu.add_command(label="Setup",command=self.config_dialog)
        self.filemenu.add_command(label="Exit",command=self.root.destroy)
        self.mainmenu.add_cascade(label="File",menu=self.filemenu)

    def ok_pressed(self):
        '''
        Config dialog callback for OK
        '''
        self.gravity = float(self.grav_str.get())
        self.mass = float(self.mass_str.get())
        self.time_mult = float(self.time_mult_str.get())
        self.debug = self.dbg_var.get()
        print "new settings, gravity = %02f, mass = %02f, time_mult = %02f" % 
(self.gravity,self.mass,self.time_mult)
        self.wnd.destroy()
        self.wnd = None

    def cancel_pressed(self):
        '''
        Config dialog callback for cancel
        '''
        self.wnd.destroy()
        self.wnd = None

    def config_dialog(self):
        '''
        Configuration dialog for setting mass, gravity, time multiplier and 
turning debugging on/off
        '''
        if(self.wnd==None):
            self.wnd = Toplevel()
            self.frm = Frame(self.wnd)
            self.grav_str = StringVar()
            self.mass_str = StringVar()
            self.time_mult_str = StringVar()
            self.dbg_var = IntVar()
            self.grav_str.set(self.gravity)
            self.mass_str.set(self.mass)
            self.time_mult_str.set(self.time_mult)
            self.dbg_var.set(self.debug)
            grav_label = Label(self.frm,text="Gravity")
            self.grav_entry = Entry(self.frm,textvariable=self.grav_str)
            mass_label = Label(self.frm,text="Mass")
            self.mass_entry = Entry(self.frm,textvariable=self.mass_str)
            delay_label = Label(self.frm,text="Delay multiplier (dist/v * 
mult)")
            self.time_mult_entry = 
Entry(self.frm,textvariable=self.time_mult_str)
            debug_btn = Checkbutton(self.frm,text="Debug",variable=self.dbg_var)
            ok_btn = Button(self.frm,text="OK",command=self.ok_pressed)
            cancel_btn = 
Button(self.frm,text="Cancel",command=self.cancel_pressed)
            grav_label.pack()
            self.grav_entry.pack()
            mass_label.pack()
            self.mass_entry.pack()
            delay_label.pack()
            self.time_mult_entry.pack()
            debug_btn.pack()
            ok_btn.pack()
            cancel_btn.pack()
            self.frm.pack()

    def draw_cart(self,coord):
        '''
        Draws the "cart" from the given coordinate set
        '''
        #print "draw_cart, coord = ",coord
        self.bbox = [coord[0]-2,self.height - 
(coord[1]-2),coord[0]+2,self.height - (coord[1]+2)]
        if(self.cart != None):
           self.canvas.coords(self.cart,*self.bbox)
        else:
            self.cart = self.canvas.create_oval(self.bbox,fill="red")

    def draw_rc(self):
        '''
        Draws the rollercoaster from the current coordinate set
        '''
        self.coords = []
        self.cart = None
        self.canvas.delete('all')
        for p in range(len(self.rc)) :
            if(p < len(self.rc)-1):
                point = self.rc[p].rstrip('\n').split(' ')
                point[0] = float(point[0])
                point[1] = float(point[1])
                self.coords.append(point)

        if(self.rc_tag != None):
            self.canvas.delete(self.rc_tag)
        self.rc_tag = []
        for p in range(len(self.coords)):
            if p < len(self.coords)-1:
                co = [self.coords[p][0],self.height - 
self.coords[p][1],self.coords[p+1][0],self.height - self.coords[p+1][1]]
                self.rc_tag.append(self.canvas.create_line(co))
        self.canvas.pack(fill=BOTH)



    def calc_vel(self, curr_state, next_point):
        '''
        Calculates new speed and direction for cart for a given point

        curr_state : current state of cart
        next_point : the current point of the cart
        returns    : new state with updated cart speed,direction and time to 
travel distance
        '''
        new_state = dict()
        dist = 0
        nv = 0
        co = self.coords[curr_state['coord']]
        nco = self.coords[next_point]
        new_state = curr_state

        #calculate vertical and horizontal "grid" distance travelled
        dist = co[0] - nco[0]
        nh = co[1] - nco[1]
        dist_travelled = math.sqrt(dist**2 + nh**2)
        if(self.debug):
            print "dist :",dist," height :",nh," dist_travelled 
:",dist_travelled
        pa = (curr_state['m'] * curr_state['g'] * ((nh/2)/10))

        if(pa > 0):
            nv = math.sqrt(pa)
        else:
            nv = -(math.sqrt(-pa))
        if(self.debug):
            print "nv = ",nv

        new_state['v'] += nv

        #Change cart direction if velocity is less than zero
        if(new_state['v']<0):
            new_state['direction'] = 0 - new_state['direction']
            #change negative velocity to positive velocity going the other way 
:)
            new_state['v'] = -new_state['v']

        if(self.debug):
            print "new v :",new_state['v']
        new_state['coord'] = next_point

        #Set time to travel distance at new velocity
        new_state['t'] = dist_travelled / (new_state['v']+1)
        if(self.debug):
            print "new t = ",new_state['t']

        return(new_state)


    def read_rc(self,fname):
        '''
        Read a .rc file from disk
        '''
        try:
            f = open(fname)
            self.rc = f.readlines()
            if(self.debug):
                print "read %d lines from %s" % (len(self.rc),fname)
        except:
            tkMessageBox.showerror('Error opening file','Error opening file 
"'+fname+'"')
            self.rc = None
        self.draw_rc()

    def open_rc_handler(self):
        '''
        Menu callback for "File->Open"
        '''
        fname = tkFileDialog.askopenfilename(filetypes=[(".rc", ".rc")], 
title="Select the file")
        if(fname != None):
            self.read_rc(fname)

    def tick(self):
        '''
        "Mainloop" of the simulation. Callback to the windowmanager for every 
iteration of the simulation
        '''
        self.curr_state = 
self.calc_vel(self.curr_state,self.curr_state['coord']+self.curr_state['direction'])
        self.draw_cart(self.coords[self.curr_state['coord']])
        self.speedvar.set(round(self.curr_state['v'],2))
        nco = self.curr_state['coord'] + self.curr_state['direction']
        if(self.curr_state['v'] != 0 and nco >= 0 and nco < len(self.coords)):
            self.root.after(int(self.curr_state['t']*self.time_mult),self.tick)
        else:
            return(0)

    def run(self):
        '''
        Initialize and start mainloop of simulation
        '''
        self.curr_state = {
                'coord' : 0,      #Index into rollercoaster coordinates
                'v':0,              #Cart Velocity in the current direction
                'm':self.mass,   #Mass
                'g':self.gravity, #Gravity
                't':0,               #Time to travel distance
                'direction':1      #Direction of cart, 1 = left to right, -1 = 
right to left
        }
        self.calc_vel(self.curr_state,1)
        self.root.after(int(self.curr_state['t']*self.time_mult),self.tick)


if __name__ == '__main__' :
    rc = rollercoaster(sys.argv[1:])




<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

Recently Viewed:
boot-loaders.gr...    php.pear.genera...    debugging.valgr...    kde.redhat.user...    text.xml.xsl.ge...    culture.languag...    hardware.microc...    java.servicemix...    redhat.release....    web.zope.plone....    user-groups.lin...    opendarwin.webk...    video.mjpeg.use...    sysutils.bcfg2....    encryption.gpg....    lx-office.devel...    xfree86.forum/2...    mail.mutt.devel...    acpi.devel/2003...    qnx.openqnx.dev...    network.irc.irs...    freebsd.devel.m...   
Home | blog view | USPTO Patent Archive | advertise | OSDir is an inevitable website. super tiny logo

Free Magazines

Cisco News
Receive a free quarterly e-newsletter with exclusive articles on how Cisco IT uses its own products and solutions to enable the business.
subscribe

Systems Management News, the newspaper for IT systems administration and data center managers! Each issue of Systems Management News is chock-full of news and analysis to help you understand what's happening in your field.
subscribe

The Enterprise Newsweekly eWeek is the essential technology information source for builders of e-business.
subscribe

Oracle Magazine Oracle Magazine contains technology strategy articles, sample code, tips, Oracle and partner news, how to articles for developers and DBAs, and more. Oracle (NASDAQ: ORCL) is the world's largest enterprise software company.
subscribe

Total Telecom Total Telecom is "The Economist of the communications industry".
subscribe