Example #1
0
class Environment(Frame):

    def __init__(self, root, mw, username):
        Frame.__init__(self, root, background="MediumTurquoise")
        self.parent = root
        self.mw = mw
        self.username = username

        self.levelFilename = "../support/levels/level"
        self.stencilFilename = "../support/stencil/level"
        self.helpFilename = "../support/help/level"
        self.canRun = False
        self.endStatus = False

        # change font size depending on screen dimension
        screen_width = self.parent.winfo_screenwidth()
        screen_height = self.parent.winfo_screenheight()

        # projector setting
        if screen_width == 1280:
	    self.customFont1 = tkFont.Font(family="Pupcat", size=18, weight=tkFont.BOLD)
	    self.customFont2 = tkFont.Font(family="LMMono10", size=17)
	    self.boldFont = tkFont.Font(family="LMMono10", size=17, weight=tkFont.BOLD)
	    self.italFont = tkFont.Font(family="LMMono10", size=17, slant=tkFont.ITALIC)

	# single screen setting
	elif screen_width == 1920:
	    self.customFont1 = tkFont.Font(family="Pupcat", size=14, weight=tkFont.BOLD)
	    self.customFont2 = tkFont.Font(family="LMMono10", size=14)
	    self.boldFont = tkFont.Font(family="LMMono10", size=14, weight=tkFont.BOLD)
	    self.italFont = tkFont.Font(family="LMMono10", size=14, slant=tkFont.ITALIC)

	# double screen setting
	else:
	    self.customFont1 = tkFont.Font(family="Pupcat", size=14, weight=tkFont.BOLD)
            self.customFont2 = tkFont.Font(family="LMMono10", size=15)
            self.boldFont = tkFont.Font(family="LMMono10", size=14, weight=tkFont.BOLD)
	    self.italFont = tkFont.Font(family="LMMono10", size=14, slant=tkFont.ITALIC)


        self.initToolbar()
        self.initCanvas()
        self.initTextBoxes()
        self.initUI()

        self.currLevel = 1

        self.beatenLevels = []
        self.initLevelCanvas()
        self.initLevelText()
        maze.create_maze()


    def initUI(self):
        self.parent.title("GLIDE")
        self.pack(fill=BOTH, expand=1)
        x = (self.parent.winfo_screenwidth() - DIM_X)/2
        y = (self.parent.winfo_screenheight() - DIM_Y)/2
        self.parent.geometry('%dx%d+%d+%d' % (DIM_X, DIM_Y, x, y))


    def initLevelCanvas(self):
	
	# create the canvas
	name = self.levelFilename + str(self.currLevel)
	self.tilemap = TileMap(name)
	
	f = open(name, 'r')
	levelMap = []
	while True:
	    line = f.readline()
	    if line == '':
		break
	    levelMap.append(line)
	f.close()
	
	self.painter = Painter(self.canvas, levelMap)

    # Redraw the canvas, but do not create a new tilemap. Used so that the levels
    # with randomized maps can be redrawn without creating a new tilemap.
    def redrawLevelCanvas(self):
	
	name = self.levelFilename + str(self.currLevel)
	f = open(name, 'r')
	levelMap = []
	while True:
	    line = f.readline()
	    if line == '':
		break
	    levelMap.append(line)
	f.close()
	
	self.painter = Painter(self.canvas, levelMap)


    def initLevelText(self):
	# clear the text editor
	self.textEditor.delete(1.0, END)
	
	# put stencil code into the text editor
	name = self.stencilFilename + str(self.currLevel)
        f = open(name, 'r')
        lineNum = 0
	while True:
	    line = f.readline()
	    if line == "":
		break
	    else:
		self.textEditor.insert(END, line)
	f.close()
	
	# allow editing for the help box and clear it
	self.helpBox.config(state=NORMAL)
	self.helpBox.delete(1.0, END)   # clear text boxes
	
	# put help files into the help box - what we want to show on each screen
        # is in its own string inside the "screens"
        name = self.helpFilename + str(self.currLevel)
        f = open(name, 'r')
        self.screens = []
        self.screens.append("")
        numScreen = 0

	while True:
	    line = f.readline()
	    if line == "":
		break
	    elif line == "*****\n":
		self.screens.append("")
		numScreen += 1
	    else:
		self.screens[numScreen] += line
	f.close()
	
	# insert the first screen's text into the help box and set a variable saying so
	self.putHelpboxText(0)
	self.shownScreen = 0
	
	# disable editing again
        self.helpBox.config(state=DISABLED)


    def loadUserCode(self):
	# clear the text editor
	self.textEditor.delete(1.0, END)
	
	# put user's code into the text editor
	name = "code" + str(self.currLevel) + self.username
        f = open(name, 'r')
        lineNum = 0
	while True:
	    line = f.readline()
	    if line == "":
		break
	    else:
		self.textEditor.insert(END, line)
	f.close()


    def putHelpboxText(self, screenNum):
        self.helpBox.insert(END, self.screens[screenNum])
        self.shownScreen = screenNum
	
	# do tag parsing
	
	codeStart = self.helpBox.search("<code>", 1.0)
	while codeStart != '':
	    l = re.split('\.', codeStart)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(codeStart, "%d.%d" % (line, col+6))  # remove the "<code>" tag from the line

	    codeEnd = self.helpBox.search("</code>", 1.0)
	    if codeEnd == '':
		print "Missing </code> tag in level ", self.currLevel, " help file."
	    l = re.split('\.', codeEnd)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(codeEnd, "%d.%d" % (line, col+7))  # remove the "</code>" tag from the line

	    # apply tag
	    self.helpBox.tag_add("code", codeStart, codeEnd)

	    # check for other code tags
	    codeStart = self.helpBox.search("<code>", 1.0)

        boldStart = self.helpBox.search("<b>", 1.0)
	while boldStart != '':
	    l = re.split('\.', boldStart)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(boldStart, "%d.%d" % (line, col+3))  # remove the "<b>" tag from the line

	    boldEnd = self.helpBox.search("</b>", 1.0)
	    if boldEnd == '':
		print "Missing </b> tag in level ", self.currLevel, " help file."
	    l = re.split('\.', boldEnd)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(boldEnd, "%d.%d" % (line, col+4))  # remove the "</b>" tag from the line

	    # apply tag
	    self.helpBox.tag_add("bold", boldStart, boldEnd)

	    # check for other code tags
	    boldStart = self.helpBox.search("<b>", 1.0)

        italStart = self.helpBox.search("<i>", 1.0)
	while italStart != '':
	    l = re.split('\.', italStart)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(italStart, "%d.%d" % (line, col+3))  # remove the "<i>" tag from the line

	    italEnd = self.helpBox.search("</i>", 1.0)
	    if italEnd == '':
		print "Missing </i> tag in level ", self.currLevel, " help file."
	    l = re.split('\.', italEnd)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(italEnd, "%d.%d" % (line, col+4))  # remove the "</i>" tag from the line

	    # apply tag
	    self.helpBox.tag_add("ital", italStart, italEnd)

	    # check for other code tags
	    italStart = self.helpBox.search("<i>", 1.0)

        underStart = self.helpBox.search("<u>", 1.0)
	while underStart != '':
	    l = re.split('\.', underStart)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(underStart, "%d.%d" % (line, col+3))  # remove the "<u>" tag from the line

	    underEnd = self.helpBox.search("</u>", 1.0)
	    if underEnd == '':
		print "Missing </u> tag in level ", self.currLevel, " help file."
	    l = re.split('\.', underEnd)
	    line, col = int(l[0]), int(l[1])
	    self.helpBox.delete(underEnd, "%d.%d" % (line, col+4))  # remove the "</u>" tag from the line

	    # apply tag
	    self.helpBox.tag_add("underline", underStart, underEnd)

	    # check for other code tags
	    underStart = self.helpBox.search("<u>", 1.0)

    def initToolbar(self):
        toolbar = Frame(self.parent, relief=FLAT, background="MediumTurquoise")

        img = Image.open("Graphics/Icons/saveIcon.png")
        saveImg1 = ImageTk.PhotoImage(img)  
        self.saveLevelButton = Button(toolbar, image=saveImg1, relief=FLAT, background="Turquoise",
                                      activebackground="yellow", width=BUTTON_X, height=BUTTON_Y, command=self.save)
        self.saveLevelButton.image = saveImg1
        self.saveLevelButton.grid(row=0, column=0)

        img = Image.open("Graphics/Icons/loadIcon.png")
        loadImg = ImageTk.PhotoImage(img)  
        self.loadButton = Button(toolbar, image=loadImg, relief=FLAT, background="Turquoise",
                                 activebackground="yellow", width=BUTTON_X, height=BUTTON_Y, command=self.load)
        self.loadButton.image = loadImg
        self.loadButton.grid(row=0, column=1)

        img = Image.open("Graphics/Icons/checkIcon.png")
        checkImg = ImageTk.PhotoImage(img)  
        self.checkButton = Button(toolbar, image=checkImg, relief=FLAT, background="Turquoise",
                                  activebackground="yellow", width=BUTTON_X, height=BUTTON_Y, command=self.checkCode)
        self.checkButton.image = checkImg
        self.checkButton.grid(row=0, column=2)

        img = Image.open("Graphics/Icons/runIcon.png")
        runImg = ImageTk.PhotoImage(img)  
        self.runButton = Button(toolbar, image=runImg, relief=FLAT, background="Turquoise", state=DISABLED,
                                activebackground="yellow", width=BUTTON_X, height=BUTTON_Y, command=self.run)
        self.runButton.image = runImg
        self.runButton.grid(row=0, column=3)

        img = Image.open("Graphics/Icons/prevLevelIcon.png")
        prevLevelImg = ImageTk.PhotoImage(img)  
        self.prevLevelButton = Button(toolbar, image=prevLevelImg, relief=FLAT, background="Turquoise", state=DISABLED,
                                 activebackground="yellow", width=BUTTON_X, height=BUTTON_Y, command=self.prevLevel)
        self.prevLevelButton.image = prevLevelImg
        self.prevLevelButton.grid(row=0, column=4)

        img = Image.open("Graphics/Icons/nextLevelIcon.png")
        nextLevelImg = ImageTk.PhotoImage(img)  
        self.nextLevelButton = Button(toolbar, image=nextLevelImg, relief=FLAT, background="Turquoise", state=DISABLED,
                                 activebackground="yellow", width=BUTTON_X, height=BUTTON_Y, command=self.nextLevel)
        self.nextLevelButton.image = nextLevelImg
        self.nextLevelButton.grid(row=0, column=5)

        img = Image.open("Graphics/Icons/quitIcon.png")
        quitImg = ImageTk.PhotoImage(img)  
        quitButton = Button(toolbar, image=quitImg, relief=FLAT, background="Turquoise",
                            activebackground="yellow", width=BUTTON_X, height=BUTTON_Y, command=self.exit)
        quitButton.image = quitImg
        quitButton.grid(row=0, column=7, sticky=E)

        toolbar.pack(side=TOP, fill=X)


    def disableButtons(self):
	currStates = [self.saveLevelButton.config().get('state')[4],
	              self.loadButton.config().get('state')[4],
	              self.checkButton.config().get('state')[4],
	              self.runButton.config().get('state')[4],
	              self.prevLevelButton.config().get('state')[4],
	              self.nextLevelButton.config().get('state')[4]]
	
	# set all to disabled
	self.saveLevelButton.config(state=DISABLED)
	self.loadButton.config(state=DISABLED)
	self.checkButton.config(state=DISABLED)
	self.runButton.config(state=DISABLED)
	self.prevLevelButton.config(state=DISABLED)
	self.nextLevelButton.config(state=DISABLED)
	
	return currStates
	
    def returnButtonsToStates(self, states):
	self.saveLevelButton.config(state=states[0])
	self.loadButton.config(state=states[1])
	self.checkButton.config(state=states[2])
	self.runButton.config(state=states[3])
	self.prevLevelButton.config(state=states[4])
	self.nextLevelButton.config(state=states[5])
	

    def initCanvas(self):
        self.canvas = Canvas(self.parent, width=DIM_X, height=CANVAS_HEIGHT, background="white", relief=FLAT)
        self.canvas.pack()


    def initTextBoxes(self):
        panedWindow = PanedWindow(self.parent, width=DIM_X, height=(DIM_Y - TOOLBAR_Y)/2+5, relief=FLAT)


	# left-hand side: text box for the user to type into, plus a scrollbar
        leftPanel = Frame(panedWindow)
        scrollbar = Scrollbar(leftPanel, orient=VERTICAL)
        self.textEditor = Text(leftPanel, background="PaleTurquoise", width=MAX_CHARS, font=self.customFont2,
                               wrap=WORD, height=(DIM_Y - TOOLBAR_Y)/2, yscrollcommand=scrollbar.set,
                               selectbackground="Turquoise")
        self.textEditor.bind("<<Modified>>", self.textEditorModified)
        self.resettingModifiedFlag = False
	
	# add a scrollbar to the left-hand box
	scrollbar.config(command=self.textEditor.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.textEditor.pack(side=LEFT, fill=BOTH, expand=1)
        panedWindow.add(leftPanel)

	# right hand side: help box, plus buttons to see different help screens
	
	rightPanel = Frame(panedWindow)
	scrollbar1 = Scrollbar(rightPanel, orient=VERTICAL)
	boxPanel = Frame(rightPanel, width=DIM_Y/2, height=DIM_X - 2*TOOLBAR_Y)
        self.helpBox = Text(boxPanel, background="LemonChiffon", font=self.customFont2, selectbackground="Gold",
                            wrap=WORD, height=15, yscrollcommand=scrollbar1.set)
        
        # add a scrollbar to the right-hand box
	scrollbar1.config(command=self.helpBox.yview)
        scrollbar1.pack(side=RIGHT, fill=Y)
        self.helpBox.pack(expand=1)
        boxPanel.pack()

        # add buttons to help box
	helpboxWidth = self.helpBox.winfo_reqwidth()
        buttonBar = Frame(rightPanel, relief=FLAT, background="LemonChiffon", height=BUTTON_Y, width=helpboxWidth)

        img = Image.open("Graphics/backArrow.png")
        self.backImg = ImageTk.PhotoImage(img)
        prevButton =     Button(buttonBar, relief=RAISED, background="LemonChiffon", image=self.backImg, borderwidth=1,
                                activebackground="Turquoise", height=BUTTON_Y, command=self.prevScreen)
        prevButton.image = self.backImg
        
        img = Image.open("Graphics/yourCode.png")
        self.codeImg = ImageTk.PhotoImage(img)
        yourCodeButton = Button(buttonBar, relief=RAISED, background="LemonChiffon", image=self.codeImg, borderwidth=1,
                                activebackground="Turquoise", height=BUTTON_Y, command=self.lastScreen)
        yourCodeButton.image = self.codeImg

        img = Image.open("Graphics/nextArrow.png")
        self.nextImg = ImageTk.PhotoImage(img)
        nextButton =     Button(buttonBar, relief=RAISED, background="LemonChiffon", image=self.nextImg, borderwidth=1,
                                activebackground="Turquoise", height=BUTTON_Y, command=self.nextScreen)
        nextButton.image = self.nextImg

	prevButton.pack(side=LEFT)
	nextButton.pack(side=RIGHT)
	yourCodeButton.pack(padx=103)

	buttonBar.pack(fill=X)
	
	# set up tags to highlight errors in the text editor and do syntax highlighting
	self.textEditor.tag_config("error", background="OrangeRed", foreground="White")
	
	self.helpBox.tag_config("bold", font=self.boldFont)
	self.helpBox.tag_config("ital", font=self.italFont)
	self.helpBox.tag_config("underline", underline=1)
	self.helpBox.tag_config("code", font=self.boldFont, foreground="DarkViolet")
	
        panedWindow.add(rightPanel)
        panedWindow.pack(fill=BOTH, expand=1)


    # deals with making the "run code" button appear grayed-out when the user modifies the
    # input box, so that you have to re-compile before running
    def clearModifiedFlag(self):
	self.resettingModifiedFlag = True
	self.textEditor.edit_modified(False)
	self.resettingModifiedFlag = False


    # same as above comment
    def textEditorModified(self, selfCall=False, event=None):
	if self.resettingModifiedFlag == True:
	    return
	self.canRun = False
	self.runButton.config(state=DISABLED)
	self.clearModifiedFlag()


    # Show the previous screen in the help box
    def prevScreen(self):
	if self.shownScreen == 0:
	    pass
	else:
	    self.helpBox.config(state=NORMAL)   # first, turn on editing
	    #self.shownScreen -= 1
	    self.helpBox.delete(1.0, END)   # clear the text box first
	    #self.helpBox.insert(END, self.screens[self.shownScreen])   # add the prev screen's text
	    self.putHelpboxText(self.shownScreen-1)
	    self.helpBox.config(state=DISABLED)  # turn off editing again


    # Show the last ("Your Code") screen in the help box
    def lastScreen(self):
	if self.shownScreen == (len(self.screens)-1):
	    pass
	else:
	    self.helpBox.config(state=NORMAL)   # turn on editing
	    #self.shownScreen = len(self.screens)-1
	    self.helpBox.delete(1.0, END)   # clear text box
	    #self.helpBox.insert(END, self.screens[self.shownScreen])
	    self.putHelpboxText(len(self.screens)-1)
            self.helpBox.config(state=DISABLED)   # turn off editing


    # Show the next screen in the help box
    def nextScreen(self):
	if self.shownScreen == (len(self.screens)-1):
	    pass
	else:
	    self.helpBox.config(state=NORMAL)   # first, turn on editing
	    #self.shownScreen += 1
	    self.helpBox.delete(1.0, END)   # clear text box
	    #self.helpBox.insert(END, self.screens[self.shownScreen])
	    self.putHelpboxText(self.shownScreen+1)
            self.helpBox.config(state=DISABLED)   # turn off editing


    # Return to the main window
    def exit(self):
	self.cleanUp()
	self.painter = None
	
	for widget in self.parent.pack_slaves():
	    widget.pack_forget()
	
        from MainWindow import MainWindow
	mw = MainWindow(self.parent)
	mw.pack()
	
        self.destroy()


    def save(self):
        pass

    def load(self):
        # clear the text editor
	self.textEditor.delete(1.0, END)
	
	# put user's code into the text editor
	name = "../support/levels/sol" + str(self.currLevel)
        f = open(name, 'r')
        lineNum = 0
	while True:
	    line = f.readline()
	    if line == "":
		break
	    else:
		self.textEditor.insert(END, line)
	f.close()

    # Save the user's code in the text editor into a file and tell the tilemap to check the code.
    def checkCode(self):
	filename = "code" + str(self.currLevel) + self.username
        f = open(filename, 'w')
        text = self.textEditor.get(1.0, END)
        f.write(text)
        f.close()

        # disable buttons & show "checking" dialog while we run the level dummy
        currStates = self.disableButtons()
        self.painter.showCheckingText()
        self.update()

        # run the level dummy to see if the code compiles
        noError = self.tilemap.runLevelDummy(self.username)

        # return buttons to their states once the method has returned & hide "checking" dialog
        self.returnButtonsToStates(currStates)
        self.painter.hideCheckingText()

        if not noError:
	    self.handleError()

        else:
	    # redraw the level - if we're in one of the randomized levels, the map/maze will change with
	    # each compilation
	    self.redrawLevelCanvas()
	    # reset plane
	    
	    # make sure no lines are highlighted as error lines
	    self.textEditor.tag_remove("error", 1.0, END)
	    
	    self.screens[-1] = "Yay! No compile or runtime errors!"
	    self.runButton.config(state=NORMAL)
	    self.canRun = True

	# show the new text in the "your code" part of the help box
	self.helpBox.config(state=NORMAL)   # turn on editing
	self.shownScreen = len(self.screens)-1
	self.helpBox.delete(1.0, END)   # clear text box
	self.helpBox.insert(END, self.screens[self.shownScreen])
	self.helpBox.config(state=DISABLED)   # turn off editing


    def handleError(self):
	# the error line to highlight in the code
	errorLine = 0

	# read in the error file
	errText = ""
	f = open("output.py", 'r')
	while True:
	    line = f.readline()
	    if line == "":
		break
	    elif line.startswith("code"):
	        errText += line
	        continue

            m = re.search("line (\d+)", line)
	    if m != None:
		val = m.group(1)
		errorLine = int(val) - 5
		line = re.sub(val, str(errorLine), line)

		# highlight line in textEditor
		self.textEditor.tag_add("error", "%d.%d" % (errorLine, 0), "%d.%s" % (errorLine, END))
		errText += line
	    else:
		errText += line
	f.close()

	# set the error text in the self.screens variable
	self.screens[-1] = errText
	self.runButton.config(state=DISABLED)


    def setEndStatus(self, b):
	self.endStatus = b


    # Get the list of commands to execute from the tilemap and tell the painter to do them. This
    # allows us to look ahead for turns so we can animate them nicely.
    def run(self):
	
	if self.canRun:
	    
	    # disable buttons while we run the level dummy
            currStates = self.disableButtons()

	    # reset plane
	    self.painter.initPlane()
	    
	    # get name list if in binary search level (None if not this level)
	    nameList = self.tilemap.getNameList()

	    cmdList = self.tilemap.getLevel()
	    
	    if self.currLevel == 6:
		self.painter.setSpeeds(.004, .0015)
            elif self.currLevel == 3:
		self.painter.setSpeeds(.010, .005)
	    else:
		self.painter.setSpeeds(.015, .008)

	    cmdList = re.sub('04350', 'i', cmdList) # i = s-bend east south
	    cmdList = re.sub('05140', 'j', cmdList) # j = s-bend east north
	    cmdList = re.sub('14051', 'k', cmdList) # k = s-bend north east
	    cmdList = re.sub('15241', 'l', cmdList) # l = s-bend north west
	    cmdList = re.sub('24152', 'm', cmdList) # m = s-bend west north
	    cmdList = re.sub('25342', 'n', cmdList) # n = s-bend west south
	    cmdList = re.sub('34253', 'o', cmdList) # o = s-bend south west
	    cmdList = re.sub('35043', 'p', cmdList) # p = s-bend south east

	    cmdList = re.sub('043', 'a', cmdList)   # a = right turn south
	    cmdList = re.sub('051', 'b', cmdList)   # b = left turn north
	    cmdList = re.sub('342', 'c', cmdList)   # c = right turn west
	    cmdList = re.sub('350', 'd', cmdList)   # d = left turn east
	    cmdList = re.sub('253', 'e', cmdList)   # e = left turn south
	    cmdList = re.sub('241', 'f', cmdList)   # f = right turn north
	    cmdList = re.sub('152', 'g', cmdList)   # g = left turn west
	    cmdList = re.sub('140', 'h', cmdList)   # h = right turn east

	    desks = re.findall('8(\d+?)8', cmdList)
	    cmdList = re.sub('8\d+?8', '8x', cmdList)  # x = desk
	    nextDesk = -1

	    for i in range(len(cmdList)):
		if self.endStatus:
		    self.painter.destroy()
		    self.destroy()
		    return

		cmd = cmdList[i]
		if cmd == '0':
		    self.painter.movePlaneEast()
		elif cmd == '1':
		    self.painter.movePlaneNorth()
		elif cmd == '2':
		    self.painter.movePlaneWest()
		elif cmd == '3':
		    self.painter.movePlaneSouth()
		elif cmd == '4':
		    self.painter.rotatePlaneClockwise(90)
		elif cmd == '5':
		    self.painter.rotatePlaneCounterclockwise(90)
		elif cmd == '6':     # crash
		    self.painter.crash()
		    if self.currLevel == 5:
		        self.screens[-1] = "You asked too many students and your teacher woke up! Yikes!\nTry to find Sally in fewer guesses."
		    else:
			self.screens[-1] = "Oh no - your plane crashed!"
		    self.helpBox.config(state=NORMAL)   # turn on editing
	            self.shownScreen = len(self.screens)-1
	            self.helpBox.delete(1.0, END)   # clear text box
	            self.helpBox.insert(END, self.screens[self.shownScreen])
	            self.helpBox.config(state=DISABLED)   # turn off editing
	            self.returnButtonsToStates(currStates)
	            self.update()
	            time.sleep(.8)
	            self.painter.initPlane()
	            self.painter.clearNames()
	            return
		elif cmd == '7':
		    pass
		elif cmd == '8':
		    nextDesk += 1
		elif cmd == 'x':
		    currDesk = int(desks[nextDesk])
		    self.painter.askName(nameList[currDesk], currDesk+1)
		elif cmd == 'y':
		    self.painter.dropWaterBalloon()
		elif cmd == 'z':
		    self.painter.dropWaterBalloon(True)
		elif cmd == 'a':
		    self.painter.takeRightTurnSouth()
		elif cmd == 'b':
		    self.painter.takeLeftTurnNorth()
		elif cmd == 'c':
		    self.painter.takeRightTurnWest()
		elif cmd == 'd':
		    self.painter.takeLeftTurnEast()
		elif cmd == 'e':
		    self.painter.takeLeftTurnSouth()
		elif cmd == 'f':
		    self.painter.takeRightTurnNorth()
		elif cmd == 'g':
		    self.painter.takeLeftTurnWest()
		elif cmd == 'h':
		    self.painter.takeRightTurnEast()
		elif cmd == 'i':
		    self.painter.sBendEastSouth()
		elif cmd == 'j':
		    self.painter.sBendEastNorth()
		elif cmd == 'k':
		    self.painter.sBendNorthEast()
		elif cmd == 'l':
		    self.painter.sBendNorthWest()
		elif cmd == 'm':
		    self.painter.sBendWestNorth()
		elif cmd == 'n':
		    self.painter.sBendWestSouth()
		elif cmd == 'o':
		    self.painter.sBendSouthWest()
		elif cmd == 'p':
		    self.painter.sBendSouthEast()
		else:
		    print ("Unknown movement command %i; not executing." % cmd)


	    # check for a win, or an "inefficient" win - reached goal but had extra cmds at end
	    match = re.search('7', cmdList)
	    if match != None and match.start() == len(cmdList)-1:    # actual win
		if self.currLevel == 6:
		    self.screens[-1] = "CONGRATULATIONS! You've reached the end of GLIDE 1.0! Stay tuned " \
		                       "for more levels in future versions of GLIDE."
		else:
		    self.screens[-1] = "Congrats! You beat the level!\n\nYou can hit the Next Level button to " \
				        "move on, or try out other cool stuff with your plane here."
		self.beatenLevels.append(self.currLevel)
		
		# if not at last level, make the next level button un-grayed
		if self.currLevel < 6:
		     currStates[5] = "normal"
		self.painter.animateWin()
		# show the new text in the "your code" part of the help box
		self.helpBox.config(state=NORMAL)   # turn on editing
		self.shownScreen = len(self.screens)-1
		self.helpBox.delete(1.0, END)   # clear text box
		self.helpBox.insert(END, self.screens[self.shownScreen])
		self.helpBox.config(state=DISABLED)   # turn off editing
		self.returnButtonsToStates(currStates)
		self.update()
		time.sleep(.7)
		self.painter.clearNames()
		return

            # inefficient win
	    elif match != None:
		if self.currLevel == 5:
		    self.screens[-1] = "You found Sally but kept asking students, and your teacher noticed. Uh oh! " \
		                       "Try making your plane find Sally by asking as few students as possible."
		else:
		    self.screens[-1] = "You passed the goal - looks your code contained some extra stuff. " \
				       "Try making your plane reach the goal in as few moves as possible."

            # didn't hit goal at all
            else:
		if self.currLevel == 5:
		    self.screens[-1] = "Looks like Sally's still sleeping. Try again to wake her up."
		else:
		    self.screens[-1] = "Oops! Your plane didn't make it to the goal."

	    # show the new text in the "your code" part of the help box
	    self.helpBox.config(state=NORMAL)   # turn on editing
	    self.shownScreen = len(self.screens)-1
	    self.helpBox.delete(1.0, END)   # clear text box
	    self.helpBox.insert(END, self.screens[self.shownScreen])
	    self.helpBox.config(state=DISABLED)   # turn off editing

	    # make the run button clickable again
	    self.returnButtonsToStates(currStates)

	    # reset the plane
	    self.update()
	    time.sleep(1.2)
	    self.painter.initPlane()

	    self.painter.clearNames()


    def prevLevel(self):
	self.painter.killAnimation()  # stop fireworks, if going
	self.currLevel -= 1
	self.initLevelCanvas()
	self.initLevelText()
	
	# when going to previous level, always reload user's saved code
	self.loadUserCode()
	
	# do the appropriate graying-out of buttons
	if self.currLevel == 1:
	    self.prevLevelButton.config(state=DISABLED)
	else:
	    self.prevLevelButton.config(state=NORMAL)
	self.nextLevelButton.config(state=NORMAL)
	self.runButton.config(state=DISABLED)


    def nextLevel(self):
	self.painter.killAnimation()   # stop fireworks, if going
	self.currLevel += 1
	self.initLevelCanvas()
	self.initLevelText()
	
	# if the next level (now currLevel) has already been beaten, then reload the user's 
	# saved code
	if self.currLevel in self.beatenLevels:
	    self.loadUserCode()
	
	# do the appropriate graying-out of buttons
	if self.currLevel in self.beatenLevels and self.currLevel < 6:
	    self.nextLevelButton.config(state=NORMAL)
	else:
	    self.nextLevelButton.config(state=DISABLED)
	self.prevLevelButton.config(state=NORMAL)
	self.runButton.config(state=DISABLED)


    def cleanUp(self):
	f = open("runLevel.py", "w")
	f.close()