Phillip Trelford's Array

POKE 36879,255

Pacman Kata at Progressive F# Tutorials NYC 2013

I’m a bit of a Pacman fan so when I came across the Pacman Kata in the Kata Catalogue I was hooked:

Pacman finds himself in a grid filled with monsters. Will he be able to eat all the dots on the board before the monsters eat him?

Back in early 2012 we ran a Pacman Kata at the F#unctional Londoners meetup where you start with a maze and sprites and your task is to write a simple AI. After the event I extended the sample to run on Windows 8, Windows Phone as well as Silverlight and WPF, and somehow got a mention from Channel 9.

A few months back Neil Danson ported the sample to iOS, and over the last few weeks I’ve been playing with the HTML 5 canvas and have created a FunScript version too.

When Rich Minerich suggested a version for the Progressive F# Tutorials in New York I jumped at the chance, and teamed up with Mathias Brandewinder to create a fun session centred around Pacman:

Pacman Kata - Progressive F# Tutorials NYC 2013 from ptrelford

 

Code samples from the session: http://trelford.com/Pacman.Kata.zip

Test-driven Pacman

The session began with some good old unit tests:

[<Test>]
let ``pacman should wrap from left to right beyond left extent`` () =
    let p = wrap { x = leftExtent-1; y =0 }
    Assert.AreEqual(rightExtent, p.x)

Followed by automated acceptance tests using TickSpec:

Scenario: Pacman eats dots
  When pacman eats a pac-dot
  Then he scores 10

Scenario: Pacman eats power pellets
  When pacman eats a power pellet
  Then he scores 50

In the sample the scenarios are automated using attribute based step definitions:

type Property = PacDot | PowerPellet

let [<When>] ``pacman eats a pac-dot`` () =
    properties <- PacDot::properties

let [<When>] ``pacman eats a power pellet`` () =
    properties <- PowerPellet::properties

let [<Then>] ``he scores (.*)`` (points:int) =
    let scored =
        properties |> List.sumBy (function
            | PacDot -> 10
            | PowerPellet -> 50
        )
    Assert.AreEqual(points, scored)

Controls

Next up we looked at implementing keyboard controls, first with Mario and then Pacman, both in FunScript:

Pacman keys 

The controls can be composed from simple functions:

let left (dx,_) p = if dx = –1 then {p with x=p.x+dx} else p
let right (dx,_) p = if dx = 1 then {p with x=p.x+dx} else p
let up (_,dy) p = if dy = -1 then {p with y=p.y+dy} else p
let down (_,dy) p = if dy = 1 then {p with y=p.y+dy} else p

let step dir pacman = pacman |> left dir |> right dir |> up dir |> down dir

Ghosts

The grand finale was writing your own AI for the Ghosts (or Pacman) using an API designed by Mathias specifically for the session:

// Decision is based on current move, line of sight and possible moves
member this.Decide (current: Move) (lineOfSight: Sight) (choices: Move Set) =
    n <- n + 1
           
    let inSight (creatures:Creature list) =
        creatures                
        |> List.exists (function PacMan 0 -> true | _ -> false)

    let standard  () =
        let restricted =                 
            choices 
            |> Set.filter (fun c -> not (c = backwards current))
        if (restricted |> Set.count > 0)
        then randomMove restricted
        else randomMove choices

    let home () =
        let s = lineOfSight
        let xs = [Up,s.Up; Down,s.Down; Left,s.Left; Right,s.Right]
        let x = 
            xs 
            |> List.tryFind (fun (d,xs) ->
                xs |> List.exists (snd >> inSight)
            )
        match x with
        | Some (d,_) -> d
        | None -> standard ()

    if (n / 500) % 2 = 0 then home ()
    else standard ()

The simple AI above switches the ghosts between homing in on Pacman and random moves every 500 frame updates (roughly every 8 seconds).

At the end we played off Mathias’s payoff function based Pacman AI against my simple Ghosts on the big screen which ended in a tie :)

Blue ghosts

In the more competitive Pacman session ran by Paulmichael Blasucci and Rich Minerich the final was between Jack Fox and Tyler Smith.

More fun

And there’s more fun to come, Rich Minerich will be running a Pacman competition at the Progressive F# Tutorials in London this year:

ProgFsharp London 2013

and there’s a Pacman Kata scheduled for November at the F#unctional Londoners meetup.

Pingbacks and trackbacks (1)+

Comments are closed