Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>JavaScript Dijkstra's Algorithm Sample</title>
    <meta charset="utf-8">
<!--
Created using JS Bin
http://jsbin.com

Copyright (c) 2020 by wertrain (http://jsbin.com/wufufe/1/edit)

Released under the MIT license: http://jsbin.mit-license.org
-->
<meta name="robots" content="noindex">
    <meta name="description" content="">
    <meta name="author" content="wertrain">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style type="text/css">
      canvas {
        background-color:white;
        display: block;
      }
    </style>
    <canvas id="canvas" width="640" height="480"></canvas>
  </head>
  <body>
    <script src="scripts/map.js"></script>
    <script src="scripts/dijkstra.js"></script>
    <script src="scripts/chara.js"></script>
    <script src="scripts/item.js"></script>
    <script src="scripts/resources.js"></script>
    <script>
      "use strict";
      window.onload = function () {
          var canvas = document.getElementById('canvas');
          var context = canvas.getContext('2d');
          
          var mapchip = new Image();
          var charachip = new Image();
          var itemchip = new Image();
          var CHIP_SIZE = 32;
          mapchip.src = mapChipDataURL;
          charachip.src = charaChipDataURL;
          itemchip.src = itemChipDataURL;
          
          var map = new Map();
          map.create(mapchip, CHIP_SIZE);
          
          var chara = new Chara();
          chara.create(charachip, CHIP_SIZE);
          chara.put(1, 1);
          
          var getRandomPos = function() {
              var pos = null;
              do {
                  var movableWidth = map.getWidth() - 2 - 1, movableHeight = map.getHeight() - 2 - 1;
                  pos = {x: Math.floor(Math.random() * movableWidth) + 1, y: Math.floor(Math.random() * movableHeight) + 1};
              } while(map.isHit(pos.x, pos.y));
              return pos;
          }
          var dijkstra = new Dijkstra();
          
          var item = new Item();
          item.create(itemchip, CHIP_SIZE);
          
          var resetShortestPath = function() {
              var goal = getRandomPos();
              var route = dijkstra.findShortestPath(map.getArray(), chara.getX(), chara.getY(), goal.x, goal.y);
              item.put(goal.x, goal.y);
              chara.trace(route);
          }
          
          resetShortestPath();
          setInterval(function(){
              if (chara.update()) {
                  resetShortestPath();
              }
              map.draw(context);
              dijkstra.draw(context, CHIP_SIZE);
              item.draw(context);
              chara.draw(context);
          }, 33);
      }
    </script>
  <script>
var Chara = function() {
    this.charaChip_ = null;
    this.chipSize_ = 0;
    this.x_ = 0;
    this.y_ = 0;
    this.px_ = 0;
    this.py_ = 0;
    this.animCount_ = 0;
    this.animIndex_ = 0;
    this.direction_ = 0;
    this.movingLength_ = 0;
    this.route_ = null;
    this.influenceMap_ = null;
};
Chara.DIR_FRONT = 0;
Chara.DIR_LEFT  = 1;
Chara.DIR_RIGHT = 2;
Chara.DIR_BACK  = 3;
Chara.SPEED = 4;

Chara.prototype = {
    create: function(image, size) {
        this.charaChip_ = image;
        this.chipSize_ = size;
    },
    put: function(x, y) {
        this.x_ = x;
        this.y_ = y;
        this.px_ = this.x_ * this.chipSize_;
        this.py_ = this.y_ * this.chipSize_;
        this.direction_ = Chara.DIR_FRONT;
    },
    update: function() {
        if (this.animCount_++ > 8) {
            this.animIndex_ = (this.animIndex_ === 0) ? 2 : 0;
            this.animCount_ = 0;
        }
        if (this.movingLength_ > 0) {
            this.movingLength_ -= Chara.SPEED;
            if (this.movingLength_ <= 0) {
                this.movingLength_ = 0;
            }
            switch (this.direction_) {
            case Chara.DIR_FRONT:
                this.py_ += Chara.SPEED;
                if (this.movingLength_ === 0) {
                    ++this.y_;
                    this.py_ = this.y_ * this.chipSize_;
                }
                break;
            case Chara.DIR_LEFT:
                this.px_ -= Chara.SPEED;
                if (this.movingLength_ === 0) {
                    --this.x_;
                    this.px_ = this.x_ * this.chipSize_;
                }
                break;
            case Chara.DIR_RIGHT:
                this.px_ += Chara.SPEED;
                if (this.movingLength_ === 0) {
                    ++this.x_;
                    this.px_ = this.x_ * this.chipSize_;
                }
                break;
            case Chara.DIR_BACK:
                this.py_ -= Chara.SPEED;
                if (this.movingLength_ === 0) {
                    --this.y_;
                    this.py_ = this.y_ * this.chipSize_;
                }
                break;
            }
        } else if (this.route_ !== null) {
            for (var i = 0; i < this.route_.length; i++) {
                if (this.route_[i].x === this.x_ && this.route_[i].y === this.y_) {
                    if (i === 0) {
                       return true;
                    }
                    if (this.route_[i - 1].x !== this.x_) {
                        if (this.route_[i - 1].x < this.x_) {
                            this.move(Chara.DIR_LEFT);
                        } else {
                            this.move(Chara.DIR_RIGHT);
                        }
                    } else if (this.route_[i - 1].y !== this.y_) {
                        if (this.route_[i - 1].y < this.y_) {
                            this.move(Chara.DIR_BACK);
                        } else {
                            this.move(Chara.DIR_FRONT);
                        }
                    }
                    break;
                }
            }
        } else if (this.influenceMap_ !== null) {
            var xx = [0, -1, 1, 0], yy = [1, 0, 0, -1];
            for (var i = 0; i < 4; i++) {
                var current = this.influenceMap_[this.y_][this.x_];
                if (current < this.influenceMap_[this.y_ + yy[i]][this.x_ + xx[i]]) {
                    this.move(i);
                    break;
                }
            }
            if (this.movingLength_ === 0) {
                return true;
            }
        }
        return false;
    },
    move: function(dir) {
        if (this.movingLength_ !== 0) {
            return false;
        }
        this.moving = true;
        this.movingLength_ = this.chipSize_;
        this.direction_ = dir;
        return true;
    },
    trace: function(route) {
        this.route_ = route;
    },
    setInfluence: function(map) {
        this.influenceMap_ = map;
    },
    getX: function() {
        return this.x_;
    },
    getY: function() {
        return this.y_;
    },
    draw: function(context) {
        context.drawImage(this.charaChip_, 
            this.animIndex_ * this.chipSize_, this.direction_ * this.chipSize_, this.chipSize_, this.chipSize_,
            this.px_, this.py_, this.chipSize_, this.chipSize_
        );
    }
};

var Node = function(x, y, type) {
    this.score = Number.MAX_VALUE;
    this.prev = null;
    this.done = false;
    this.type = type;
    this.x = x;
    this.y = y;
};
Node.TYPE_PASS  = 0;
Node.TYPE_WALL  = 1;
Node.TYPE_ROUTE = 2;

var Dijkstra = function() {
    this.map_ = null;
    this.indeterminateList_ = [];
};

Dijkstra.prototype = {
    scoreFromMap: function(map, startX, startY) {
        this.map_ = new Array(map.length);
        for (var i = 0; i < map.length; i++) {
            this.map_[i] = new Array(map[i].length);
            for (var j = 0; j < map[i].length; j++) {
                this.map_[i][j] = new Node(j, i, map[i][j]);
            }
        }
        
        var startNode = this.map_[startY][startX];
        startNode.score = 0;
        this.indeterminateList_.push(startNode);
        
        while (this.indeterminateList_.length !== 0) {
            var node = null;
            var minIndex = -1, minScore = Number.MAX_VALUE;
            for (var i = 0; i < this.indeterminateList_.length; i++) {
                var tmp = this.indeterminateList_[i];
                if (tmp.done) {
                    continue;
                }
                if(tmp.score < minScore) {
                    minScore = tmp.score;
                    minIndex = i;
                    node = tmp;
                }
                this.maxScore_ = Math.max(this.maxScore_, tmp.score);
            }
            
            if (node === null) {
                break;
            }
            
            this.indeterminateList_.splice(minIndex, 1);
            node.done = true;
            
            var xx = [0, 1, 0, -1], yy = [1, 0, -1, 0];
            for (var i = 0; i < 4; i++) {
                var width = this.map_[node.y].length, height = this.map_.length;
                if (node.y + yy[i] < 0 || node.y + yy[i] >= height || 
                    node.x + xx[i] < 0 || node.x + xx[i] >= width) {
                    continue;
                }
                var t = this.map_[node.y + yy[i]][node.x + xx[i]];
                if (t.done || t.type == Node.TYPE_WALL) {
                    continue;
                }
                if (node.score + 1 < t.score) {
                    t.score = node.score + 1;
                    t.prev = node;
                    if (this.indeterminateList_.indexOf(t) === -1) {
                        this.indeterminateList_.push(t);
                    }
                }
            }
        }
    },
    findShortestPath: function(map, startX, startY, goalX, goalY) {
        this.scoreFromMap(map, startX, startY);
        var route = [];
        var goalNode = this.map_[goalY][goalX];
        while (goalNode !== null) {
            goalNode.type = Node.TYPE_ROUTE;
            route.push(goalNode);
            goalNode = goalNode.prev;
        }
        return route;
    },
    getScoredMap: function() {
        if (this.map_ === null) {
            return null;
        }
        var scoreMap = new Array(this.map_.length);
        for (var i = 0; i < this.map_.length; i++) {
            scoreMap[i] = new Array(this.map_[i].length);
            for (var j = 0; j < this.map_[i].length; j++) {
                var score = this.map_[i][j].score;
                if (score === Number.MAX_VALUE) {
                    score = -1;
                }
                scoreMap[i][j] = score;
            }
        }
        return scoreMap;
    },
    draw: function(context, chipSize) {
        for (var i = 0; i < this.map_.length; i++) {
            for (var j = 0; j < this.map_[i].length; j++) {
                var score = String(this.map_[i][j].score);
                if (this.map_[i][j].score < 10) {
                    score = '0' + score;
                }
                switch(this.map_[i][j].type) {
                case Node.TYPE_PASS:
                    context.font = '12px Georgia';
                    context.fillStyle = 'rgba(0, 0, 0, 1.0)';
                    context.fillText(score, j * chipSize + 10, i * chipSize + 20);
                    break;
                case Node.TYPE_ROUTE:
                    context.beginPath();
                    context.fillStyle = 'rgba(192, 80, 77, 0.5)';
                    context.fillRect(j * chipSize, i * chipSize, chipSize, chipSize);
                    context.font = '12px Georgia';
                    context.fillStyle = 'rgba(0, 0, 0, 1.0)';
                    context.fillText(score, j * chipSize + 10, i * chipSize + 20);
                    break;
                }
            }
        }
    },
};

var Item = function() {
    this.itemChip_ = null;
    this.chipSize_ = 0;
    this.x_ = 0;
    this.y_ = 0;
    this.px_ = 0;
    this.py_ = 0;
};

Item.prototype = {
    create: function(image, size) {
        this.itemChip_ = image;
        this.chipSize_ = size;
    },
    put: function(x, y) {
        this.x_ = x;
        this.y_ = y;
        this.px_ = this.x_ * this.chipSize_;
        this.py_ = this.y_ * this.chipSize_;
    },
    isHit: function(x, y) {
        return (this.x_ === x && this.y_ === y);
    },
    draw: function(context) {
        context.drawImage(this.itemChip_, 
            0, 0, this.chipSize_, this.chipSize_,
            this.px_, this.py_, this.chipSize_, this.chipSize_
        );
    }
};

var defaultMap = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
    [1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1], 
    [1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1], 
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
    [1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], 
    [1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1], 
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1], 
    [1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1], 
    [1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], 
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
    [1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1], 
    [1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1], 
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
];

