Generating a maze with a simple algorithm
- Find available directions
- pick one at random
- if no available directions, backtrack to last position loop step 1 to 3 until back at start location
A Pen by Gabriel Valfridsson on CodePen.
| <div> | |
| <canvas></canvas> | |
| <ul> | |
| <li><label>Width:</label><input id=width type="text"/></li> | |
| <li><label>Height:</label><input id=height type="text"/></li> | |
| <li><label>Path Width:</label><input id=pathwidth type="text"/></li> | |
| <li><label>Wall Width:</label><input id=wallwidth type="text"/></li> | |
| <li><label>Outer Width:</label><input id=outerwidth type="text"/></li> | |
| <li><label>Path Color:</label><input id=pathcolor type="text"/></li> | |
| <li><label>Wall Color:</label><input id=wallcolor type="text"/></li> | |
| <li><label>Seed:</label><input id=seed type="text"/></li> | |
| <li><input id=randomseed type="button" value="Random Seed"/></li> | |
| </ul> | |
| </div> |
Generating a maze with a simple algorithm
A Pen by Gabriel Valfridsson on CodePen.
| pathWidth = 10 //Width of the Maze Path | |
| wall = 2 //Width of the Walls between Paths | |
| outerWall = 2 //Width of the Outer most wall | |
| width = 25 //Number paths fitted horisontally | |
| height = 25 //Number paths fitted vertically | |
| delay = 1 //Delay between algorithm cycles | |
| x = width/2|0 //Horisontal starting position | |
| y = height/2|0 //Vertical starting position | |
| seed = Math.random()*100000|0//Seed for random numbers | |
| wallColor = '#d24' //Color of the walls | |
| pathColor = '#222a33'//Color of the path | |
| randomGen = function(seed){ | |
| if(seed===undefined)var seed=performance.now() | |
| return function(){ | |
| seed = (seed * 9301 + 49297) % 233280 | |
| return seed/233280 | |
| } | |
| } | |
| init = function(){ | |
| offset = pathWidth/2+outerWall | |
| map = [] | |
| canvas = document.querySelector('canvas') | |
| ctx = canvas.getContext('2d') | |
| canvas.width = outerWall*2+width*(pathWidth+wall)-wall | |
| canvas.height = outerWall*2+height*(pathWidth+wall)-wall | |
| ctx.fillStyle = wallColor | |
| ctx.fillRect(0,0,canvas.width,canvas.height) | |
| random = randomGen(seed) | |
| ctx.strokeStyle = pathColor | |
| ctx.lineCap = 'square' | |
| ctx.lineWidth = pathWidth | |
| ctx.beginPath() | |
| for(var i=0;i<height*2;i++){ | |
| map[i] = [] | |
| for(var j=0;j<width*2;j++){ | |
| map[i][j] = false | |
| } | |
| } | |
| map[y*2][x*2] = true | |
| route = [[x,y]] | |
| ctx.moveTo(x*(pathWidth+wall)+offset, | |
| y*(pathWidth+wall)+offset) | |
| } | |
| init() | |
| inputWidth = document.getElementById('width') | |
| inputHeight = document.getElementById('height') | |
| inputPathWidth = document.getElementById('pathwidth') | |
| inputWallWidth = document.getElementById('wallwidth') | |
| inputOuterWidth = document.getElementById('outerwidth') | |
| inputPathColor = document.getElementById('pathcolor') | |
| inputWallColor = document.getElementById('wallcolor') | |
| inputSeed = document.getElementById('seed') | |
| buttonRandomSeed = document.getElementById('randomseed') | |
| settings = { | |
| display: function(){ | |
| inputWidth.value = width | |
| inputHeight.value = height | |
| inputPathWidth.value = pathWidth | |
| inputWallWidth.value = wall | |
| inputOuterWidth.value = outerWall | |
| inputPathColor.value = pathColor | |
| inputWallColor.value = wallColor | |
| inputSeed.value = seed | |
| }, | |
| check: function(){ | |
| if(inputWidth.value != width|| | |
| inputHeight.value != height|| | |
| inputPathWidth.value != pathWidth|| | |
| inputWallWidth.value != wall|| | |
| inputOuterWidth.value != outerWall|| | |
| inputPathColor.value != pathColor|| | |
| inputWallColor.value != wallColor|| | |
| inputSeed.value != seed){ | |
| settings.update() | |
| } | |
| }, | |
| update: function(){ | |
| clearTimeout(timer) | |
| width = parseFloat(inputWidth.value) | |
| height = parseFloat(inputHeight.value) | |
| pathWidth = parseFloat(inputPathWidth.value) | |
| wall = parseFloat(inputWallWidth.value) | |
| outerWall = parseFloat(inputOuterWidth.value) | |
| pathColor = inputPathColor.value | |
| wallColor = inputWallColor.value | |
| seed = parseFloat(inputSeed.value) | |
| x = width/2|0 | |
| y = height/2|0 | |
| init() | |
| loop() | |
| } | |
| } | |
| buttonRandomSeed.addEventListener('click',function(){ | |
| inputSeed.value = Math.random()*100000|0 | |
| }) | |
| loop = function(){ | |
| x = route[route.length-1][0]|0 | |
| y = route[route.length-1][1]|0 | |
| var directions = [[1,0],[-1,0],[0,1],[0,-1]], | |
| alternatives = [] | |
| for(var i=0;i<directions.length;i++){ | |
| if(map[(directions[i][1]+y)*2]!=undefined&& | |
| map[(directions[i][1]+y)*2][(directions[i][0]+x)*2]===false){ | |
| alternatives.push(directions[i]) | |
| } | |
| } | |
| if(alternatives.length===0){ | |
| route.pop() | |
| if(route.length>0){ | |
| ctx.moveTo(route[route.length-1][0]*(pathWidth+wall)+offset, | |
| route[route.length-1][1]*(pathWidth+wall)+offset) | |
| timer = setTimeout(loop,delay) | |
| } | |
| return; | |
| } | |
| direction = alternatives[random()*alternatives.length|0] | |
| route.push([direction[0]+x,direction[1]+y]) | |
| ctx.lineTo((direction[0]+x)*(pathWidth+wall)+offset, | |
| (direction[1]+y)*(pathWidth+wall)+offset) | |
| map[(direction[1]+y)*2][(direction[0]+x)*2] = true | |
| map[direction[1]+y*2][direction[0]+x*2] = true | |
| ctx.stroke() | |
| timer = setTimeout(loop,delay) | |
| } | |
| settings.display() | |
| loop() | |
| setInterval(settings.check,400) |
| body{ | |
| margin: 0; | |
| background: #222a33; | |
| text-align: center; | |
| } | |
| div{ | |
| display: inline-block; | |
| margin: 20px auto 0 auto; | |
| position: relative; | |
| } | |
| ul{ | |
| position: absolute; | |
| right: 0; | |
| width: 220px; | |
| height: 100%; | |
| float: left; | |
| list-style: none; | |
| padding: 0; | |
| margin: 0; | |
| text-align: left; | |
| color: #eee; | |
| font-family: helvetica; | |
| } | |
| li{ | |
| padding: 5px 5px 5px 5px; | |
| } | |
| label{ | |
| width: 50%; | |
| display: inline-block; | |
| box-sizing: border-box; | |
| text-align: right; | |
| padding-right: 5px; | |
| text-shadow: 2px 2px 0px rgba(0,0,0,0.2); | |
| } | |
| input{ | |
| width: 50%; | |
| height: 24px; | |
| box-sizing: border-box; | |
| padding: 0; | |
| margin: 0; | |
| border: none; | |
| background: #ccc; | |
| color: #333; | |
| font-weight: bold; | |
| text-align: center; | |
| border-radius: 2px; | |
| transition: background 200ms; | |
| box-shadow: 2px 2px 0px rgba(0,0,0,0.2); | |
| } | |
| input:focus{ | |
| outline: none; | |
| background: #fff; | |
| color: #222; | |
| } | |
| input[type=button]{ | |
| background: #111; | |
| color: #eee; | |
| margin-left: 50%; | |
| font-weight: normal; | |
| cursor: pointer; | |
| } | |
| input[type=button]:active{ | |
| transform: translate(2px,2px); | |
| box-shadow: 0px 0px 0px rgba(0,0,0,0.2); | |
| } | |
| canvas{ | |
| margin-right: 220px; | |
| display: block; | |
| float: left; | |
| } |