Pacman

Pacman finds himself in a grid filled with monsters...

Pacman Game

×

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?

This is a full blown Pacman game. If you're looking for an introduction to FunScript, then visit other tutorials, in particular the Mario game which is much simpler.

Images, mazes and graphics

Some of the graphics, maze structure and walls are defined as embedded strings or arrays in the following section, so that the game is stand-alone and easily portable.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
// Create image using the specified data
let createImage data =
  let img = Globals.document.createElement_img()
  img.src <- data
  img

// Define the structure of the maze using ASCII
let maze = ("\
##/------------7/------------7##,\
##|............|!............|##,\
##|./__7./___7.|!./___7./__7.|##,\
##|o|  !.|   !.|!.|   !.|  !o|##," + (...)).Split(',')

let tileBits = [| (...) |]

let blank = [| (...)|]

Maze functionality

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
let isWall (c:char) = "_|!/7LJ-".IndexOf(c) <> -1

let tileAt (x,y) = if x < 0 || x > 30 then ' ' else maze.[y].[x]
    
let isWallAt (x,y) = tileAt(x,y) |> isWall

let noWall (x,y) (ex,ey) =
  let bx, by = (x+6+ex) >>> 3, (y+6+ey) >>> 3
  isWallAt (bx,by) |> not

let verticallyAligned (x,y) =  (x % 8) = 5
let horizontallyAligned (x,y) = (y % 8) = 5
let isAligned n = (n % 8) = 5

let canGoUp (x,y) = isAligned x && noWall (x,y) (0,-4)
let canGoDown (x,y) = isAligned x && noWall (x,y) (0,5)
let canGoLeft (x,y) = isAligned y && noWall (x,y) (-4,0)
let canGoRight (x,y) = isAligned y && noWall (x,y) (5,0)

Background rendering

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
let tileColors = "BBBBBBBBBYY"
let tileChars =  "/_7|!L-J=.o"

let toTile (c:char) =
  let i = tileChars.IndexOf(c)
  if i = -1 then blank, 'B'
  else tileBits.[i], tileColors.[i]

let draw f (lines:int[]) =
  let width = 8   
  lines |> Array.iteri (fun y line ->
    for x = 0 to width-1 do
      let bit = (1 <<< (width - 1 - x))
      let pattern = line &&& bit
      if pattern <> 0 then f (x,y)
  )

let createBrush (context:CanvasRenderingContext2D) (r,g,b,a) =
  let id = context.createImageData(float 1,float 1)
  let d = id.data
  d.[0] <- float r; d.[1] <- float g
  d.[2] <- float b; d.[3] <- float a
  id

let createBackground () =
  let background = Globals.document.createElement_canvas() 
  background.width <- 256.
  background.height <- 256.  
  let context = background.getContext_2d()
  context.fillStyle <- "rgb(0,0,0)"
  context.fillRect (0., 0. , 256., 256.);
  let blue = createBrush context (63,63,255,255)
  let yellow = createBrush context (255,255,0,255)
  let lines = maze    
  for y = 0 to lines.Length-1 do
    let line = lines.[y]
    for x = 0 to line.Length-1 do
      let c = line.[x]
      let tile, color = toTile c        
      let brush = match color with 'Y' -> yellow | _ -> blue
      let f (x',y') = 
        context.putImageData
          (brush, float (x*8 + x'), float (y*8 + y'))
      draw f tile
  background

let countDots () =
  maze |> Array.sumBy (fun line -> 
    line.ToCharArray() 
    |> Array.sumBy (function '.' -> 1 | 'o' -> 1 | _ -> 0))

let clearCell (background : HTMLCanvasElement) (x,y) =
  let context = background.getContext_2d()
  context.fillStyle <- "rgb(0,0,0)"
  context.fillRect (float (x*8), float (y*8), 8., 8.);

Ghosts

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
let wrap (x,y) (dx,dy) =
  let x = 
    if dx = -1 && x = 0 then 30 * 8
    elif dx = 1  && x = 30 *8 then 0
    else x
  x + dx, y + dy

type Ghost(image:HTMLImageElement,x,y,v) =
  let mutable x' = x
  let mutable y' = y
  let mutable v' = v
  member val Image = image
  member val IsReturning = false with get, set
  member __.X = x'
  member __.Y = y' 
  member __.V = v'
  member ghost.Reset() =
    x' <- x
    y' <- y
  member ghost.Move(v) =
    v' <- v    
    let dx,dy = v
    let x,y = wrap (x',y') (dx,dy)
    x' <- x
    y' <- y

