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