For a few minutes I started to think I can't assume the original position of the crate is always invisible. But no, I was just not handling the case where empty_cell == occupied cell (should be considered occupied)
3CIDHIL2YPGFIPMVPGROBQPUGPGF5OPDQXHSRCQ7EVLNKJ6XDNHQC local curr = level[y][x]if (y == empty_cell.y and x == empty_cell.x) or(not (y == occupied_cell.y and x == occupied_cell.x) andcurr ~= CELL_WALL andcurr ~= CELL_CRATE andcurr ~= CELL_CRATE_ON_TARGET) then
if is_empty(level, x,y, empty_cell, occupied_cell) then
function is_empty(level, x,y, empty, occupied)Real_print('aa', x,y, empty.x,empty.y, occupied.x,occupied.y)if empty.y ~= occupied.y or empty.x ~= occupied.x thenReal_print('bb')if x == empty.x and y == empty.y thenReal_print('cc')return trueendendif x == occupied.x and y == occupied.y thenReal_print('dd')return falseendlocal curr = level[y][x]return curr ~= CELL_WALL and curr ~= CELL_CRATE and curr ~= CELL_CRATE_ON_TARGETend
endfunction dump_path(c)if c == nil then return endif not c.dir thenassert(not c.moves)assert(not c.prev)io.stdout:write('\n')returnendio.stdout:write('push '..c.dir..' ')local c2 = c.moveswhile c2 doif c2.dir thenio.stdout:write('move '..c2.dir..' ')endc2 = c2.prevenddump_path(c.prev)