let createGhosts context = 
  [|
     redd, (16, 11), (1,0)
     cyand, (14, 15), (1,0)
     pinkd, (16, 13), (0,-1)
     oranged, (18, 15), (-1,0)
  |]
  |> Array.map (fun (data,(x,y),v) -> 
    Ghost(createImage data, (x*8)-7, (y*8)-3, v)    
  )

Ghost movement

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
let flood canFill fill (x,y) =
  let rec f n = function
    | [] -> ()
    | ps ->
      let ps = ps |> List.filter (fun (x,y) -> canFill (x,y))
      ps |> List.iter (fun (x,y) -> fill (x,y,n))
      ps 
      |> List.collect (fun (x,y) -> 
          [(x-1,y);(x+1,y);(x,y-1);(x,y+1)])
      |> f (n+1)
  f 0 [(x,y)]

let route_home =
  let numbers =
    maze |> Array.map (fun line ->
      line.ToCharArray() 
      |> Array.map (fun c -> if isWall c then 999 else -1)
    )
  let canFill (x:int,y:int) =
    y>=0 && y < (numbers.Length-1) &&
    x>=0 && x < (numbers.[y].Length-1) &&
    numbers.[y].[x] = -1      
  let fill (x,y,n) = numbers.[y].[x] <- n
  flood canFill fill (16,15)
  numbers

let fillValue (x,y) (ex,ey) =
  let bx = int (Globals.Math.floor(float ((x+6+ex)/8)))
  let by = int (Globals.Math.floor(float ((y+6+ey)/8)))
  route_home.[by].[bx]

let fillUp (x,y) = fillValue (x,y) (0,-4)
let fillDown (x,y) = fillValue (x,y) (0,5)
let fillLeft (x,y) = fillValue (x,y) (-4,0)
let fillRight (x,y) = fillValue (x,y) (5,0)

let chooseDirection (ghost:Ghost) =
  let x,y = ghost.X, ghost.Y
  let dx,dy = ghost.V
  let isBackwards (a,b) =
    (a <> 0 && a = -dx) || (b <> 0 && b = -dy)
  let directions = 
    [|if canGoLeft(x,y) then yield (-1,0), fillLeft(x,y)
      if canGoDown(x,y) then yield (0,1), fillDown(x,y)
      if canGoRight(x,y) then yield (1,0), fillRight(x,y)
      if canGoUp(x,y) then yield (0,-1), fillUp(x,y) |]
  let dx,dy =
    if ghost.IsReturning 
    then
      directions
      |> Array.sortBy snd        
      |> fun xs -> 
        let v, n = xs.[0]
        if n = 0 then ghost.IsReturning <- false
        v
    else      
      directions
      |> Array.map fst
      |> Array.filter (not << isBackwards)
      |> fun xs ->
        if xs.Length = 0 then 0, 0
        else
            let i = Globals.Math.random() * float xs.Length
            xs.[int (Globals.Math.floor i)]
  dx,dy

Keyboard input

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
type Keys() =
  let mutable keysPressed = Set.empty
  member keys.Reset () = keysPressed <- Set.empty
  member keys.IsPressed keyCode = Set.contains keyCode keysPressed
  member keys.Update (e : KeyboardEvent, pressed) =
    let keyCode = int e.keyCode
    let op =  if pressed then Set.add else Set.remove
    keysPressed <- op keyCode keysPressed

Pacman

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
type Pacman () =
  let pu1, pu2 = createImage pu1, createImage pu2
  let pd1, pd2 = createImage pd1, createImage pd2
  let pl1, pl2 = createImage pl1, createImage pl2
  let pr1, pr2 = createImage pr1, createImage pr2
  let lastp = ref pr1
  member __.ImageAt(x,y,v) =
    let p1, p2 =
      match !v with
      | -1,  0 -> pl1, pl2
      |  1,  0 -> pr1, pr2
      |  0, -1 -> pu1, pu2
      |  0,  1 -> pd1, pd2
      |  _,  _ -> !lastp, !lastp
    let x' = int (Globals.Math.floor(float (!x/6)))
    let y' = int (Globals.Math.floor(float (!y/6)))
    let p = if (x' + y') % 2 = 0 then p1 else p2
    lastp := p
    p
     
