Last active
October 23, 2019 21:09
-
-
Save vicalloy/4603625 to your computer and use it in GitHub Desktop.
[coffeescript] maze generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fmtTime = (t) -> | |
d = new Date(null); | |
d.setSeconds(t/1000); | |
return d.toTimeString().substr 3, 5 | |
move = (obj, direction, step) -> | |
if !step? | |
step = 10 | |
attr = 'left' | |
attr = 'top' if direction in [0, 2] | |
step = -step if direction in [0, 3] | |
d = obj.css attr | |
d = d.substring 0, d.length - 2 | |
d = parseInt(d) + step; | |
obj.css attr, d + "px" | |
getNextBlockPos = (x, y, direction) -> | |
switch direction | |
when 0 then y -= 1 | |
when 1 then x += 1 | |
when 2 then y += 1 | |
when 3 then x -= 1 | |
return [x, y] | |
class Block | |
constructor: (@mmap, @x, @y, direction) -> | |
@walls = [true, true, true, true] # top,right,bottom,left | |
if mmap | |
mmap.mmap[x][y] = @ | |
if direction? | |
direction = (direction + 2) % 4 | |
@walls[direction] = false | |
getNextBlockPos: (direction) -> | |
return getNextBlockPos(@x, @y, direction) | |
getNextBlock: -> | |
directions = _.shuffle [0..3] | |
for direction in directions | |
if !@walls[direction] # if no wall | |
continue | |
pt = @getNextBlockPos(direction) | |
x = pt[0] | |
y = pt[1] | |
if x >= @mmap.maxX || x < 0 || y >= @mmap.maxY || y < 0 | |
continue | |
if @mmap.mmap[x][y] # if walked | |
continue | |
@walls[direction] = false | |
return new Block @mmap, x, y, direction | |
return false | |
class Map | |
resetMap: -> | |
@genMap @maxX, @maxY | |
genMap: (@maxX, @maxY) -> | |
@mmap = for x in [0...@maxX] | |
for y in [0...@maxY] | |
false | |
solution = [] | |
@solution = solution | |
block_stack = [new Block false, -1, -1] # a unused block | |
block = new Block @, 0, 0 | |
dowhile = -> | |
next_block = block.getNextBlock() | |
if next_block | |
block_stack.push block | |
block = next_block | |
if block.x == maxX - 1 && block.y == maxY - 1 # is end | |
for o in block_stack | |
if o.x >= 0 | |
solution.push [o.x, o.y] | |
solution.push [maxX - 1, maxY - 1] | |
else | |
block = block_stack.pop() | |
dowhile() while block_stack.length | |
moveNext: (x, y, direction) -> | |
if @mmap[x][y].walls[direction] # has wall | |
return false | |
return getNextBlockPos(x, y, direction) | |
class DrawMap | |
constructor: (@mmap, @cellWidth) -> | |
if @cellWidth == undefined | |
@cellWidth = 10 | |
getMapSize: -> | |
return [(@mmap.maxX + 2) * @cellWidth, (@mmap.maxY + 2) * @cellWidth] | |
createLine: (x1, y1, x2, y2, color) -> | |
#pass | |
createSolutionLine: (x1, y1, x2, y2) -> | |
@createLine(x1, y1, x2, y2) | |
drawStart: -> | |
drawEnd: -> | |
getCellCenter: (x, y) -> | |
w = @cellWidth | |
return [(x + 1) * w + w / 2, (y + 1) * w + w / 2] | |
drawSolution: -> | |
pre = [0, 0] | |
for o in @mmap.solution | |
p1 = @getCellCenter(pre[0], pre[1]) | |
p2 = @getCellCenter(o[0], o[1]) | |
@createSolutionLine(p1[0], p1[1], p2[0], p2[1]) | |
pre = o | |
drawCell: (block) -> | |
width = @cellWidth | |
x = block.x + 1 | |
y = block.y + 1 | |
walls = block.walls | |
if walls[0] | |
@createLine(x * width, y * width, (x + 1) * width + 1, y * width) | |
if walls[1] | |
@createLine((x + 1) * width, y * width, (x + 1) * width, (y + 1) * width + 1) | |
if walls[2] | |
@createLine(x * width, (y + 1) * width, (x + 1) * width + 1, (y + 1) * width) | |
if walls[3] | |
@createLine(x * width, y * width, x * width, (y + 1) * width + 1) | |
drawMap: -> | |
for y in [[email protected]] | |
for x in [[email protected]] | |
@drawCell(@mmap.mmap[x][y]) | |
@drawStart() | |
@drawEnd() | |
class HTML5DrawMap extends DrawMap | |
constructor: (@ctx, @mmap, @cellWidth) -> | |
super @mmap, @cellWidth | |
createLine: (x1, y1, x2, y2, color) -> | |
@ctx.moveTo x1, y1 | |
@ctx.lineTo x2, y2 | |
@ctx.stroke() | |
drawStart: -> | |
@ctx.fillText "S", @cellWidth + 1, @cellWidth * 2 - 1 | |
drawEnd: -> | |
@ctx.fillText "E", @cellWidth * @mmap.maxX + 1, @cellWidth * (@mmap.maxY + 1) - 1 | |
#init params | |
elCanvas = $ "#id-canvas" | |
elMapsize = $ '#id-mapsize' | |
elMan = $ '#id-man' | |
elTimer = $('#id-timer'); | |
ctx = elCanvas[0].getContext "2d" | |
startTime = new Date() | |
mmap = new Map() | |
mmap.genMap 20, 20 | |
manX = 0 | |
manY = 0 | |
win = false | |
timer = setInterval(-> | |
ss = ; | |
elTimer.text fmtTime(new Date() - startTime) | |
, 1000) | |
newGame = -> | |
manX = 0 | |
manY = 0 | |
win = false | |
elMan.css('left', '-493px') | |
elMan.css('top', '-482px') | |
size = elMapsize.val(); | |
if size > 48 | |
alert 'map size mast <= 48' | |
return | |
mmap.genMap size, size | |
ctx.beginPath() | |
ctx.clearRect 0, 0, 500, 500 | |
dmap.drawMap() | |
startTime = new Date() | |
isWin = -> | |
maxX == mmap.manX - 1 && manY == mmap.maxY - 1 | |
go = (direction)-> | |
if win | |
return | |
n = mmap.moveNext(manX, manY, direction) | |
if n | |
manX = n[0] | |
manY = n[1] | |
move(elMan, direction) | |
if isWin() | |
win = true | |
clearInterval(timer); | |
alert('you win'); | |
$(document).keydown((e) -> | |
k = e.keyCode || e.which | |
switch k | |
when 37 then go 3 | |
when 38 then go 0 | |
when 39 then go 1 | |
when 40 then go 2 | |
else return true | |
return false | |
) | |
dmap = new HTML5DrawMap(ctx, mmap, 10) | |
dmap.drawMap() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment