Walnut/Ordinary Programming/Ordinary Computing Examples

From Erights

(Difference between revisions)
Jump to: navigation, search
(FIELD_OTHER)
m (Reverted edits by 89.19.172.22 (Talk); changed back to last version by Kevin Reid)
Line 1: Line 1:
[[Category:Walnut|2]]
[[Category:Walnut|2]]
-
FIELD_MESSAGE_domelacel
+
===Ordinary Computing Examples===
 +
 
 +
====Pretty E====
 +
 
 +
====Racetrack Game for a single computer====
 +
 
 +
Below is a simple game of racetrack: 3 cars are set on the track, to race between walls around curves to the finish line. Each driver can choose to accelerate or decelerate his car by +/- 1 space/turn during each turn. Do not build up too much velocity, you won't be able to slow down!
 +
 
 +
The example has just about everything in it: JPanels, objects, functions, Java API calls, it's all there. We will come back to this example later in the book, to make the track distributed and secure. Then we shall invite Satan for a little competition, with souls on the line.
 +
 
 +
<pre>
 +
 
 +
<nowiki># E sample
 +
 
 +
#!/usr/bin/env rune
 +
 +
# Copyright 2002 Combex, Inc. under the terms of the MIT X license
 +
# found at http://www.opensource.org/licenses/mit-license.html
 +
pragma.syntax("0.9")
 +
 +
def traceln(text) { stderr.println(text) }
 +
 +
def attachAction(component,target,verb) {
 +
    def listener {
 +
        to actionPerformed(event) {
 +
            try {
 +
                E.call(target, verb, [])
 +
            } catch problem {
 +
                throw <- (problem) # send to E tracelog instead of AWT
 +
            }
 +
        }
 +
    }
 +
    component.addActionListener(listener)
 +
}
 +
 +
def newButton(labelText, verb, target) {
 +
    def button := <swing:makeJButton>(labelText)
 +
    button.setBackground(<awt:makeSystemColor>.getControl())
 +
    attachAction(button,target,verb)
 +
    return button
 +
}
 +
 +
def abs(number) {return if (number >= 0) {number} else {-number}}
 +
 +
def makeCoord(x,y) {
 +
    def coord {
 +
        to getX() {return x}
 +
        to getY() {return y}
 +
        to printOn(writer) {writer.print(`coord: $x,$y`)}
 +
        to samePlace(coord2) :boolean {
 +
            return x == coord2.getX() &&  y == coord2.getY()
 +
        }
 +
 +
        /**
 +
          * The "add" method is the underlying function for the "+" operator.
 +
          * Here, by writing an "add" method, we make coordinates work with "+"
 +
          */
 +
        to add(coord2) {return makeCoord(x + coord2.getX(),y + coord2.getY())}
 +
 +
        /**
 +
          * The "subtract" method is the underlying function for the "-" operator
 +
          */
 +
        to subtract(coord2) {return makeCoord(x - coord2.getX(),y - coord2.getY())}
 +
    }
 +
    return coord
 +
}
 +
 +