[<JSEmit("(new Audio({0})).play();")>]
let sound(file:string) : unit = failwith "never"

Level gameplay

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
let playLevel (keys:Keys, onLevelCompleted, onGameOver) =
  let pacman = Pacman()
  let pills = maze |> Array.map (fun line -> 
    line.ToCharArray() 
    |> Array.map (fun c -> c))

  let canvas = Globals.document.getElementsByTagName_canvas().[0]
  canvas.width <- 256.
  canvas.height <- 256.  
  let context = canvas.getContext_2d()
  context.fillStyle <- "rgb(0,0,0)"
  context.fillRect (0., 0. , 256., 256.);
  let bonusImages = 
    [| createImage _200; createImage _400; 
       createImage _800; createImage _1600 |]
  let background = createBackground()
  let ghosts = createGhosts(context)
  let blue,eyed = createImage blue, createImage eyed

  let dotsLeft = ref (countDots())
  let score = ref 0
  let bonus = ref 0
  let bonuses = ref []
  let energy = ref 128
  let flashCountdown = ref 0
  let powerCountdown = ref 0
  let x, y = ref (16 * 8 - 7), ref (23 * 8 - 3)
  let v = ref (0,0)

  let moveGhosts () =
    ghosts |> Array.iter (fun ghost -> 
      ghost.Move(chooseDirection ghost)
    )

  let movePacman () =
    let inputs =
       [| if keys.IsPressed 81 (*q*) then 
            yield canGoUp (!x,!y), (0,-1)
          if keys.IsPressed 65 (*a*) then 
            yield canGoDown (!x,!y), (0,1)
          if keys.IsPressed 90 (*z*) then 
            yield canGoLeft (!x,!y), (-1,0)
          if keys.IsPressed 88 (*x*) then 
            yield canGoRight (!x,!y), (1,0) |]
    let canGoForward =
      match !v with
      | 0,-1 -> canGoUp(!x,!y)
      | 0,1  -> canGoDown(!x,!y)
      | -1,0 -> canGoLeft(!x,!y)
      | 1, 0 -> canGoRight(!x,!y)
      | _ -> false
    let availableDirections =
      inputs
      |> Array.filter fst
      |> Array.map snd
      |> Array.sortBy (fun v' -> v' = !v)
    if availableDirections.Length > 0 then
      v := availableDirections.[0]
    elif inputs.Length = 0 || not canGoForward then
      v := 0,0         
    let x',y' = wrap (!x,!y) !v
    x := x'
    y := y'

  let eatPills () =
    let tx = int (Globals.Math.floor(float ((!x+6)/8)))
    let ty = int (Globals.Math.floor(float ((!y+6)/8)))     
    let c = pills.[ty].[tx]
    if c = '.' then
      pills.[ty].[tx] <- ' '
      clearCell background (tx,ty)
      score := !score + 10
      decr dotsLeft      
      sound("Dot5.wav")
    if c = 'o' then       
      pills.[ty].[tx] <- ' '
      clearCell background (tx,ty)
      bonus := 0
      score := !score + 50
      powerCountdown := 250
      decr dotsLeft
      sound("Powerup.wav")
      
  let touchingGhosts () =
    let px, py = !x, !y
    ghosts |> Array.filter (fun ghost ->
      let x,y = ghost.X, ghost.Y
      ((px >= x && px < x + 13) ||
       (x < px + 13 && x >= px)) &&
      ((py >= y && py < y + 13) ||
       (y < py + 13 && y >= py))
    )

  let collisionDetection () =
    let touched = touchingGhosts ()
    if touched.Length > 0
    then 
      if !powerCountdown > 0 then
        touched |> Array.iter (fun ghost -> 
          if not ghost.IsReturning then
            sound "EatGhost.wav"
            ghost.IsReturning <- true
            let added = int (Globals.Math.pow(2.,float !bonus))
            score := !score + added * 200 
            let image = bonusImages.[!bonus]
            bonuses := (100, (image, ghost.X, ghost.Y)) :: !bonuses
            bonus :=  min 3 (!bonus + 1)
        )
      else
        decr energy
        if !flashCountdown = 0 then sound "Hurt.wav"
        flashCountdown := 30
    if !flashCountdown > 0 then decr flashCountdown 
  
  let updateBonus () =
    let removals,remainders =
      !bonuses 
      |> List.map (fun (count,x) -> count-1,x)
      |> List.partition (fst >> (=) 0)
    bonuses := remainders

  let logic () =
    moveGhosts()
    movePacman()
    eatPills ()
    if !powerCountdown > 0 then decr powerCountdown
    collisionDetection()
    updateBonus ()

  let renderPacman () =
    let p = pacman.ImageAt(x,y,v)
    if (!flashCountdown >>> 1) % 2 = 0
    then context.drawImage(p, float !x, float !y)

  let renderEnergy () =
    context.fillStyle <- "yellow"
    context.fillRect(120., 250., float !energy, 2.)

  let renderGhosts () =
    ghosts |> Array.iter (fun ghost ->
      let image =
        if ghost.IsReturning then eyed
        else 
          if !powerCountdown = 0
          then ghost.Image
          elif !powerCountdown > 100 || 
                ((!powerCountdown >>> 3) % 2) <> 0 
          then blue
          else ghost.Image
      context.drawImage(image, float ghost.X, float ghost.Y) 
    )

  let renderScore () =
    context.fillStyle <- "white"
    context.font <- "bold 8px";
    context.fillText("Score " + (!score).ToString(), 0., 255.)

  let renderBonus () =
    !bonuses |> List.iter (fun (_,(image,x,y)) -> 
      context.drawImage(image, float x, float y))

  let render () =
    context.drawImage(background, 0., 0.)
    renderScore ()
    renderEnergy ()
    renderPacman()
    renderGhosts ()
    renderBonus ()

  let rec update () =
    logic ()
    render ()
    if !dotsLeft = 0 then onLevelCompleted()
    elif !energy <= 0 then onGameOver()
    else Globals.setTimeout(update, 1000. / 60.) |> ignore

  update()

