pathfinding

by not important

HTML

<script src="https://code.jquery.com/jquery-2.1.3.js"></script>
<script src="http://chancejs.com/chance.js"></script>
<div class="container" id="container"></div>

CSS

.container {
    position: relative;
    font-family: arial;
}

.row {
    overflow: auto;
}

.cell {
    text-align: center;
    font-size: 12px;
    width: 20px;
    height: 20px;
    background-color: #dae8f2;
    float: left;
    border: 1px solid #ccc;
    border-color: #efefef #ccc #ccc #efefef;
    transition: background-color 0.25s linear;
    line-height: 20px;
    text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.6);
}

.wall {
    background-color: #999;
}

.cell:not(.wall) {
    cursor: pointer;
}

.filled {
    background-color: #e3aad6;
}

.visited {
    background-color: #ff0;
}

.cell.path {
    background-color: #800;
    color: #fff;
    text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.6);
}

.container .cell.start-position,
.container .cell.target {
    background-color: #080;
    color: #fff;
    text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.6);
}

CoffeeScript

# pathfinding
rng = new Chance 19930910
class Pathfinder
    constructor: (@gridData, @targetPosition, @fillCallback, @visitedCallback, @foundCallback) ->
        @width = @gridData[0].length
        @height = @gridData.length

    parseGridData: ->
        data = []
        for row, y in @gridData
            for cell, x in row
                index = y * @width + x
                node =
                    open: !!cell
                    visited: false
                    index: 0
                    x: x
                    y: y
                data[index] = node
        data

    beginFill: (x, y) ->
        @startPosition = [x, y]
        @reset()
        @closeNode x, y
        @addNeighbors x, y
        @stepInterval = setInterval =>
            @nextStep()
        , 1000 / 60

    nextStep: ->
        if @open.length is 0
            clearInterval @stepInterval
            return
        [x, y] = @iToC @open.shift()
        @closeNode x, y
        @addNeighbors x, y

    addNeighbors: (x, y) ->
        {index} = @data[@cToI x, y]
        @addOpen x + 1, y, index
        @addOpen x - 1, y, index
        @addOpen x, y + 1, index
        @addOpen x, y - 1, index

    addOpen: (x, y, nodeIndex) ->
        index = @cToI x, y
        node = @data[index]
        if node.open
            if node.open
                @open.push index
                node.index = nodeIndex + 1
                node.open = false
                node.visited = true
                @visitedCallback x, y, node.index
        [tX, tY] = @targetPosition
        if x is tX and y is tY
            @targetFound()

    closeNode: (x, y) ->
        node = @data[@cToI x, y]
        node.open = false
        @fillCallback x, y, node.index

    targetFound: ->
        clearInterval @stepInterval
        @solutionPath = []
        @solutionPath.push @targetPosition
        while @walkSolution()
            true

    pathFound: ->
        path = @solutionPath.reverse()
        @foundCallback...