def makeInstrumentPanel(car) :near {
 +
    def makeIndicator(speed,positiveText,negativeText):pbc {
 +
        var answer := ""
 +
        var direction := positiveText
 +
        if (speed < 0) {direction := negativeText}
 +
        for i in 1..abs(speed) {answer := answer + direction}
 +
        if (speed == 0) {answer := "0"}
 +
        return answer
 +
    }
 +
    def makeXIndicator(speed) {return makeIndicator(speed,">","<")}
 +
    def makeYIndicator(speed) {return makeIndicator(speed,"^\n","V\n")}
 +
    def frame := <swing:makeJFrame>(`Car ${car.getName()} Instrument Panel`)
 +
    def lbl(text) {return <swing:makeJLabel>(text)}
 +
    def xLabel := lbl("Horizontal Speed:")
 +
    def xIndicator := <swing:makeJTextArea>()
 +
    xIndicator.setText("0")
 +
    def yLabel := <swing:makeJTextArea>("V \ne\nr\nt\ni\nc\na\nl")
 +
    yLabel.setBackground(<awt:makeSystemColor>.getControl())
 +
    def yIndicator := <swing:makeJTextArea>()
 +
    yIndicator.setText("0")
 +
    def statusPane := lbl("Running...")
 +
    def instrumentPanel
 +
    def btn(name,action) {return newButton(name,action,instrumentPanel)}
 +
    def submitButton := btn("Submit","submit")
 +
    var acceleration := makeCoord(0,0)
 +
    def realPane :=JPanel`
 +
        ${lbl("")}  $xLabel    >                      >                  >
 +
        V          $xIndicator >                      >                  >
 +
        $yLabel.Y  $yIndicator ${btn("\\","upLeft")}  ${btn("^","up")}  ${btn("/","upRight")}
 +
        V          V          ${btn("<","left")}    ${btn("0","zero")} ${btn(">","right")}
 +
        V          V          ${btn("/","downLeft")} ${btn("V","down")} ${btn("\\","downRight")}
 +
        V          V          $submitButton.X        >                  >
 +
        $statusPane >          >                      >                  >`
 +
    frame.setDefaultCloseOperation(<swing:makeWindowConstants>.getDO_NOTHING_ON_CLOSE())
 +
    frame.getContentPane().add(realPane)
 +
    frame.pack()
 +
    frame.show()
 +
    bind instrumentPanel {
 +
        to submit() {
 +
            submitButton.setEnabled(false)
 +
            car.accelerate(acceleration)
 +
        }
 +
        to prepareForNextTurn() {
 +
            xIndicator.setText(makeXIndicator(car.getVelocity().getX()))
 +
            yIndicator.setText(makeYIndicator(-(car.getVelocity().getY())))
 +
            acceleration := makeCoord(0,0)
 +
            submitButton.setEnabled(true)
 +
            # Note, public static transferFocus on awt Component is not Java API, added in E environment
 +
            <awt:makeComponent>.transferFocus([frame.getContentPane()], statusPane)
 +
        }
 +
        to setStatus(status) {statusPane.setText(status)}
 +
        to upLeft() {acceleration := makeCoord(-1,-1)}
 +
        to up() {acceleration := makeCoord(0,-1)}
 +
        to upRight() {acceleration := makeCoord(1,-1)}
 +
        to left() {acceleration := makeCoord(-1,0)}
 +
        to zero() {acceleration := makeCoord(0,0)}
 +
        to right() {acceleration := makeCoord(1,0)}
 +
        to downLeft() {acceleration := makeCoord(-1,1)}
 +
        to down() {acceleration := makeCoord(0,1)}
 +
        to downRight() {acceleration := makeCoord(1,1)}
 +
    }
 +
    return instrumentPanel
 +
}
 +
 +