Main gaim entry point

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
let rec game (keys:Keys) =
  keys.Reset()
  let canvas = Globals.document.getElementsByTagName_canvas().[0]
  let context = canvas.getContext_2d()
  let drawText(text,x,y) =
    context.fillStyle <- "white"
    context.font <- "bold 8px";
    context.fillText(text, x, y)
  let levelCompleted () =
    drawText("COMPLETED",96.,96.)
    Globals.setTimeout((fun () -> game(keys)),5000.) |> ignore 
  let gameOver () =
    drawText("GAME OVER",96.,96.)
    Globals.setTimeout((fun () -> game(keys)),5000.) |> ignore
  let start () =
    let background = createBackground()
    context.drawImage(background, 0., 0.)
    context.fillStyle <- "white"
    context.font <- "bold 8px";
    drawText("CLICK TO START", 88., 96.)
    canvas.onclick <- (fun e -> 
      canvas.onclick <- null
      playLevel (keys, levelCompleted, gameOver)
      box true
    )

  let canvas = Globals.document.getElementsByTagName_canvas().[0]
  canvas.width <- 256.
  canvas.height <- 256.  
  start()
  
let main () =
  let keys = Keys()
  Globals.addEventListener_keydown(fun e -> keys.Update(e, true); null)
  Globals.addEventListener_keyup(fun e -> keys.Update(e, false); null)
  game (keys)  

do Runtime.Run(directory="Web")
val createImage : data:string -> HTMLImageElement

Full name: Program.createImage
val data : string
val img : HTMLImageElement
type Globals

Full name: FunScript.TypeScript.Globals
property Globals.document: Document
member Document.createElement_img : unit -> HTMLImageElement
property HTMLImageElement.src: string
val maze : string []

Full name: Program.maze
"\
##|.L--J.L---J.LJ.L---J.L--J.|##,\
##|..........................|##,\
##|./__7./7./______7./7./__7.|##,\
##|.L--J.|!.L--7/--J.|!.L--J.|##,\
##|......|!....|!....|!......|##,\
##L____7.|L__7 |! /__J!./____J##,\
#######!.|/--J LJ L--7!.|#######,\
#######!.|! |!.|#######,\
#######!.|! /__==__7 |!.|#######,\
-------J.LJ | ! LJ.L-------,\
########. | **** ! .########,\
_______7./7 | ! /7./_______,\
#######!.|! L______J |!.|#######,\
#######!.|! |!.|#######,\
#######!.|! /______7 |!.|#######,\
##/----J.LJ L--7/--J LJ.L----7##,\
##|............|!............|##,\
##|./__7./___7.|!./___7./__7.|##,\
##|.L-7!.L---J.LJ.L---J.|/-J.|##,\
##|o..|!.......<>.......|!..o|##,\
##L_7.|!./7./______7./7.|!./_J##,\
##/-J.LJ.|!.L--7/--J.|!.LJ.L-7##,\
##|......|!....|!....|!......|##,\
###|./____JL__7.|!./__JL____7.|##,\
##|.L--------J.LJ.L--------J.|##,\
##|..........................|##,\
##L--------------------------J##"
val tileBits : int [] []

