Object subclass: #Map instanceVariableNames: 'ocMap xpos ypos ' classVariableNames: '' poolDictionaries: '' category: 'Hamster'! !Map methodsFor: 'initialize-release'! initialize | tempoc tempdict | ocMap:= OrderedCollection new. xpos:=0. ypos:=0. Transcript cr;show:'MapInit please wait'. 1 to: 132 do: [:i| tempoc:= OrderedCollection new. 1 to: 132 do: [:j| tempdict:= Dictionary new. tempdict at: 'north' put: 1. tempdict at: 'east' put: 1. tempdict at: 'south' put: 1. tempdict at: 'west' put: 1. tempdict at: 'dist' put: 65000. tempdict at: 'visited' put: 0. tempdict at: 'corn' put: 128. tempoc add: tempdict. ]. ocMap add: tempoc. Transcript show:' .'. ]. Transcript show:', done'; cr.! ! !Map methodsFor: 'accessing'! getAValueDirection | direction | direction:=self getNextCornDirection. (direction=-1) ifTrue:[direction:=self getHomeDirection]. ^direction.! getCornDistFromX: tx Y: ty | tsx tsy dist1 dist2 | tsx:=xpos.tsy:=ypos.xpos:=tx. ypos:=ty. ((self getCorns)>0) ifTrue:[xpos:=tsx.ypos:=tsy.^0]. dist1:=65001. ((self getDistanceFromHomeInDirection:1)>(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:1)=0) ifTrue:[dist2:=self getCornDistFromX:(xpos+1) Y:ypos. (dist2(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:2)=0) ifTrue:[dist2:=self getCornDistFromX:(xpos-1) Y:ypos. (dist2(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:3)=0) ifTrue:[dist2:=self getCornDistFromX:xpos Y:(ypos+1). (dist2(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:4)=0) ifTrue:[dist2:=self getCornDistFromX:xpos Y:(ypos-1). (dist265000) ifTrue:[((self getVisited)=0) ifTrue:[dist1:=0]]. (dist1>65000) ifTrue:[1 to:4 do:[:i| ((self getVisitedInDirection:i)=0) ifTrue:[dist1:=0]]]. xpos:=tsx.ypos:=tsy. dist1:=dist1+1. ^(dist1).! getCornInDirection: direction | tx ty | ((self wallInBetween: direction)=0) ifTrue:[ tx:=xpos. ty:=ypos. (direction=1) ifTrue: [tx:=tx+1]. (direction=2) ifTrue: [tx:=tx-1]. (direction=3) ifTrue: [ty:=ty+1]. (direction=4) ifTrue: [ty:=ty-1]. tx:=self transCoords: tx. ty:=self transCoords: ty. ^(((ocMap at:tx) at:ty) at:'corn'). ] ifFalse:[^-1].! getCorns | tx ty | tx:=xpos. ty:=ypos. tx:=self transCoords: tx. ty:=self transCoords: ty. ^(((ocMap at:tx) at:ty) at:'corn').! getDistanceFromHome | tx ty | tx:=self transCoords: xpos. ty:=self transCoords: ypos. ^(((ocMap at:tx) at:ty) at: 'dist').! getDistanceFromHomeInDirection: direction | tx ty | ((self wallInBetween: direction)=0) ifTrue:[ tx:=xpos. ty:=ypos. (direction=1) ifTrue: [tx:=tx+1]. (direction=2) ifTrue: [tx:=tx-1]. (direction=3) ifTrue: [ty:=ty+1]. (direction=4) ifTrue: [ty:=ty-1]. tx:=self transCoords: tx. ty:=self transCoords: ty. ^(((ocMap at:tx) at:ty) at: 'dist'). ] ifFalse:[^-1].! getHomeDirection | direction | 1 to: 4 do:[:i| ((self getDistanceFromHomeInDirection:i)<(self getDistanceFromHome)) ifTrue:[((self wallInBetween:i)=0) ifTrue:[direction:=i]]]. (xpos=0) ifTrue:[(ypos=0) ifTrue:[direction:=-1]]. ^direction.! getNextCornDirection | tsx tsy adir dist1 dist2 | adir:=0. 1 to: 4 do:[:i| ((self getCornInDirection:i)>0) ifTrue:[adir:=i]]. (adir=0) ifFalse:[^adir]. tsx:=xpos.tsy:=ypos. dist1:=65001. ((self getDistanceFromHomeInDirection:1)>(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:1)=0) ifTrue:[dist2:=self getCornDistFromX:(xpos+1) Y:ypos. (dist2(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:2)=0) ifTrue:[dist2:=self getCornDistFromX:(xpos-1) Y:ypos. (dist2(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:3)=0) ifTrue:["self halt."dist2:=self getCornDistFromX:xpos Y:(ypos+1). (dist2(self getDistanceFromHome)) ifTrue:[ ((self wallInBetween:4)=0) ifTrue:[dist2:=self getCornDistFromX:xpos Y:(ypos-1). (dist265000) ifTrue:[adir:=-1. 1 to: 4 do:[:i|((self getVisitedInDirection:i)=0) ifTrue:[adir:=i]]. ^adir] ifFalse:[^adir].! getVisited | tx ty | tx:=xpos. ty:=ypos. tx:=self transCoords: tx. ty:=self transCoords: ty. ^(((ocMap at:tx) at:ty) at:'visited').! getVisitedInDirection: direction | tx ty | ((self wallInBetween: direction)=0) ifTrue:[ tx:=xpos. ty:=ypos. (direction=1) ifTrue: [tx:=tx+1]. (direction=2) ifTrue: [tx:=tx-1]. (direction=3) ifTrue: [ty:=ty+1]. (direction=4) ifTrue: [ty:=ty-1]. tx:=self transCoords: tx. ty:=self transCoords: ty. ^(((ocMap at:tx) at:ty) at:'visited'). ] ifFalse:[^-1].! wallInBetween: direction | tx ty | tx:=self transCoords: xpos. ty:=self transCoords: ypos. (direction=1) ifTrue: [^(((ocMap at:tx) at:ty) at:'east')]. (direction=2) ifTrue: [^(((ocMap at:tx) at:ty) at:'west')]. (direction=3) ifTrue: [^(((ocMap at:tx) at:ty) at:'south')]. (direction=4) ifTrue: [^(((ocMap at:tx) at:ty) at:'north')].! ! !Map methodsFor: 'div'! n0:north e0:east s0:south w0:west ((ocMap at:66) at:66) at: 'north' put: north. ((ocMap at:66) at:66) at: 'east' put: east. ((ocMap at:66) at:66) at: 'south' put: south. ((ocMap at:66) at:66) at: 'west' put: west. ((ocMap at:66) at:66) at: 'dist' put: 0. ((ocMap at:66) at:66) at: 'corn' put: 0. ((ocMap at:66) at:66) at: 'visited' put: 1. xpos:=0. ypos:=0.! putCorn: ccount InDirection: direction | tx ty | (ccount>-1) ifTrue:[ tx:=xpos. ty:=ypos. (direction=1) ifTrue: [tx:=tx+1]. (direction=2) ifTrue: [tx:=tx-1]. (direction=3) ifTrue: [ty:=ty+1]. (direction=4) ifTrue: [ty:=ty-1]. tx:=self transCoords: tx. ty:=self transCoords: ty. ((ocMap at:tx) at:ty) at:'corn' put: ccount. ].! transCoords: avalue ^(avalue + 66).! updateDistance:distance x:txpos y:typos | tx ty | tx:=self transCoords: txpos. ty:=self transCoords: typos. ((ocMap at:tx) at:ty) at: 'dist' put: distance. tx:=xpos. ty:=ypos. xpos:=txpos. ypos:=typos. ((self getDistanceFromHomeInDirection: 1)>(distance+1)) ifTrue: [self updateDistance:(distance + 1) x:(txpos+1) y:typos]. ((self getDistanceFromHomeInDirection: 2)>(distance+1)) ifTrue: [self updateDistance:(distance + 1) x:(txpos-1) y:typos]. ((self getDistanceFromHomeInDirection: 3)>(distance+1)) ifTrue: [self updateDistance:(distance + 1) x:txpos y:(typos+1)]. ((self getDistanceFromHomeInDirection: 4)>(distance+1)) ifTrue: [self updateDistance:(distance + 1) x:txpos y:(typos-1)]. xpos:=tx. ypos:=ty.! updatePos: direction corn:numcorn | oldDistance txpos typos | txpos:=self transCoords: xpos. typos:=self transCoords: ypos. oldDistance:=((ocMap at:txpos) at:typos) at: 'dist'. (direction=1) ifTrue: [xpos:=xpos+1]. (direction=2) ifTrue: [xpos:=xpos-1]. (direction=3) ifTrue: [ypos:=ypos+1]. (direction=4) ifTrue: [ypos:=ypos-1]. txpos:=self transCoords: xpos. typos:=self transCoords: ypos. ((((ocMap at:txpos) at:typos) at: 'dist')>oldDistance) ifTrue: [self updateDistance:(oldDistance + 1) x:xpos y:ypos]. ((ocMap at:txpos) at:typos) at: 'visited' put: 1. ((ocMap at:txpos) at:typos) at: 'corn' put: numcorn.! updatePos: direction n:north e:east s:south w:west corn:numcorn cn: cn ce: ce cs: cs cw:cw | oldDistance txpos typos | txpos:=self transCoords: xpos. typos:=self transCoords: ypos. oldDistance:=((ocMap at:txpos) at:typos) at: 'dist'. (direction=1) ifTrue: [xpos:=xpos+1]. (direction=2) ifTrue: [xpos:=xpos-1]. (direction=3) ifTrue: [ypos:=ypos+1]. (direction=4) ifTrue: [ypos:=ypos-1]. txpos:=self transCoords: xpos. typos:=self transCoords: ypos. ((ocMap at:txpos) at:typos) at: 'north' put: north. ((ocMap at:txpos) at:typos) at: 'east' put: east. ((ocMap at:txpos) at:typos) at: 'south' put: south. ((ocMap at:txpos) at:typos) at: 'west' put: west. ((ocMap at:txpos) at:typos) at: 'visited' put: 1. ((((ocMap at:txpos) at:typos) at: 'dist')>oldDistance) ifTrue: [self updateDistance:(oldDistance + 1) x:xpos y:ypos]. ((ocMap at:txpos) at:typos) at: 'corn' put: numcorn. self putCorn: cn InDirection: 4. self putCorn: ce InDirection: 1. self putCorn: cs InDirection: 3. self putCorn: cw InDirection: 2.! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! Map class instanceVariableNames: ''! !Map class methodsFor: 'instance creation'! new ^super new! ! Object subclass: #Hamster instanceVariableNames: 'pid px py pdir pload plook pcorn socket connection stream rand ' classVariableNames: 'DirectionMap MAXLOAD PDirSymbols PlookSymbols Skip ' poolDictionaries: '' category: 'Hamster'! !Hamster methodsFor: 'Auskunft'! getCorn "gibt die Anzah der Koerner zurueck, die sich auf dem Feld befinden, wo sich der Hamster gerade befindet" ^pcorn! getCornInDirection: direction | tv | tv:=0. self turnToDirection: direction. ((self getLook)=#corn) ifTrue:[tv:=255]. ((self getLook)=#wall) ifTrue:[tv:=-1]. ^tv.! getDirection "gibt die Blickrichtung des Hamsters zurueck" ^PDirSymbols at: (pdir + 1).! getLoad "gibt die Anzah der Koerner in den Backen des Hamsters zurueck" ^pload! getLook "gibt zurueck, was sich auf dem Feld befindet, wohin der Hamster gerade schaut." ^plook! getPosition "gibt die Position des Hamsters reltiv zum Ausgangsfeld als Point zurueck" ^px@py! getWallInDirection: direction | tv | tv:=0. self turnToDirection: direction. ((self getLook)=#wall) ifTrue:[tv:=1]. ^tv! ! !Hamster methodsFor: 'Handlung'! drop: aNumber "Hamster legt aNumber Koerner ab, falls das nicht möglich ist, entsprechend weniger." | response oldLoad | oldLoad := self getLoad. self stream nextPut: $l; nextPutAll: (' ', (pid printString), ' ', ((aNumber negated) printString)); nextPut: Character cr; flush. response := (self stream upTo: Character lf) readStream. response skipSeparators. Skip ifTrue:[ response upTo: Character space. response skipSeparators]. pid := (response upTo: Character space) asNumber. response skipSeparators. pcorn := (response upTo: Character space) asNumber. response skipSeparators. pload := (response upTo: Character space) asNumber. ^oldLoad - pload.! move "Bewegt den Hamster in die momentane Richtung ein Feld nach vorne" | response oldPosition | oldPosition := self getPosition. self stream nextPut: $m; nextPutAll: (' ', pid printString); nextPut: Character cr; flush. response := (self stream upTo: Character lf) readStream. response skipSeparators. Skip ifTrue:[ response upTo: Character space. response skipSeparators]. pid := (response upTo: Character space) asNumber. response skipSeparators. px := (response upTo: Character space) asNumber. response skipSeparators. py := (response upTo: Character space) asNumber. response skipSeparators. plook:= PlookSymbols at: ((response upTo: Character space) asNumber + 1). response skipSeparators. pcorn := (response upTo: Character space) asNumber. ^(oldPosition = self getPosition).! moveToDirection: adirection self turnToDirection: adirection. self move.! take: aNumber "Hamster nimmt aNumber Koerner auf, falls das nicht möglich ist, entsprechend weniger." | response oldLoad | oldLoad := self getLoad. self stream nextPut: $l; nextPutAll: (' ', (pid printString), ' ', ((aNumber) printString)); nextPut: Character cr; flush. response := (self stream upTo: Character lf) readStream. response skipSeparators. Skip ifTrue:[ response upTo: Character space. response skipSeparators]. pid := (response upTo: Character space) asNumber. response skipSeparators. pcorn := (response upTo: Character space) asNumber. response skipSeparators. pload := (response upTo: Character space) asNumber. ^pload - oldLoad.! turn: aDirection "Hamster wird um 90 Grad in die Richtung gedreht, die aDirection angibt: #left - Drehung nach links (von der Blickrichtung aus) #right - Drehung nach rechts (von der Blickrichtung aus) #negative - Drehen im math. negativen Drehsinn #positive - Drehen im math. positiven Drehsinn" | response direction | direction := (aDirection isSymbol) ifTrue: [DirectionMap at: aDirection] ifFalse: [aDirection]. self stream nextPut: $t; nextPutAll: (' ', (pid printString), ' ', (direction printString)); nextPut: Character cr; flush. response := (self stream upTo: Character lf) readStream. response skipSeparators. Skip ifTrue:[ response upTo: Character space. response skipSeparators]. pid := (response upTo: Character space) asNumber. response skipSeparators. pdir := (response upTo: Character space) asNumber. response skipSeparators. plook:= PlookSymbols at: ((response upTo: Character space) asNumber + 1)! turnToDirection: adirection (adirection=1) ifTrue:[[(self getDirection)=#east] whileFalse:[self turn:#right]]. (adirection=2) ifTrue:[[(self getDirection)=#west] whileFalse:[self turn:#right]]. (adirection=3) ifTrue:[[(self getDirection)=#south] whileFalse:[self turn:#right]]. (adirection=4) ifTrue:[[(self getDirection)=#north] whileFalse:[self turn:#right]].! ! !Hamster methodsFor: 'Kontrolle'! control | abbruch amap adirection poszero | Transcript cr;cr;show:'*******************************************';cr; show:'* Smalltalk-Hamster *';cr; show:'* author: Christoph Walter *';cr; show:'*******************************************'. amap:=Map new initialize. abbruch:=0. [abbruch=0] whileTrue: [ poszero:=0. (((self getPosition) x)=0) ifTrue:[(((self getPosition) y)=0) ifTrue:[poszero:=1]]. (poszero=1) ifTrue:[ self drop:MAXLOAD. amap n0:(self getWallInDirection:4) e0:(self getWallInDirection:1) s0:(self getWallInDirection:3) w0:(self getWallInDirection:2). adirection:=amap getAValueDirection. (adirection>0) ifTrue:[self moveToDirection: adirection] ifFalse:[abbruch:=1]. ] ifFalse:[ self take:MAXLOAD. ((amap getVisitedInDirection:adirection)=1) ifTrue:[amap updatePos:adirection corn:(self getCorn)] ifFalse:[amap updatePos:adirection n:(self getWallInDirection:4) e:(self getWallInDirection:1) s:(self getWallInDirection:3) w:(self getWallInDirection:2) corn:(self getCorn) cn:(self getCornInDirection:4) ce:(self getCornInDirection:1) cs:(self getCornInDirection:3) cw:(self getCornInDirection:2)]. ((self getLoad)=MAXLOAD) ifFalse:[ adirection:=amap getAValueDirection. self moveToDirection: adirection. ] ifTrue:[ adirection:=amap getHomeDirection. self moveToDirection: adirection. ]. ]. ]. Transcript cr; show:'READY.'.! ! !Hamster methodsFor: 'Hilfsmethoden'! random "gibt eine Zufallszahl zurück" ^self rand next! ! !Hamster methodsFor: 'initialize-release'! initialize "initialisiere den Hamster, vor allem wichtig für die Kommunikation" "Fuer die Verbindung zum Labyrinth brauchen wir die Adresse des Rechners, auf dem das Labyrinth laeuft. Dies passiert ueber SocketAccessor getHostname. Falls das nicht funktioniert, muß die Adresse als Zeichenkette anstelle von (SocketAccessor getHostname) eingetragen werden." self socket: (SocketAccessor newTCPclientToHost: (SocketAccessor getHostname) port: 12345). self connection: (ExternalConnection new input: self socket; output: self socket). self stream: self connection readAppendStream. "interne Variablen initialisieren" pid := 0. px := 0. py := 0. plook := #wall. pcorn := 0. pload := 0.! ! !Hamster methodsFor: 'accessing'! connection ^connection! connection: anExternalConnection connection := anExternalConnection! rand ^rand isNil ifTrue: [rand := Random new.] ifFalse: [rand]! socket ^socket! socket: aSocketAccessor socket := aSocketAccessor! stream ^stream! stream: aReadWriteStream stream := aReadWriteStream! ! !Hamster methodsFor: 'others'! create "creates a new Hamster" | response | self stream nextPut: $c; nextPut: Character cr; flush. response := (self stream upTo: Character lf) readStream. response skipSeparators. Skip ifTrue:[response upTo: Character space. response skipSeparators.]. pid := (response upTo: Character space) asNumber. (pid = -1) ifTrue: [Dialog warn: 'Konnte den Hamster nicht mit dem Labyrinth verbinden'] ifFalse: [ response skipSeparators. px := (response upTo: Character space) asNumber. response skipSeparators. py := (response upTo: Character space) asNumber. response skipSeparators. pdir := (response upTo: Character space) asNumber. response skipSeparators. plook:= PlookSymbols at: ((response upTo: Character space) asNumber +1). response skipSeparators. pcorn := (response upTo: Character space) asNumber. response skipSeparators. pload := (response upTo: Character space) asNumber].! delete "deletes a Hamster" | response deletedId | self stream nextPut: $d; nextPutAll: (' ', pid printString); nextPut: Character cr; flush. "response := (self stream upTo: Character cr) readStream. response skipSeparators. response upTo: Character space. response skipSeparators. deletedId := (response upTo: Character space) asNumber."! run "Diese Funktion ist das Hamsterhauptprogramm :-)" self create. self control. self delete.! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! Hamster class instanceVariableNames: ''! !Hamster class methodsFor: 'class initialization'! initialize "Hamster initialize" MAXLOAD := 12. Skip := true. "It can happen that the command characters are missing due to some problem. If this is the case, set skip to false" PlookSymbols := #(#empty #corn #wall). " look - we are in cornwall" PDirSymbols := #(#east #north #west #south). "where are we looking at?" DirectionMap := Dictionary new. DirectionMap at: #left put: 1; at: #right put: -1; at: #positive put: 1; at: #negative put: -1.! ! !Hamster class methodsFor: 'instance creation'! new "Erzeugt eine neue Instanz der Klasse Hamster und initialisier die Variablen auf vernuenftige Standardwerte. Achtung das initialize, das hier aufgerufen wird, ist das der Instanz (im Protokoll initialize/release auf der instance-Seite), nicht die Klassenmethode initialize hier oben!!" ^super new initialize! ! !Hamster class methodsFor: 'examples'! example "Hamster example" | h | SocketAccessor allInstances do: [:sa | sa close]. h := self new. h run! ! Hamster initialize!