-- moving player without moving any crates function draw_crate_to_move() if crate_to_move == nil then return end color(1,0,0) local x,y = crate_to_move.x, crate_to_move.y rect('line', left+(x-1)*side, top+(y-1)*side, side, side) end function car.update() if next_pending_move and Current_time >= next_pending_move then local dir = table.remove(pending_moves) move(dir, --[[add to undo]] false) if #pending_moves > 0 then next_pending_move = Current_time + 0.1 end end end function make_all_pending_moves() while #pending_moves > 0 do local dir = table.remove(pending_moves) move(dir, --[[add to undo]] false) end end function plan_move_to_empty_space(y, x) local path = find_empty_path(level_state, player, {y=y, x=x}) if path == nil then return end pending_moves = unwind_steps(path, {}) local src = level_state[player.y][player.x] local dest = level_state[y][x] local u = { {x=player.x, y=player.y, cell=src}, {x=x, y=y, cell=dest}} table.insert(undo_history, u) -- add to undo without making move yet next_pending_move = Current_time end function find_empty_path(level, src, dst) if not is_empty(level, dst.x, dst.y) then return end local done = initialize_array(false, lh, lw) local cands = {} table.insert(cands, {x=src.x, y=src.y}) while #cands > 0 do local cand = table.remove(cands, 1) local x,y = cand.x, cand.y if x == dst.x and y == dst.y then return cand end if y >= 1 and y <= lh and x >= 1 and x <= lw and not done[y][x] then done[y][x] = true local curr = level[y][x] if curr ~= CELL_WALL and curr ~= CELL_CRATE and curr ~= CELL_CRATE_ON_TARGET then table.insert(cands, {x=x-1, y=y, dir='left', prev=cand}) table.insert(cands, {x=x+1, y=y, dir='right', prev=cand}) table.insert(cands, {x=x, y=y-1, dir='up', prev=cand}) table.insert(cands, {x=x, y=y+1, dir='down', prev=cand}) end end end end function is_empty(level, x,y) local curr = level[y][x] return curr ~= CELL_WALL and curr ~= CELL_CRATE and curr ~= CELL_CRATE_ON_TARGET end function unwind_path(c) local result = {} while c do table.insert(result, {x=c.x, y=c.y}) c = c.prev end return result end function unwind_steps(c, out) -- insert steps in reverse order while c do table.insert(out, c.dir) c = c.prev end return out end function initialize_array(val, dim, ...) local result = {} local other_dims = {...} if #other_dims == 0 then for i=1,dim do table.insert(result, val) end else for i=1,dim do table.insert(result, initialize_array(val, ...)) end end return result end function dump_path(c) if c == nil then return end if not c.dir then assert(not c.moves) assert(not c.prev) io.stdout:write('\n') return end io.stdout:write('p'..c.dir..' ') local c2 = c.moves while c2 do if c2.dir then io.stdout:write('m'..c2.dir..' ') end c2 = c2.prev end dump_path(c.prev) end