Full name: Program.tileBits
[|0b00000000;0b00000000;0b00000000;0b00000000;0b00000011;0b00000100;0b00001000;0b00001000|] // tl
  [|0b00000000;0b00000000;0b00000000;0b00000000;0b11111111;0b00000000;0b00000000;0b00000000|] // top
  [|0b00000000;0b00000000;0b00000000;0b00000000;0b11000000;0b00100000;0b00010000;0b00010000|] // tr
  [|0b00001000;0b00001000;0b00001000;0b00001000;0b00001000;0b00001000;0b00001000;0b00001000|] // left
  [|0b00010000;0b00010000;0b00010000;0b00010000;0b00010000;0b00010000;0b00010000;0b00010000|] // right
  [|0b00001000;0b00001000;0b00000100;0b00000011;0b00000000;0b00000000;0b00000000;0b00000000|] // bl
  [|0b00000000;0b00000000;0b00000000;0b11111111;0b00000000;0b00000000;0b00000000;0b00000000|] // bottom
  [|0b00010000;0b00010000;0b00100000;0b11000000;0b00000000;0b00000000;0b00000000;0b00000000|] // br
  [|0b00000000;0b00000000;0b00000000;0b00000000;0b11111111;0b00000000;0b00000000;0b00000000|] // door
  [|0b00000000;0b00000000;0b00000000;0b00011000;0b00011000;0b00000000;0b00000000;0b00000000|] // pill
  [|0b00000000;0b00011000;0b00111100;0b01111110;0b01111110;0b00111100;0b00011000;0b00000000|] // power
val blank : int []

Full name: Program.blank
0b00000000;0b00000000;0b00000000;0b00000000;0b00000000;0b00000000;0b00000000;0b00000000
val isWall : c:char -> bool

Full name: Program.isWall
val c : char
Multiple items
val char : value:'T -> char (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.char

--------------------
type char = System.Char

Full name: Microsoft.FSharp.Core.char
val tileAt : x:int * y:int -> char

Full name: Program.tileAt
val x : int
val y : int
val isWallAt : x:int * y:int -> bool

Full name: Program.isWallAt
val noWall : x:int * y:int -> ex:int * ey:int -> bool

Full name: Program.noWall
val ex : int
val ey : int
val bx : int
val by : int
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
val verticallyAligned : x:int * y:'a -> bool

Full name: Program.verticallyAligned
val y : 'a
val horizontallyAligned : x:'a * y:int -> bool

Full name: Program.horizontallyAligned
val x : 'a
val isAligned : n:int -> bool

Full name: Program.isAligned
val n : int
val canGoUp : x:int * y:int -> bool

Full name: Program.canGoUp
val canGoDown : x:int * y:int -> bool

Full name: Program.canGoDown
val canGoLeft : x:int * y:int -> bool

Full name: Program.canGoLeft
val canGoRight : x:int * y:int -> bool

Full name: Program.canGoRight
val tileColors : string

Full name: Program.tileColors
val tileChars : string

Full name: Program.tileChars
val toTile : c:char -> int [] * char

Full name: Program.toTile
val i : int
System.String.IndexOf(value: string) : int
System.String.IndexOf(value: char) : int
System.String.IndexOf(value: string, comparisonType: System.StringComparison) : int
System.String.IndexOf(value: string, startIndex: int) : int
System.String.IndexOf(value: char, startIndex: int) : int
System.String.IndexOf(value: string, startIndex: int, comparisonType: System.StringComparison) : int
System.String.IndexOf(value: string, startIndex: int, count: int) : int
System.String.IndexOf(value: char, startIndex: int, count: int) : int
System.String.IndexOf(value: string, startIndex: int, count: int, comparisonType: System.StringComparison) : int
val draw : f:(int * int -> unit) -> lines:int [] -> unit