def makeCar(name,startLocation,raceMap)  {
 +
    var location := startLocation
 +
    var acceleration := makeCoord(0,0)
 +
    var velocity := makeCoord(0,0)
 +
    var hasCrashed := false
 +
    var hasFinished := false
 +
    def instrumentPanel
 +
    def sign(x) {
 +
        return if (x > 0) {
 +
            1
 +
        } else if (x < 0) {
 +
            -1
 +
        } else {0}
 +
    }
 +
   
 +
    def accelReactors := [].asMap().diverge()
 +
 +
    /**
 +
      * Compute the path the car will take from the location at the
 +
      * beginning of this turn to the end; return the result
 +
      * as a list of coords
 +
      */
 +
    def computeIntermediateLocations(start,finish)  {
 +
        def locations := [].diverge()
 +
        def slope := (finish.getY() - start.getY()) / (finish.getX() - start.getX())
 +
        def computeRemainingLocations(current) {
 +
            var nextX := current.getX()
 +
            var nextY := current.getY()
 +
            var distToGo := 0
 +
            #if the car is traveling faster in the x direction than
 +
            #in the y direction, increment x position by one along
 +
            #the path and compute the new y
 +
            if (slope < 1.0 && slope > -1.0) {
 +
                distToGo := finish.getX() - current.getX()
 +
                nextX += sign(distToGo)
 +
                def distTraveled := nextX - start.getX()
 +
                nextY := start.getY() + ((slope * distTraveled) + 0.5) //1
 +
                #if the car is traveling faster in the y direction than
 +
                #in the x direction, increment y position by one along
 +
                #the path and compute new x
 +
            } else {
 +
                distToGo := finish.getY() - current.getY()
 +
                nextY += sign(distToGo)
 +
                def distTraveled := nextY - start.getY()
 +
                nextX := start.getX() + ((distTraveled/slope) + 0.5) //1
 +
            }
 +
            def next := makeCoord(nextX,nextY)
 +
            locations.push(next)
 +
            if (!(next.samePlace(finish))) {
 +
                computeRemainingLocations(next)
 +
            }
 +
        }
 +
        computeRemainingLocations(start)
 +
        return locations
 +
    }
 +
    def car {
 +
        to accelerate(accel) {
 +
            traceln(`accelerating car $name`)
 +
            acceleration := accel
 +
            for each in accelReactors {
 +
                each.reactToAccel(car)
 +
            }
 +
        }
 +
        to move(){
 +
            traceln("into move")
 +
            velocity += acceleration
 +
            def newLocation := location + velocity
 +
            traceln("got newlocation")
 +
            def path := computeIntermediateLocations(location,newLocation)
 +
            location := newLocation
 +
            traceln("assigned  location")
 +
            hasCrashed := hasCrashed || raceMap.causesCrash(path)
 +
            hasFinished := hasFinished || raceMap.causesFinish(path)
 +
            traceln("got crash finish")
 +
            if (hasCrashed) {
 +
                instrumentPanel.setStatus("Crashed")
 +
            } else if (hasFinished) {instrumentPanel.setStatus("Finished")}
 +
            traceln("out of move")
 +
        }
 +
        to getLocation() {return location}
 +
        to getVelocity() {return velocity}
 +
        to hasCrashed() {return hasCrashed}
 +
        to hasFinished() {return hasFinished}
 +
        to getName() {return name}
 +
        to prepareForNextTurn() {instrumentPanel.prepareForNextTurn()}
 +
        to addAccelReactor(reactor) {accelReactors[reactor] := reactor}
 +
        to removeAccelReactor(reactor) {accelReactors.remove(reactor)}
 +
    }
 +
    bind instrumentPanel := makeInstrumentPanel(car)
 +
    return car
 +
}
 +
 +
def makeTrackViewer(initialTextMap)  {
 +
    def frame := <swing:makeJFrame>("Track View")
 +
    def mapPane := <swing:makeJTextArea>(initialTextMap)
 +
    def statusPane := <swing:makeJLabel>(" ")
 +
    def realPane :=
 +
      JPanel`$mapPane.Y
 +
              $statusPane`
 +
    frame.getContentPane().add(realPane)
 +
    def windowListener {
 +
        to windowClosing(event) {
 +
            interp.continueAtTop()
 +
        }
 +
        match [verb,args] {}
 +
    }
 +
    frame.addWindowListener(windowListener)
 +
    frame.pack()
 +
    frame.show()
 +
    def trackViewer {
 +
        to refresh(textMap) {mapPane.setText(textMap)}
 +
        to showStatus(status) {statusPane.setText(status)}
 +
    }
 +
    return trackViewer
 +
}
 +
 +
def makeRaceMap() {
 +
    def baseMap := [
 +
        "..........W...............",
 +
        "..........W...........FFFF",
 +
        "......W...WW..............",
 +
        "......W....W..............",
 +
        "......W....WWW............",
 +
        "......W........W..........",
 +
        "......W.....W.............",
 +
        "......W.....W.............",
 +
        "......W...................",
 +
        "......W..................."]
 +
 +
    def isWall(coord) :boolean {return baseMap[coord.getY()] [coord.getX()] == 'W' }
 +
    def isFinish(coord) :boolean {return baseMap[coord.getY()] [coord.getX()] == 'F'}
 +
    def pointCrash(coord) :boolean {
 +
        var result := false
 +
        if (coord.getX() < 0 || coord.getY() < 0 ||
 +
              coord.getX() >= baseMap[0].size() || coord.getY() >= baseMap.size()) {
 +
            result := true
 +
        } else if (isWall(coord)) {
 +
            result := true
 +
        }
 +
        return result
 +
    }
 +
    def raceMap {
 +
        to getAsTextWithCars(cars) {
 +
            def embedCarsInLine(index,line) {
 +
                def inBounds(xLoc) :boolean {return xLoc >= 0 && xLoc < line.size()}
 +
                var result := line
 +
                for each in cars {
 +
                    if (each.getLocation().getY() == index &&
 +
                          inBounds(each.getLocation().getX())) {
 +
                        def editable := result.diverge(char)
 +
                        editable[each.getLocation().getX()] := (each.getName())[0]
 +
                        result := editable.snapshot()
 +
                    }
 +
                }
 +
                return result
 +
            }
 +
            var result := ""
 +
            for i => each in baseMap {
 +
                result := result + embedCarsInLine(i,each) + "\n"
 +
            }
 +
            return result
 +
        }
 +
        to causesCrash(path) :boolean {
 +
            var result := false
 +
            for each in path {
 +
                if (pointCrash(each)) {
 +
                    result := true
 +
                    break()
 +
                }
 +
            }
 +
            return result
 +
        }
 +
        to causesFinish(path) :boolean {
 +
            var result := false
 +
            for each in path {
 +
                if (pointCrash(each)) {
 +
                    break()
 +
                } else if (isFinish(each)) {
 +
                    result := true
 +
                    break()
 +
                }
 +
            }
 +
            return result
 +
        }
 +
    }
 +
    return raceMap
 +
}
 +
 +
