
The grid is loaded from a text file that uses symbols to map the layout, currently I use a very simple layout that looks like this:
* * * * * * * * * * *
* # . . . _ . . . # *
* . * * * * * * * . *
* . * * * * * * * . *
* . . . . # . . . . *
* . * * * * * * * . *
* . * * * * * * * . *
* . . . . # . . . . *
* . * * * * * * * . *
* . * * * * * * * . *
* # . . . _ . . . # *
* * * * * * * * * * *
* Wall
. Food
# Power Pill
_ Empty
When the game starts off Pacman is in the lower empty cell and the Monster in the top empty cell. The arrow keys move Pacman around and the Monster tracks the Pacman. The rules are split into four drl files; base, key-handlers, Pacman and Monster.
A KeyListener implementation is hooked up to a WorkingMemory EntryPoint and feeds in key presses. From the KeyEvent it creates a derived (not in WorkingMemory) possible Direction and validates that Direction. If the new Direction is valid the old Direction is retracted and the new one inserted. The exitpoint is used to send print information to a channel, which is appended to the GUI.
rule KeyListenerRule dialect "mvel" whenAs the Tick, simulated time, increases we attempt to change a Character's Location based on the given Direction. The rule makes sure the new Location is valid, and if so schedules the move to the new Location, in time with the Tick.
$keyEvent : KeyEvent() from entry-point "KeyListener"
$char : Character( name == "Pacman" )
$l : Location( character == $char )
$newD : Direction() from createDirection( $l.character, $keyEvent )
$target : Cell( row == ($l.row + $newD.vertical), col == ($l.col + $newD.horizontal) )
CellContents( cell == $target, cellType != CellType.WALL )
$oldD : Direction( character == $l.character )
then
exitPoints["ConsoleExitPoint" ].insert( "insert " + $newD + "\n" );
retract( $keyEvent );
retract( $oldD );
insert( $newD );
end
rule validDirection dialect "mvel" whenAs the pacman moves around it detects the CellContents, if it's Food it'll increase the score by 1.
$l : Location( )
$d : Direction( character == $l.character )
$target : Cell( row == ($l.row + $d.vertical), col == ($l.col +
$d.horizontal) )
CellContents( cell == $target, cellType != CellType.WALL )
not ScheduledLocationUpdate( location == $l )
$t : Tick()
then
insert( new ScheduledLocationUpdate($l, $l.row += $d.vertical,
$l.col += $d.horizontal, $t.tock + 1) );
end
rule setNewDirection dialect "mvel" when
$s : ScheduledLocationUpdate()
$l : Location( this == $s.location )
Tick( tock == $s.tock )
then
exitPoints["ConsoleExitPoint"].insert( "set new Location " + $l + "\n" );
modify( $l ) { row = $s.row, col = $s.col };
retract( $s );
end
rule EatFood dialect "mvel" no-loop whenAmong other things it's also looking out for Monster collisions.
$char : Character( name == "Pacman" )
$l : Location( character == $char )
$target : Cell( row == $l.row, col == $l.col)
$contents : CellContents( cell == $target, cellType == CellType.FOOD )
$s : Score()
then
modify( $contents ) { cellType = CellType.EMPTY };
modify( $s ) { score += 1 };
end
rule MonsterCollision dialect "mvel" no-loop whenThe implementation currently uses a simple distance diff from the Monster to the Pacman to determine the Monster direction. The direction must be valid and if both a horizontal and a vertical direction is valid it uses dynamic salience to pick the one with the highest difference. This is a simplistic approach, just to get the ball rolling, ideally we would implement the logic as in the original arcade game.
$pac : Character( name == "Pacman" )
$pacLoc : Location( character == $pac )
$mon : Character( name == "Monster" )
$monLoc : Location( character == $mon, col == $pacLoc.col, row == $pacLoc.row )
$t : Tick()
then
retract( $t );
end
rule FinishedKilled dialect "mvel" when
$pac : Character( name == "Pacman" )
$pacLoc : Location( character == $pac )
$mon : Character( name == "Monster" )
$monLoc : Location( character == $mon, col == $pacLoc.col, row == $pacLoc.row )
not Tick()
$s : Score()
then
exitPoints["ConsoleExitPoint"].insert( "Killed!!!! score = " + $s.score + " \n" );
kcontext.knowledgeRuntime.halt();
end
rule GoRight dialect "mvel" salience (Math.abs( $df.colDiff )) whenRunning the game and pressing the left arrow gives the following output. Notice Pacman moves to the left and stops when he reaches the wall, the Monster tracks him to the left and then comes down for the kill.
$df : DirectionDiff(colDiff > 0 )
$target : Cell( row == $df.row, col == ($df.col + 1) )
CellContents( cell == $target, cellType != CellType.WALL )
$d : Direction( character == $df.fromChar, horizontal != Direction.RIGHT)
then
retract( $d );
retract( $df );
insert( new Direction($df.fromChar, Direction.RIGHT, 0 ) );
end
rule GoDown dialect "mvel" salience (Math.abs( $df.rowDiff )) when
$df : DirectionDiff(rowDiff < 0 )
$target : Cell( col == $df.col, row == ($df.row - 1))
CellContents( cell == $target, cellType != CellType.WALL )
$d : Direction( character == $df.fromChar, vertical != Direction.DOWN)
then
retract( $d );
retract( $df );
insert( new Direction($df.fromChar, 0, Direction.DOWN ) );
end
insert Direction Pacman speed = 5 LEFTI've committed everything to drools-examples, you'll need drools trunk, as there are a few fixes necessary for this to work:
set new Location Location Monster speed = 3 10:4
set new Location Location Pacman speed = 5 1:4
set new Location Location Monster speed = 3 10:3
set new Location Location Pacman speed = 5 1:3
set new Location Location Monster speed = 3 10:4
set new Location Location Monster speed = 3 10:3
set new Location Location Pacman speed = 5 1:2
set new Location Location Monster speed = 3 10:2
retract Direction Monster speed = 3 LEFT
set new Location Location Monster speed = 3 10:1
set new Location Location Pacman speed = 5 1:1
retract Direction Pacman speed = 5 LEFT
set new Location Location Monster speed = 3 9:1
set new Location Location Monster speed = 3 8:1
set new Location Location Monster speed = 3 7:1
set new Location Location Monster speed = 3 6:1
set new Location Location Monster speed = 3 5:1
set new Location Location Monster speed = 3 4:1
set new Location Location Monster speed = 3 3:1
set new Location Location Monster speed = 3 2:1
set new Location Location Monster speed = 3 1:1
Killed!!!! score = 8
trunk/drools-examples/drools-examples-drl/src/main/java/org/drools/examples/pacman/
trunk/drools-examples/drools-examples-drl/src/main/resources/org/drools/examples/pacman/
trunk/drools-examples/drools-examples-drl/src/main/rules/org/drools/examples/pacman/
It's still very basic. Next it needs to be hooked up to a GUI, such as SwtPacman, the source code of which is provided here on a wiki page where you can also add notes:
http://www.jboss.org/community/docs/DOC-14378
Then it should be updated to real Pacman grid layouts and all the monsters added, each with it's own custom logic. There is also additional logic like Ghosts slowing down when they turn corners and Pacman slowing down when he eats food. You can find out all the details at Wikipedia, here.
Ghost Color | Original Pac Man[13] | American Pac-Man | ||||||
---|---|---|---|---|---|---|---|---|
Character (Personality) | Translation | Nickname | Translation | Alternate character | Alternate nickname | Character (Personality) | Nickname | |
Red | Oikake (????) | chaser | Akabei (???) | red guy | Urchin | Macky | Shadow | Blinky |
Pink | Machibuse (????) | ambusher | Pinky (????) | pink guy | Romp | Micky | Speedy | Pinky |
Cyan | Kimagure (????) | fickle | Aosuke (??) | blue guy | Stylist | Mucky | Bashful | Inky |
Orange | Otoboke (???) | stupid | Guzuta (???) | slow guy | Crybaby | Mocky | Pokey | Clyde |
I hope everyone finds this useful, and if anyone wants to help me finish this please dive straight in :)

tried to find link in wiki -- got Article not found
ReplyDeletepropoer url is http://www.jboss.org/community/docs/DOC-14378?uniqueTitle=false
And no,
ReplyDeletehttp://www.jboss.org/community/servlet/JiveServlet/download/14378-1-6930/SwtPacMan.zip
doesnt work
Error
An general error occurred while processing your request.
Thanks, the post is now corrected, also noticed bad copy paste for some code, which is also corrected.
ReplyDelete