Walnut/Ordinary Programming/Ordinary Computing Examples

From Erights

(Difference between revisions)
Jump to: navigation, search
(Racetrack Game for a single computer: add missing "return instrumentPanel")
(FIELD_OTHER)
Line 1: Line 1:
[[Category:Walnut|2]]
[[Category:Walnut|2]]
-
===Ordinary Computing Examples===
+
FIELD_MESSAGE_domelacel
-
 
+
-
====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 21:28, 16 December 2008


FIELD_MESSAGE_domelacel

Personal tools
more tools