Walnut/Ordinary Programming/Ordinary Computing Examples

From Erights

(Difference between revisions)
Jump to: navigation, search
(removing spam from a bot)
(getdomdardom)
Line 1: Line 1:
 +
livarlic4tz
[[Category:Walnut|2]]
[[Category:Walnut|2]]

Revision as of 11:01, 24 January 2008

livarlic4tz

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) {
             E.call(target, verb, [])
         }
     }
     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)}
     }
 }
 
 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