/**
 +
  * create the cars, place them in a flex map to be used as a set
 +
  */
 +
def makeCars(raceMap) {
 +
    def carList := [
 +
        makeCar("1",makeCoord(1,9),raceMap),
 +
        makeCar("2",makeCoord(2,9),raceMap),
 +
        makeCar("3",makeCoord(3,9),raceMap)]
 +
    def carSet := [].asMap().diverge()
 +
    for each in carList {carSet[each] := each}
 +
    return carSet
 +
}
 +
 +
/**
 +
  * @author </nowiki>[mailto:marcs@skyhunter.com Marc Stiegler]<nowiki>
 +
  */
 +
def makeRaceTrack() {
 +
    def raceMap := makeRaceMap()
 +
    def cars := makeCars(raceMap)
 +
    var carsReadyToMove  := [].asMap().diverge()
 +
    def mapViewer := makeTrackViewer(raceMap.getAsTextWithCars(cars))
 +
    def raceTrack {
 +
        to reactToAccel(car) {
 +
            traceln("racetrack reacting to accel")
 +
            carsReadyToMove[car] := car
 +
            if (carsReadyToMove.size() >= cars.size()) {
 +
                raceTrack.completeNextTurn()
 +
            }
 +
        }
 +
        to completeNextTurn() {
 +
            def winners := [].diverge()
 +
            for each in cars {
 +
                each.move()
 +
                if (each.hasCrashed()) {
 +
                    cars.removeKey(each)
 +
                } else if (each.hasFinished()) {
 +
                    winners.push(each)
 +
                }
 +
            }
 +
            mapViewer.refresh(raceMap.getAsTextWithCars(cars) )
 +
            if (winners.size() == 1) {
 +
                mapViewer.showStatus(`Car ${winners[0].getName()} has won!`)
 +
            } else if (winners.size() > 1) {
 +
                mapViewer.showStatus("It's a tie!")
 +
            } else if (cars.size() == 0) {
 +
                mapViewer.showStatus("Everyone's dead!")
 +
            } else {raceTrack.prepareForNextTurn()}
 +
        }
 +
        to prepareForNextTurn() {
 +
            traceln("into prepare for next turn")
 +
            carsReadyToMove := [].asMap().diverge()
 +
            for each in cars {
 +
                each.prepareForNextTurn()
 +
            }
 +
        }
 +
    }
 +
    for each in cars {each.addAccelReactor(raceTrack)}
 +
    return raceTrack
 +
}
 +
 +
makeRaceTrack()
 +
# In actual code, the following line would not be commented out
 +
# interp.blockAtTop()</nowiki>
 +
 
 +
</pre>

Revision as of 00:27, 17 December 2008


Ordinary Computing Examples

Pretty E

Racetrack Game for a single computer

Below is a simple game of racetrack: 3 cars are set on the track, to race between walls around curves to the finish line. Each driver can choose to accelerate or decelerate his car by +/- 1 space/turn during each turn. Do not build up too much velocity, you won't be able to slow down!

The example has just about everything in it: JPanels, objects, functions, Java API calls, it's all there. We will come back to this example later in the book, to make the track distributed and secure. Then we shall invite Satan for a little competition, with souls on the line.


 # E sample
  
 #!/usr/bin/env rune
 
 # Copyright 2002 Combex, Inc. under the terms of the MIT X license
 # found at http://www.opensource.org/licenses/mit-license.html
 pragma.syntax("0.9")
 
 def traceln(text) { stderr.println(text) }
 
 def attachAction(component,target,verb) {
     def listener {
         to actionPerformed(event) {
             try {
                 E.call(target, verb, [])
             } catch problem {
                 throw <- (problem) # send to E tracelog instead of AWT
             }
         }
     }
     component.addActionListener(listener)
 }
 
 def newButton(labelText, verb, target) {
     def button := <swing:makeJButton>(labelText)
     button.setBackground(<awt:makeSystemColor>.getControl())
     attachAction(button,target,verb)
     return button
 }
 
 def abs(number) {return if (number >= 0) {number} else {-number}}
 
 def makeCoord(x,y) {
     def coord {
         to getX() {return x}
         to getY() {return y}
         to printOn(writer) {writer.print(`coord: $x,$y`)}
         to samePlace(coord2) :boolean {
             return x == coord2.getX() &&  y == coord2.getY()
         }
 
         /**
          * The "add" method is the underlying function for the "+" operator.
          * Here, by writing an "add" method, we make coordinates work with "+"
          */
         to add(coord2) {return makeCoord(x + coord2.getX(),y + coord2.getY())}
 
         /**
          * The "subtract" method is the underlying function for the "-" operator
          */
         to subtract(coord2) {return makeCoord(x - coord2.getX(),y - coord2.getY())}
     }
     return coord
 }
 
 def makeInstrumentPanel(car) :near {
     def makeIndicator(speed,positiveText,negativeText):pbc {
         var answer := ""
         var direction := positiveText
         if (speed < 0) {direction := negativeText}
         for i in 1..abs(speed) {answer := answer + direction}
         if (speed == 0) {answer := "0"}
         return answer
     }
     def makeXIndicator(speed) {return makeIndicator(speed,">","<")} 
     def makeYIndicator(speed) {return makeIndicator(speed,"^\n","V\n")} 
     def frame := <swing:makeJFrame>(`Car ${car.getName()} Instrument Panel`)
     def lbl(text) {return <swing:makeJLabel>(text)} 
     def xLabel := lbl("Horizontal Speed:") 
     def xIndicator := <swing:makeJTextArea>() 
     xIndicator.setText("0") 
     def yLabel := <swing:makeJTextArea>("V \ne\nr\nt\ni\nc\na\nl") 
     yLabel.setBackground(<awt:makeSystemColor>.getControl()) 
     def yIndicator := <swing:makeJTextArea>() 
     yIndicator.setText("0") 
     def statusPane := lbl("Running...") 
     def instrumentPanel 
     def btn(name,action) {return newButton(name,action,instrumentPanel)} 
     def submitButton := btn("Submit","submit") 
     var acceleration := makeCoord(0,0) 
     def realPane :=JPanel`
         ${lbl("")}  $xLabel     >                      >                  > 
         V           $xIndicator >                      >                  > 
         $yLabel.Y   $yIndicator ${btn("\\","upLeft")}  ${btn("^","up")}   ${btn("/","upRight")} 
         V           V           ${btn("<","left")}     ${btn("0","zero")} ${btn(">","right")}
         V           V           ${btn("/","downLeft")} ${btn("V","down")} ${btn("\\","downRight")}
         V           V           $submitButton.X        >                  >
         $statusPane >           >                      >                  >`
     frame.setDefaultCloseOperation(<swing:makeWindowConstants>.getDO_NOTHING_ON_CLOSE())
     frame.getContentPane().add(realPane)
     frame.pack()
     frame.show()
     bind instrumentPanel {
         to submit() {
             submitButton.setEnabled(false)
             car.accelerate(acceleration)
         }
         to prepareForNextTurn() {
             xIndicator.setText(makeXIndicator(car.getVelocity().getX()))
             yIndicator.setText(makeYIndicator(-(car.getVelocity().getY())))
             acceleration := makeCoord(0,0)
             submitButton.setEnabled(true)
             # Note, public static transferFocus on awt Component is not Java API, added in E environment
             <awt:makeComponent>.transferFocus([frame.getContentPane()], statusPane)
         }
         to setStatus(status) {statusPane.setText(status)}
         to upLeft() {acceleration := makeCoord(-1,-1)}
         to up() {acceleration := makeCoord(0,-1)}
         to upRight() {acceleration := makeCoord(1,-1)}
         to left() {acceleration := makeCoord(-1,0)}
         to zero() {acceleration := makeCoord(0,0)}
         to right() {acceleration := makeCoord(1,0)}
         to downLeft() {acceleration := makeCoord(-1,1)}
         to down() {acceleration := makeCoord(0,1)}
         to downRight() {acceleration := makeCoord(1,1)}
     }
     return instrumentPanel
 }
 
 def makeCar(name,startLocation,raceMap)  {
     var location := startLocation
     var acceleration := makeCoord(0,0)
     var velocity := makeCoord(0,0)
     var hasCrashed := false
     var hasFinished := false
     def instrumentPanel
     def sign(x) {
         return if (x > 0) {
             1
         } else if (x < 0) {
             -1
         } else {0}
     }
     
     def accelReactors := [].asMap().diverge()
 
     /**
      * Compute the path the car will take from the location at the
      * beginning of this turn to the end; return the result
      * as a list of coords
      */
     def computeIntermediateLocations(start,finish)  {
         def locations := [].diverge()
         def slope := (finish.getY() - start.getY()) / (finish.getX() - start.getX())
         def computeRemainingLocations(current) {
             var nextX := current.getX()
             var nextY := current.getY()
             var distToGo := 0
             #if the car is traveling faster in the x direction than
             #in the y direction, increment x position by one along
             #the path and compute the new y
             if (slope < 1.0 && slope > -1.0) {
                 distToGo := finish.getX() - current.getX()
                 nextX += sign(distToGo)
                 def distTraveled := nextX - start.getX()
                 nextY := start.getY() + ((slope * distTraveled) + 0.5) //1
                 #if the car is traveling faster in the y direction than
                 #in the x direction, increment y position by one along
                 #the path and compute new x
             } else {
                 distToGo := finish.getY() - current.getY()
                 nextY += sign(distToGo)
                 def distTraveled := nextY - start.getY()
                 nextX := start.getX() + ((distTraveled/slope) + 0.5) //1
             }
             def next := makeCoord(nextX,nextY)
             locations.push(next)
             if (!(next.samePlace(finish))) {
                 computeRemainingLocations(next)
             }
         }
         computeRemainingLocations(start)
         return locations
     }
     def car {
         to accelerate(accel) {
             traceln(`accelerating car $name`)
             acceleration := accel
             for each in accelReactors {
                 each.reactToAccel(car)
             }
         }
         to move(){
             traceln("into move")
             velocity += acceleration
             def newLocation := location + velocity
             traceln("got newlocation")
             def path := computeIntermediateLocations(location,newLocation)
             location := newLocation
             traceln("assigned  location")
             hasCrashed := hasCrashed || raceMap.causesCrash(path)
             hasFinished := hasFinished || raceMap.causesFinish(path)
             traceln("got crash finish")
             if (hasCrashed) {
                 instrumentPanel.setStatus("Crashed")
             } else if (hasFinished) {instrumentPanel.setStatus("Finished")}
             traceln("out of move")
         }
         to getLocation() {return location}
         to getVelocity() {return velocity}
         to hasCrashed() {return hasCrashed}
         to hasFinished() {return hasFinished}
         to getName() {return name}
         to prepareForNextTurn() {instrumentPanel.prepareForNextTurn()}
         to addAccelReactor(reactor) {accelReactors[reactor] := reactor}
         to removeAccelReactor(reactor) {accelReactors.remove(reactor)}
     }
     bind instrumentPanel := makeInstrumentPanel(car)
     return car
 }
 
 def makeTrackViewer(initialTextMap)  {
     def frame := <swing:makeJFrame>("Track View")
     def mapPane := <swing:makeJTextArea>(initialTextMap)
     def statusPane := <swing:makeJLabel>(" ")
     def realPane :=
       JPanel`$mapPane.Y
              $statusPane`
     frame.getContentPane().add(realPane)
     def windowListener {
         to windowClosing(event) {
             interp.continueAtTop()
         }
         match [verb,args] {}
     }
     frame.addWindowListener(windowListener)
     frame.pack()
     frame.show()
     def trackViewer {
         to refresh(textMap) {mapPane.setText(textMap)}
         to showStatus(status) {statusPane.setText(status)}
     }
     return trackViewer
 }
 
 def makeRaceMap() {
     def baseMap := [
         "..........W...............",
         "..........W...........FFFF",
         "......W...WW..............",
         "......W....W..............",
         "......W....WWW............",
         "......W........W..........",
         "......W.....W.............",
         "......W.....W.............",
         "......W...................",
         "......W..................."]
 
     def isWall(coord) :boolean {return baseMap[coord.getY()] [coord.getX()] == 'W' }
     def isFinish(coord) :boolean {return baseMap[coord.getY()] [coord.getX()] == 'F'}
     def pointCrash(coord) :boolean {
         var result := false
         if (coord.getX() < 0 || coord.getY() < 0 ||
               coord.getX() >= baseMap[0].size() || coord.getY() >= baseMap.size()) {
             result := true
         } else if (isWall(coord)) {
             result := true
         }
         return result
     }
     def raceMap {
         to getAsTextWithCars(cars) {
             def embedCarsInLine(index,line) {
                 def inBounds(xLoc) :boolean {return xLoc >= 0 && xLoc < line.size()}
                 var result := line
                 for each in cars {
                     if (each.getLocation().getY() == index && 
                           inBounds(each.getLocation().getX())) {
                         def editable := result.diverge(char)
                         editable[each.getLocation().getX()] := (each.getName())[0]
                         result := editable.snapshot()
                     }
                 }
                 return result
             }
             var result := ""
             for i => each in baseMap {
                 result := result + embedCarsInLine(i,each) + "\n"
             }
             return result
         }
         to causesCrash(path) :boolean {
             var result := false
             for each in path {
                 if (pointCrash(each)) {
                     result := true
                     break()
                 }
             }
             return result
         }
         to causesFinish(path) :boolean {
             var result := false
             for each in path {
                 if (pointCrash(each)) {
                     break()
                 } else if (isFinish(each)) {
                     result := true
                     break()
                 }
             }
             return result
         }
     }
     return raceMap
 }
 
 /**
  * create the cars, place them in a flex map to be used as a set
  */
 def makeCars(raceMap) {
     def carList := [ 
         makeCar("1",makeCoord(1,9),raceMap),
         makeCar("2",makeCoord(2,9),raceMap),
         makeCar("3",makeCoord(3,9),raceMap)]
     def carSet := [].asMap().diverge()
     for each in carList {carSet[each] := each}
     return carSet
 }
 
 /**
  * @author [mailto:marcs@skyhunter.com Marc Stiegler]
  */
 def makeRaceTrack() {
     def raceMap := makeRaceMap()
     def cars := makeCars(raceMap)
     var carsReadyToMove  := [].asMap().diverge()
     def mapViewer := makeTrackViewer(raceMap.getAsTextWithCars(cars))
     def raceTrack {
         to reactToAccel(car) {
             traceln("racetrack reacting to accel")
             carsReadyToMove[car] := car
             if (carsReadyToMove.size() >= cars.size()) {
                 raceTrack.completeNextTurn()
             }
         }
         to completeNextTurn() {
             def winners := [].diverge()
             for each in cars {
                 each.move()
                 if (each.hasCrashed()) {
                     cars.removeKey(each)
                 } else if (each.hasFinished()) {
                     winners.push(each)
                 }
             }
             mapViewer.refresh(raceMap.getAsTextWithCars(cars) )
             if (winners.size() == 1) {
                 mapViewer.showStatus(`Car ${winners[0].getName()} has won!`)
             } else if (winners.size() > 1) {
                 mapViewer.showStatus("It's a tie!")
             } else if (cars.size() == 0) {
                 mapViewer.showStatus("Everyone's dead!")
             } else {raceTrack.prepareForNextTurn()}
         }
         to prepareForNextTurn() {
             traceln("into prepare for next turn")
             carsReadyToMove := [].asMap().diverge()
             for each in cars {
                 each.prepareForNextTurn()
             }
         }
     }
     for each in cars {each.addAccelReactor(raceTrack)}
     return raceTrack
 }
 
 makeRaceTrack()
 # In actual code, the following line would not be commented out
 # interp.blockAtTop()

Personal tools
more tools