       @immediateNeighbors node
 
 class Node
-  constructor: (@pos, @cost, @parent = null) ->
+  constructor: (@pos) ->
     @key = JSON.stringify @pos
+    @g = @h = 0
 
   eq: (other) =>
     @key is other.key
 
 class PathFinder
-  constructor: (map, neighborStrategy=ImmediateNeighbors) ->
+  constructor: (map, neighborStrategy=ImmediateNeighbors, @costStrategy=AStar) ->
     @open = {}
     @closed = {}
     @path = null

    @start = new Node map.start()
    @goal = new Node map.goal()

    @start.f = 0 # FIXME for A*
    @open[@start.key] = @start

  distance: (from, to) ->
    [x1, y1] = from.pos
    [x2, y2] = to.pos
    Math.sqrt( (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) )

  # returns the current state for visualization
  state: =>

  # returns true if algorithm is complete
  step: =>
    return true if @path
    @current = current = _.first _.sortBy _.values(@open),
      (n) => @costStrategy n.g, n.h

    return true unless current

    if current.eq @goal
      path = [@goal.pos]
      while current.parent?
        current = current.parent
        path.unshift current.pos
      @path = path
      return true

    delete @open[current.key]
    @closed[current.key] = current

    for neighbor in @successors.of current
      newG = current.g + @distance current, neighbor

      if existing = @open[neighbor.key] or existing = @closed[neighbor.key]
        continue if newG >= existing.g
        existing.parent = current
        existing.g = newG
      else
        neighbor.parent = current
        neighbor.g = newG
        neighbor.h = @chebyshev neighbor, @goal
        @open[neighbor.key] = neighbor

    null # not done yet

Dijkstra = (g, h) -> g
Greedy   = (g, h) -> h
AStar    = (g, h) -> g + h

log = (msgs...) -> console.log msgs...
