Skip to content

Instantly share code, notes, and snippets.

@vicalloy
Last active October 23, 2019 21:09
Show Gist options
  • Save vicalloy/4603625 to your computer and use it in GitHub Desktop.
Save vicalloy/4603625 to your computer and use it in GitHub Desktop.
[coffeescript] maze generator
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