var Map = function() {
    this.map_ = null;
    this.mapChip_ = null;
    this.chipSize_ = 0;
};

Map.prototype = {
    create: function(image, size, map) {
        this.mapChip_ = image;
        this.chipSize_ = size;
        if (typeof map == 'undefined') {
            this.map_ = defaultMap;
        }
    },
    draw: function(context) {
        for (var i = 0; i < this.map_.length; i++) {
            for (var j = 0; j < this.map_[i].length; j++) {
                var index = this.map_[i][j];
                context.drawImage(this.mapChip_, 
                    index * this.chipSize_, 0, this.chipSize_, this.chipSize_,
                    j * this.chipSize_, i * this.chipSize_, this.chipSize_, this.chipSize_
                );
            }
        }
    },
    getArray: function() {
        return this.map_;
    },
    isHit: function(x, y) {
        return this.map_[y][x] !== 0;
    },
    getWidth: function(index) {
        var i = index;
        if (typeof index === 'undefined') {
            i = 0;
        }
        return this.map_[i].length;
    },
    getHeight: function() {
        return this.map_.length;
    }
};

var mapChipDataURL = 'data:image/png;base64,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';
var charaChipDataURL = 'data:image/png;base64,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';
var itemChipDataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAAB3RJTUUH3wkRAw8sfQ+YpAAAA7NJREFUWMPtlk9vG1UUxX/3vRnHmUxNTOzEdgq0NAWEEGzaZYEVC2gldv0ClbpmwY5KpWLNvnwINvANukKV2CCEBEUVpHWcP3bs2jP22PPeZVFT/ql240asclYzo3fPPfe+eeddOMEJFkSlUpFn+TYP8lwqCuWlMJTzAJOx/sLkMDsqhXmeioNQ6tZwyxo+t6HUFumEHLHvIXAOryuMtb9ZDt4vF+RLQHpj/XS77b4mbbeOQmmfpfI0TR+/RFHNwg1V+QTlysZq8N4Hry9vnFkLC7/33IX20DfQ5bu44eA/sYsKeEJQrdZeUr28BddOw5kNpfFqZCtvnS5K0Qp7O1lM6jaDgjSHq6UmSTKYl3ymgH+or1ZrqN5qwPWr3tc/RuVdEc4WQjphgW6ibO6nlEd5vBfai11jNonjuyTJ3E7YmZVXKiFRVHsZvVxXrr9tbf3DKJKLYagl52TsHdve4BPHm4OxlpyXtjGxQiPyvpnGcUvjeJTu77vFtiCKXrNwY0u5dlW1/tFyJGcaDforK/JDr8v9fp/xKKeSObYwUjWG2HmW1McdkQsDY14x8JNL04OnpQjmbNGqwCULjfPecyFaUj3bkF0BTQeEuWN9MmEtn7BaXEKMsKUT3VPEWNsALgFfzUowT4ADEvXKOPeMo4KceqNGPY7BeXqFIpPdPewwJQRSVTKQv/U7mXIsLECBCYAHcgWnShgErK2+wHK5zLDbJc9GGBG8Km66Vh/HT/56XEwACogRgsBCmjH48SG8mOKSDG8Nbpo4mP5QRj1yBIebJ0AMhA7oo/SSIeH9JvagD4HFJQNwDifCI+foAllQxAEqgqiGIrO1zBQQilgLKyPveeA920miG62WRJ0OXkCdJ5hMSAR+G2e0TYGsWNaxMeLzPqLjFfGzT1ow56LoGrgzhuhnqIfOyTuDAetAPq0yMIYeQtsUaJolOsbKrhF1Ijt47gjaXdiKXRz3FL4LoLlj7cVDkVMl5wic146qHHpP1+V0JSAplvVhuCzf+5R7btgaqb+ZaH57pP4Bw8wvZsX7+86naX9QKjV7IpsCjaJq3AV5IMJDEZooTROwW4ikZYzec8PWdj78tu+z267T32GY+VlW/OzX8cZGrZHnV0qqNw00npwQQMXgTYATaSbqbu7kyTccJq1jmQcqlYocHBwogK1WGwX4YupwyZ8eIaqh4FdQ7uT4z7J2t/nv2OMZSNbXw4LqOWB16nD6mERFvLeCdofqfqXzaPK/DKHHsfYEJzjBH+XZ1TZ811IPAAAAAElFTkSuQmCC';
</script>
<script src="https://static.jsbin.com/js/render/edit.js?4.1.8"></script>
<script>jsbinShowEdit && jsbinShowEdit({"static":"https://static.jsbin.com","root":"https://jsbin.com"});</script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-1656750-34', 'auto');
ga('require', 'linkid', 'linkid.js');
ga('require', 'displayfeatures');
ga('send', 'pageview');

</script>

</body>
</html>
  
              
            
!

CSS

              
                img, canvas, /*iframe, video,*/ svg {
 max-width:100%;
}

.overflow-container {
 overflow-y:scroll;
 -webkit-overflow- scrolling:touch
}
              
            
!

JS

              
                
              
            
!
999px

Console