Full name: Program.draw
val f : (int * int -> unit)
val lines : int []
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val width : int
module Array

from Microsoft.FSharp.Collections
val iteri : action:(int -> 'T -> unit) -> array:'T [] -> unit

Full name: Microsoft.FSharp.Collections.Array.iteri
val line : int
val bit : int
val pattern : int
val createBrush : context:CanvasRenderingContext2D -> r:int * g:int * b:int * a:int -> ImageData

Full name: Program.createBrush
val context : CanvasRenderingContext2D
type CanvasRenderingContext2D

Full name: FunScript.TypeScript.CanvasRenderingContext2D
val r : int
val g : int
val b : int
val a : int
val id : ImageData
member CanvasRenderingContext2D.createImageData : imageDataOrSw:obj * ?sh:float -> ImageData
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
val d : float array
property ImageData.data: float array
val createBackground : unit -> HTMLCanvasElement

Full name: Program.createBackground
val background : HTMLCanvasElement
member Document.createElement_canvas : unit -> HTMLCanvasElement
property HTMLCanvasElement.width: float
property HTMLCanvasElement.height: float
member HTMLCanvasElement.getContext_2d : unit -> CanvasRenderingContext2D
property CanvasRenderingContext2D.fillStyle: obj
member CanvasRenderingContext2D.fillRect : x:float * y:float * w:float * h:float -> unit
val blue : ImageData
val yellow : ImageData
val lines : string []
property System.Array.Length: int
val line : string
property System.String.Length: int
val tile : int []
val color : char
val brush : ImageData
val x' : int
val y' : int
member CanvasRenderingContext2D.putImageData : imagedata:ImageData * dx:float * dy:float * ?dirtyX:float * ?dirtyY:float * ?dirtyWidth:float * ?dirtyHeight:float -> unit
val countDots : unit -> int

Full name: Program.countDots
val sumBy : projection:('T -> 'U) -> array:'T [] -> 'U (requires member ( + ) and member get_Zero)

Full name: Microsoft.FSharp.Collections.Array.sumBy
System.String.ToCharArray() : char []
System.String.ToCharArray(startIndex: int, length: int) : char []
val clearCell : background:HTMLCanvasElement -> x:int * y:int -> unit

Full name: Program.clearCell
type HTMLCanvasElement =
  interface
    inherit HTMLElement
  end

Full name: FunScript.TypeScript.HTMLCanvasElement
val wrap : x:int * y:int -> dx:int * dy:int -> int * int

Full name: Program.wrap
val dx : int
val dy : int
Multiple items
type Ghost =
  new : image:HTMLImageElement * x:int * y:int * v:(int * int) -> Ghost
  member Move : v:(int * int) -> unit
  member Reset : unit -> unit
  member Image : HTMLImageElement
  member IsReturning : bool
  member V : int * int
  member X : int
  member Y : int
  member IsReturning : bool with set

Full name: Program.Ghost

--------------------
new : image:HTMLImageElement * x:int * y:int * v:(int * int) -> Ghost
val image : HTMLImageElement
type HTMLImageElement =
  interface
    inherit MSResourceMetadata
    inherit MSDataBindingExtensions
    inherit MSImageResourceExtensions
    inherit HTMLElement
  end

Full name: FunScript.TypeScript.HTMLImageElement
val v : int * int
val mutable x' : int
val mutable y' : int
val mutable v' : int * int
val set : elements:seq<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.set
member Ghost.X : int

Full name: Program.Ghost.X
val __ : Ghost
member Ghost.Y : int

Full name: Program.Ghost.Y
member Ghost.V : int * int

Full name: Program.Ghost.V
val ghost : Ghost
member Ghost.Reset : unit -> unit

Full name: Program.Ghost.Reset
member Ghost.Move : v:(int * int) -> unit

Full name: Program.Ghost.Move
val createGhosts : context:'a -> Ghost []

Full name: Program.createGhosts
val context : 'a
val redd : string

Full name: Program.redd
val cyand : string

Full name: Program.cyand
val pinkd : string

Full name: Program.pinkd
val oranged : string

Full name: Program.oranged
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val flood : canFill:(int * int -> bool) -> fill:(int * int * int -> unit) -> x:int * y:int -> unit

Full name: Program.flood
val canFill : (int * int -> bool)
val fill : (int * int * int -> unit)
val f : (int -> (int * int) list -> unit)
val ps : (int * int) list
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val iter : action:('T -> unit) -> list:'T list -> unit

Full name: Microsoft.FSharp.Collections.List.iter
val collect : mapping:('T -> 'U list) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.collect
val route_home : int [] []

Full name: Program.route_home
val numbers : int [] []
val fillValue : x:int * y:int -> ex:int * ey:int -> int

Full name: Program.fillValue
property Globals.Math: Math
member Math.floor : x:float -> float
val fillUp : x:int * y:int -> int

Full name: Program.fillUp
val fillDown : x:int * y:int -> int

Full name: Program.fillDown
val fillLeft : x:int * y:int -> int

Full name: Program.fillLeft
val fillRight : x:int * y:int -> int

Full name: Program.fillRight
val chooseDirection : ghost:Ghost -> int * int

Full name: Program.chooseDirection
property Ghost.X: int
property Ghost.Y: int
property Ghost.V: int * int
val isBackwards : (int * int -> bool)
val directions : ((int * int) * int) []
property Ghost.IsReturning: bool
val sortBy : projection:('T -> 'Key) -> array:'T [] -> 'T [] (requires comparison)

Full name: Microsoft.FSharp.Collections.Array.sortBy
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val xs : ((int * int) * int) []
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val filter : predicate:('T -> bool) -> array:'T [] -> 'T []

Full name: Microsoft.FSharp.Collections.Array.filter
val xs : (int * int) []
val i : float
member Math.random : unit -> float
Multiple items
type Keys =
  new : unit -> Keys
  member IsPressed : keyCode:int -> bool
  member Reset : unit -> unit
  member Update : e:KeyboardEvent * pressed:bool -> unit

Full name: Program.Keys

--------------------
new : unit -> Keys
val mutable keysPressed : Set<int>
Multiple items
module Set

from Microsoft.FSharp.Collections

--------------------
type Set<'T>

Full name: FunScript.TypeScript.Set<_>
val empty<'T (requires comparison)> : Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.empty
val keys : Keys
member Keys.Reset : unit -> unit

Full name: Program.Keys.Reset
member Keys.IsPressed : keyCode:int -> bool

Full name: Program.Keys.IsPressed
val keyCode : int
val contains : element:'T -> set:Set<'T> -> bool (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.contains
member Keys.Update : e:KeyboardEvent * pressed:bool -> unit

Full name: Program.Keys.Update
val e : KeyboardEvent
type KeyboardEvent =
  interface
    inherit UIEvent
  end

Full name: FunScript.TypeScript.KeyboardEvent
val pressed : bool
property KeyboardEvent.keyCode: float
val op : (int -> Set<int> -> Set<int>)
val add : value:'T -> set:Set<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.add
val remove : value:'T -> set:Set<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.remove
Multiple items
type Pacman =
  new : unit -> Pacman
  member ImageAt : x:int ref * y:int ref * v:(int * int) ref -> HTMLImageElement

Full name: Program.Pacman

--------------------
new : unit -> Pacman
val pu1 : HTMLImageElement
val pu2 : HTMLImageElement
val pu1 : string

Full name: Program.pu1
val pd1 : HTMLImageElement
val pd2 : HTMLImageElement
val pd1 : string

Full name: Program.pd1
val pl1 : HTMLImageElement
val pl2 : HTMLImageElement
val pl1 : string

Full name: Program.pl1
val pr1 : HTMLImageElement
val pr2 : HTMLImageElement
val pr1 : string

Full name: Program.pr1
val lastp : HTMLImageElement ref
Multiple items
val ref : value:'T -> 'T ref

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
member Pacman.ImageAt : x:int ref * y:int ref * v:(int * int) ref -> HTMLImageElement

Full name: Program.Pacman.ImageAt
val x : int ref
val y : int ref
val v : (int * int) ref
val p1 : HTMLImageElement
val p2 : HTMLImageElement
val p : HTMLImageElement
Multiple items
type JSEmitAttribute =
  inherit Attribute
  new : emit:string -> JSEmitAttribute
  member Emit : string

Full name: FunScript.JSEmitAttribute

--------------------
new : emit:string -> JSEmitAttribute
val sound : file:string -> unit

Full name: Program.sound
val file : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val playLevel : keys:Keys * onLevelCompleted:(unit -> unit) * onGameOver:(unit -> unit) -> unit

Full name: Program.playLevel
val onLevelCompleted : (unit -> unit)
val onGameOver : (unit -> unit)
val pacman : Pacman
val pills : char [] []
val canvas : HTMLCanvasElement
member Document.getElementsByTagName_canvas : unit -> NodeListOf<HTMLCanvasElement>
val bonusImages : HTMLImageElement []
val _200 : string

Full name: Program._200
val _400 : string

Full name: Program._400
val _800 : string

Full name: Program._800
val _1600 : string

Full name: Program._1600
val ghosts : Ghost []
val blue : HTMLImageElement
val eyed : HTMLImageElement
val blue : string

Full name: Program.blue
val dotsLeft : int ref
val score : int ref
val bonus : int ref
val bonuses : (int * (HTMLImageElement * int * int)) list ref
val energy : int ref
val flashCountdown : int ref
val powerCountdown : int ref
val moveGhosts : (unit -> unit)
val iter : action:('T -> unit) -> array:'T [] -> unit

Full name: Microsoft.FSharp.Collections.Array.iter
member Ghost.Move : v:(int * int) -> unit
val movePacman : (unit -> unit)
val inputs : (bool * (int * int)) []
member Keys.IsPressed : keyCode:int -> bool
val canGoForward : bool
val availableDirections : (int * int) []
val v' : int * int
val eatPills : (unit -> unit)
val tx : int
val ty : int
val decr : cell:int ref -> unit

Full name: Microsoft.FSharp.Core.Operators.decr
val touchingGhosts : (unit -> Ghost [])
val px : int
val py : int
val collisionDetection : (unit -> unit)
val touched : Ghost []
val added : int
member Math.pow : x:float * y:float -> float
val min : e1:'T -> e2:'T -> 'T (requires comparison)

Full name: Microsoft.FSharp.Core.Operators.min
val updateBonus : (unit -> unit)
val removals : (int * (HTMLImageElement * int * int)) list
val remainders : (int * (HTMLImageElement * int * int)) list
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val count : int
val x : HTMLImageElement * int * int
val partition : predicate:('T -> bool) -> list:'T list -> 'T list * 'T list

Full name: Microsoft.FSharp.Collections.List.partition
val logic : (unit -> unit)
val renderPacman : (unit -> unit)
member Pacman.ImageAt : x:int ref * y:int ref * v:(int * int) ref -> HTMLImageElement
member CanvasRenderingContext2D.drawImage : image:HTMLElement * offsetX:float * offsetY:float * ?width:float * ?height:float * ?canvasOffsetX:float * ?canvasOffsetY:float * ?canvasImageWidth:float * ?canvasImageHeight:float -> unit
val renderEnergy : (unit -> unit)
val renderGhosts : (unit -> unit)
property Ghost.Image: HTMLImageElement
val renderScore : (unit -> unit)
property CanvasRenderingContext2D.font: string
member CanvasRenderingContext2D.fillText : text:string * x:float * y:float * ?maxWidth:float -> unit
val renderBonus : (unit -> unit)
val render : (unit -> unit)
val update : (unit -> unit)
static member Globals.setTimeout : handler:obj * ?timeout:obj -> float
static member Globals.setTimeout : handler:obj * timeout:obj * params args:obj array -> float
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val game : keys:Keys -> unit

Full name: Program.game
member Keys.Reset : unit -> unit
val drawText : (string * float * float -> unit)
val text : string
val x : float
val y : float
val levelCompleted : (unit -> unit)
val gameOver : (unit -> unit)
val start : (unit -> unit)
property HTMLElement.onclick: System.Func<MouseEvent,obj>
val e : MouseEvent
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
val main : unit -> unit

Full name: Program.main
static member Globals.addEventListener_keydown : listener:System.Func<KeyboardEvent,obj> * ?useCapture:bool -> unit
member Keys.Update : e:KeyboardEvent * pressed:bool -> unit
static member Globals.addEventListener_keyup : listener:System.Func<KeyboardEvent,obj> * ?useCapture:bool -> unit

Live demo

Click here to open the sample live, running using JavaScript in a dialog window.

To look at the generated JavaScript, view the source of this web page and scroll to the end of the file.

Tutorials

Learn FunScript from the following introductory tutorials

Samples

Browse other amazing samples created with FunScript

Fork me on GitHub