mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 17:45:40 -05:00
Fixed #1090.
This commit is contained in:
parent
0fa5d264f4
commit
e67b4ae064
3 changed files with 53 additions and 53 deletions
|
@ -92,60 +92,58 @@ module.exports.consolidateThangs = consolidateThangs = (thangs) ->
|
|||
padding = 0
|
||||
console.log 'got max width', width, 'height', height, 'left', left, 'bottom', bottom, 'of thangs', thangs.length, 'structural', structural.length if debug
|
||||
grid = new Grid structural, width, height, padding, left, bottom
|
||||
console.log grid.toString() if debug
|
||||
|
||||
# Approach: start at bottom left. Go right, then up. At each occupied grid square, find the largest rectangle we can make starting at that corner, add a corresponding Thang to the grid, and unmark all occupied grid squares.
|
||||
# Since it's not like we're going to do any of these:
|
||||
# http://stackoverflow.com/questions/5919298/algorithm-for-finding-the-fewest-rectangles-to-cover-a-set-of-rectangles
|
||||
# http://stackoverflow.com/questions/4701887/find-the-set-of-largest-contiguous-rectangles-to-cover-multiple-areas
|
||||
dissection = []
|
||||
for y in grid.columns bottom, height
|
||||
for x in grid.rows left, width
|
||||
continue unless grid.grid[y][x].length
|
||||
rect = largestRectangle grid, y, x, false, debug
|
||||
vertices = rect.vertices()
|
||||
for y2 in [vertices[0].y ... vertices[1].y] # maybe ..?
|
||||
for x2 in [vertices[0].x ... vertices[2].x] # maybe ..?
|
||||
grid.grid[y2][x2] = []
|
||||
console.log grid.toString() if debug
|
||||
thang = structural[dissection.length] # grab one we already know is configured properly
|
||||
console.error 'Hmm, our dissection has more Thangs than the original structural Thangs?', dissection.length unless thang
|
||||
thang.width = rect.width
|
||||
thang.height = rect.height
|
||||
thang.pos.x = rect.x
|
||||
thang.pos.y = rect.y
|
||||
thang.createBodyDef()
|
||||
dissection.push thang
|
||||
addStructuralThang = (rect) ->
|
||||
thang = structural[dissection.length] # Grab one we already know is configured properly.
|
||||
console.error 'Hmm, our dissection has more Thangs than the original structural Thangs?', dissection.length unless thang
|
||||
thang.pos.x = rect.x
|
||||
thang.pos.y = rect.y
|
||||
thang.width = rect.width
|
||||
thang.height = rect.height
|
||||
thang.createBodyDef()
|
||||
dissection.push thang
|
||||
|
||||
dissectRectangles grid, addStructuralThang, false, debug
|
||||
|
||||
# Now add the new structural thangs back to thangs and return the ones not in the dissection.
|
||||
console.log 'Turned', structural.length, 'structural Thangs into', dissection.length, 'dissecting Thangs.'
|
||||
thangs.push dissection...
|
||||
structural[dissection.length ... structural.length]
|
||||
|
||||
module.exports.largestRectangle = largestRectangle = (grid, bottomY, leftX, wantEmpty, debug) ->
|
||||
# If wantEmpty, then we try to cover empty rectangles.
|
||||
# Otherwise, we try to cover occupied rectangles.
|
||||
coveredRows = []
|
||||
shortestCoveredRow = grid.width - leftX
|
||||
for y in grid.columns bottomY, grid.height
|
||||
coveredRow = 0
|
||||
for x in grid.rows leftX, leftX + shortestCoveredRow
|
||||
if Boolean(grid.grid[y][x].length) isnt wantEmpty
|
||||
++coveredRow
|
||||
else
|
||||
break
|
||||
break unless coveredRow
|
||||
coveredRows.push coveredRow
|
||||
shortestCoveredRow = Math.min(shortestCoveredRow, coveredRow)
|
||||
console.log 'largestRectangle() for', bottomY, leftX, 'got coveredRows', coveredRows if debug
|
||||
[maxArea, maxAreaRows, maxAreaRowLength, shortestRow] = [0, 0, 0, 0]
|
||||
for rowLength, rowIndex in coveredRows
|
||||
shortestRow ||= rowLength
|
||||
area = rowLength * (rowIndex + 1)
|
||||
if area > maxArea
|
||||
maxAreaRows = rowIndex + 1
|
||||
maxAreaRowLength = shortestRow
|
||||
maxArea = area
|
||||
shortestRow = Math.min(rowLength, shortestRow)
|
||||
console.log 'So largest rect has area', maxArea, 'with', maxAreaRows, 'rows of length', maxAreaRowLength if debug
|
||||
rect = new Rectangle leftX + maxAreaRowLength / 2, bottomY + maxAreaRows / 2, maxAreaRowLength, maxAreaRows
|
||||
console.log 'That corresponds to a rectangle', rect.toString() if debug
|
||||
rect
|
||||
|
||||
module.exports.dissectRectangles = dissectRectangles = (grid, rectangleCallback, wantEmpty, debug) ->
|
||||
# Mark Maxham's fast sweeper approach: https://github.com/codecombat/codecombat/issues/1090
|
||||
console.log grid.toString() if debug
|
||||
for x in grid.rows grid.left, grid.left + grid.width
|
||||
y = grid.clampColumn grid.bottom
|
||||
while y < grid.clampColumn grid.bottom + grid.height
|
||||
y2 = y # Note our current y.
|
||||
++y2 until occ x, y2, grid, wantEmpty # Sweep through y to expand 1xN rect.
|
||||
if y2 > y # If we get a hit, sweep X with that swath.
|
||||
x2 = x + 1
|
||||
++x2 until occCol x2, y, y2, grid, wantEmpty
|
||||
w = x2 - x
|
||||
h = y2 - y
|
||||
rect = addRect grid, x, y, w, h, wantEmpty
|
||||
rectangleCallback rect
|
||||
console.log grid.toString() if debug
|
||||
y = y2
|
||||
++y
|
||||
|
||||
occ = (x, y, grid, wantEmpty) ->
|
||||
return true if y > grid.bottom + grid.height or x > grid.left + grid.width
|
||||
console.error 'trying to check invalid coordinates', x, y, 'from grid', grid.bottom, grid.left, grid.width, grid.height unless grid.grid[y]?[x]
|
||||
Boolean(grid.grid[y][x].length) is wantEmpty
|
||||
|
||||
occCol = (x, y1, y2, grid, wantEmpty) ->
|
||||
for j in [y1 ... y2]
|
||||
if occ(x, j, grid, wantEmpty)
|
||||
return true
|
||||
false
|
||||
|
||||
addRect = (grid, leftX, bottomY, width, height, wantEmpty) ->
|
||||
for x in [leftX ... leftX + width]
|
||||
for y in [bottomY ... bottomY + height]
|
||||
grid.grid[y][x] = if wantEmpty then [true] else []
|
||||
new Rectangle leftX + width / 2, bottomY + height / 2, width, height
|
||||
|
|
|
@ -77,12 +77,14 @@ module.exports = # /app/lib/surface
|
|||
point: c.object {required: ['x', 'y']},
|
||||
x: {type: 'number'}
|
||||
y: {type: 'number'}
|
||||
z: {type: 'number'}
|
||||
|
||||
'surface:choose-region': c.object {required: ['points']},
|
||||
points: c.array {minItems: 2, maxItems: 2},
|
||||
c.object {required: ['x', 'y']},
|
||||
x: {type: 'number'}
|
||||
y: {type: 'number'}
|
||||
z: {type: 'number'}
|
||||
|
||||
'surface:new-thang-added': c.object {required: ['thang', 'sprite']},
|
||||
thang: {type: 'object'}
|
||||
|
|
|
@ -234,7 +234,7 @@ module.exports = class LevelPlaybackView extends CocoView
|
|||
button.addClass(classes[2]) if e.volume >= 1.0
|
||||
|
||||
onScrub: (e, options) ->
|
||||
e?.preventDefault()
|
||||
e?.preventDefault?()
|
||||
options.scrubDuration = 500
|
||||
Backbone.Mediator.publish('level:set-time', options)
|
||||
|
||||
|
@ -347,7 +347,7 @@ module.exports = class LevelPlaybackView extends CocoView
|
|||
shouldIgnore: -> return @disabled or @realTime
|
||||
|
||||
onTogglePlay: (e) ->
|
||||
e?.preventDefault()
|
||||
e?.preventDefault?()
|
||||
return if @shouldIgnore()
|
||||
button = $('#play-button')
|
||||
willPlay = button.hasClass('paused') or button.hasClass('ended')
|
||||
|
|
Loading…
Reference in a new issue