├── js ├── .gitkeep └── app.js ├── README.md ├── assets ├── boy.png ├── grass.png ├── item.png ├── step.mp3 ├── bgsound.mp3 ├── main_bg.png ├── sprites.png └── success.mp3 ├── src ├── config.js ├── index.js ├── game.js ├── solver.js └── data.js ├── .eslintrc.js ├── .babelrc ├── index.html ├── .gitignore ├── webpack.config.js ├── package.json └── css └── style.css /js/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boxbox 2 | 3 | https://akira-cn.github.io/boxbox/ 4 | -------------------------------------------------------------------------------- /assets/boy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/boy.png -------------------------------------------------------------------------------- /assets/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/grass.png -------------------------------------------------------------------------------- /assets/item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/item.png -------------------------------------------------------------------------------- /assets/step.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/step.mp3 -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const BOUND_X = 15; 4 | export const BOUND_Y = 10; -------------------------------------------------------------------------------- /assets/bgsound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/bgsound.mp3 -------------------------------------------------------------------------------- /assets/main_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/main_bg.png -------------------------------------------------------------------------------- /assets/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/sprites.png -------------------------------------------------------------------------------- /assets/success.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira-cn/boxbox/HEAD/assets/success.mp3 -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | }, 4 | extends: "eslint-config-sprite", 5 | plugins: ['html'], 6 | rules: { 7 | "complexity": ["warn", 25], 8 | 'import/prefer-default-export': 'off', 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "presets": [ 4 | ["@babel/preset-env", 5 | { 6 | "targets": { 7 | "browsers": [ 8 | "> 1%", 9 | "last 2 versions", 10 | "not ie <= 8" 11 | ] 12 | } 13 | } 14 | ] 15 | ], 16 | "plugins": [ 17 | "@babel/plugin-proposal-class-properties", 18 | [ 19 | "@babel/plugin-transform-runtime", 20 | { 21 | "corejs": false, 22 | "helpers": true, 23 | "regenerator": true, 24 | "useESModules": false 25 | } 26 | ] 27 | ] 28 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 推箱子 8 | 9 | 10 | 11 |
选择关卡后,使用键盘 上、下、左、右 键控制
12 |
13 |
14 | 15 | 16 | 17 |
18 |
19 |
你赢了!
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Logs 3 | logs 4 | *.log 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage/ 16 | .nyc_output/ 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Dependency directory 25 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 26 | node_modules/ 27 | 28 | # IDE config 29 | .idea 30 | 31 | # output 32 | output/ 33 | output.tar.gz 34 | 35 | app/ 36 | 37 | runtime/ 38 | 39 | frames/ 40 | ffmpeg.sh 41 | 42 | .DS_Store 43 | 44 | sftp-config.json 45 | package-lock.json 46 | 47 | .vscode 48 | jsconfig.json 49 | esconfig.json 50 | 51 | temp/*.js 52 | .jedi-tests -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = function (env = {}) { 4 | return { 5 | mode: env.production ? 'production' : 'development', 6 | entry: './src/index', 7 | output: { 8 | path: path.resolve(__dirname, 'js'), 9 | filename: 'app.js', 10 | publicPath: '/js/', 11 | library: ['Boxman'], 12 | libraryTarget: 'umd', 13 | }, 14 | 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.js$/, 19 | exclude: /(node_modules|bower_components)/, 20 | use: { 21 | loader: 'babel-loader', 22 | }, 23 | }, 24 | ], 25 | 26 | /* Advanced module configuration (click to show) */ 27 | }, 28 | 29 | // externals: { 30 | // spritejs: 'spritejs', 31 | // }, 32 | // Don't follow/bundle these modules, but request them at runtime from the environment 33 | 34 | stats: 'errors-only', 35 | // lets you precisely control what bundle information gets displayed 36 | 37 | devServer: { 38 | contentBase: path.join(__dirname, '.'), 39 | compress: true, 40 | port: 9090, 41 | // ... 42 | }, 43 | 44 | plugins: [ 45 | // ... 46 | ], 47 | // list of additional plugins 48 | 49 | 50 | /* Advanced configuration (click to show) */ 51 | }; 52 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "2019-contest", 3 | "version": "1.0.0", 4 | "description": "这是星计划校招选拔的综合挑战题", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --watch-poll", 8 | "build": "webpack --env.production", 9 | "lint": "eslint src --fix", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/75camp/2019-contest.git" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/75camp/2019-contest/issues" 21 | }, 22 | "homepage": "https://github.com/75camp/2019-contest#readme", 23 | "devDependencies": { 24 | "@babel/cli": "^7.2.3", 25 | "@babel/core": "^7.4.0", 26 | "@babel/plugin-proposal-class-properties": "^7.4.0", 27 | "@babel/plugin-transform-runtime": "^7.4.0", 28 | "@babel/preset-env": "^7.4.2", 29 | "babel-eslint": "^10.0.1", 30 | "babel-loader": "^8.0.5", 31 | "eslint": "^5.15.3", 32 | "eslint-config-sprite": "^1.0.6", 33 | "eslint-plugin-html": "^5.0.3", 34 | "webpack": "^4.29.6", 35 | "webpack-cli": "^3.3.0", 36 | "webpack-dev-server": "^3.2.1" 37 | }, 38 | "dependencies": { 39 | "@babel/runtime": "^7.4.2", 40 | "greenlet": "^1.0.1", 41 | "howler": "^2.1.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | body { 9 | display: flex; 10 | } 11 | 12 | #info { 13 | position: absolute; 14 | padding: 20px; 15 | } 16 | 17 | .gamepanel { 18 | margin: auto; 19 | } 20 | 21 | .levelpanel { 22 | text-align: right; 23 | font-size: 14px; 24 | margin-bottom: 3px; 25 | } 26 | 27 | #currentlevel { 28 | width: 26px; 29 | text-align: center; 30 | } 31 | 32 | #boxmap { 33 | position: relative; 34 | overflow: hidden; 35 | width: 480px; 36 | height: 320px; 37 | background-image: url(../assets/grass.png); 38 | } 39 | 40 | #boxmap > i { 41 | display: inline-block; 42 | position: absolute; 43 | width: 32px; 44 | height: 32px; 45 | background-image: url(../assets/sprites.png); 46 | background-repeat: no-repeat; 47 | } 48 | 49 | #game-result { 50 | position: absolute; 51 | left: 50%; 52 | top: 88%; 53 | transform: translate(-50%, -50%); 54 | color: #fff; 55 | z-index: 999; 56 | font-size: 4rem; 57 | font-weight: bold; 58 | opacity: 0; 59 | transition: all .3s; 60 | } 61 | 62 | #game-result.show { 63 | top: 38%; 64 | opacity: 1; 65 | transition: all .6s ease-out; 66 | } 67 | 68 | @keyframes walk { 69 | 0% {background-position-y: -96px} 70 | 33% {background-position-y: -32px} 71 | 66% {background-position-y: -64px} 72 | 100% {background-position-y: -96px} 73 | } 74 | 75 | .tree { 76 | background-position: -96px 0; 77 | } 78 | 79 | .spot { 80 | background-position: 0 0; 81 | } 82 | 83 | .bucket { 84 | background-position: -32px 0; 85 | z-index: 1; 86 | } 87 | 88 | .boxman { 89 | background-position-y: -96px; 90 | z-index: 2; 91 | } 92 | 93 | .up { 94 | background-position-x: 0px; 95 | } 96 | .right { 97 | background-position-x: -32px; 98 | } 99 | .down { 100 | background-position-x: -64px; 101 | } 102 | .left { 103 | background-position-x: -96px; 104 | } 105 | 106 | .walk { 107 | animation: walk step-end .2s forwards; 108 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import {Howl} from 'howler'; 2 | import BoxGame from './game'; 3 | 4 | function wait(ms) { 5 | return new Promise((resolve) => { 6 | setTimeout(resolve, ms); 7 | }); 8 | } 9 | 10 | const bgSound = new Howl({ 11 | src: ['assets/bgsound.mp3'], 12 | loop: true, 13 | }); 14 | 15 | bgSound.play(); 16 | 17 | const stepSound = new Howl({ 18 | src: ['assets/step.mp3'], 19 | }); 20 | 21 | const spotSound = new Howl({ 22 | src: ['assets/success.mp3'], 23 | }); 24 | 25 | const currentLevel = document.getElementById('currentlevel'); 26 | const previousLevel = document.getElementById('previouslevel'); 27 | const nextLevel = document.getElementById('nextlevel'); 28 | const reset = document.getElementById('reset'); 29 | const autoPlay = document.getElementById('autoplay'); 30 | 31 | const playLevel = Number(localStorage.getItem('playlevel')) || 1; 32 | 33 | const app = new BoxGame({ 34 | container: document.getElementById('boxmap'), 35 | onload(level) { 36 | currentLevel.value = level; 37 | }, 38 | onmove([man, bucket], direction) { 39 | let sound = stepSound; 40 | if(bucket) { 41 | let [x, y] = this.getXY(bucket); 42 | if(direction === 'left') { 43 | x--; 44 | } else if(direction === 'right') { 45 | x++; 46 | } else if(direction === 'up') { 47 | y--; 48 | } else { 49 | y++; 50 | } 51 | if(this.getSpot(x, y)) { 52 | sound = spotSound; 53 | } 54 | } 55 | sound.play(); 56 | }, 57 | async onLevelComplete(level) { 58 | localStorage.setItem('playlevel', level + 1); 59 | const result = document.getElementById('game-result'); 60 | result.className = 'show'; 61 | await wait(1300); 62 | result.className = ''; 63 | await wait(200); 64 | this.load(level + 1); 65 | }, 66 | }); 67 | 68 | app.load(playLevel); 69 | 70 | currentLevel.addEventListener('change', ({target}) => { 71 | app.load(Number(target.value)); 72 | }); 73 | 74 | previousLevel.addEventListener('click', () => { 75 | app.load(app.level - 1); 76 | }); 77 | 78 | nextLevel.addEventListener('click', () => { 79 | app.load(app.level + 1); 80 | }); 81 | 82 | reset.addEventListener('click', () => { 83 | app.load(app.level); 84 | }); 85 | 86 | autoPlay.addEventListener('click', async () => { 87 | autoPlay.disabled = true; 88 | autoPlay.innerHTML = '思考中...'; 89 | const steps = await app.solve(app.level); 90 | autoPlay.innerHTML = '行动中...'; 91 | await app.autoPlay(steps, app.level); 92 | autoPlay.disabled = false; 93 | autoPlay.innerHTML = '自动过关'; 94 | }); 95 | 96 | // for debug 97 | window.app = app; 98 | -------------------------------------------------------------------------------- /src/game.js: -------------------------------------------------------------------------------- 1 | import getData from './data'; 2 | import {BOUND_X, BOUND_Y} from './config'; 3 | import solver from './solver'; 4 | 5 | const _level = Symbol('level'); 6 | 7 | export default class BoxGame { 8 | static ITEM_WIDTH = 32; 9 | 10 | static MAX_LEVEL = 113; 11 | 12 | constructor({container, onload, onmove, onLevelComplete}) { 13 | this.container = container; 14 | this.onload = onload; 15 | this.onmove = onmove; 16 | this.onLevelComplete = onLevelComplete; 17 | } 18 | 19 | moveTo(item, x, y) { 20 | item.dataset.x = x; 21 | item.dataset.y = y; 22 | item.style.left = `${x * BoxGame.ITEM_WIDTH}px`; 23 | item.style.top = `${y * BoxGame.ITEM_WIDTH}px`; 24 | } 25 | 26 | addItem(type, x, y) { 27 | const item = document.createElement('i'); 28 | item.className = type; 29 | 30 | if(type === 'boxman') { 31 | item.className += ' down'; 32 | } 33 | 34 | this.moveTo(item, x, y); 35 | this.container.appendChild(item); 36 | } 37 | 38 | get boxman() { 39 | return this.container.querySelector('.boxman'); 40 | } 41 | 42 | getXY(item) { 43 | return [Number(item.dataset.x), Number(item.dataset.y)]; 44 | } 45 | 46 | getItem(x, y) { 47 | const items = this.container.children; 48 | for(let i = 0; i < items.length; i++) { 49 | const item = items[i]; 50 | if(x === Number(item.dataset.x) && y === Number(item.dataset.y) && item.className !== 'spot') { 51 | return item; 52 | } 53 | } 54 | return null; 55 | } 56 | 57 | getSpot(x, y) { 58 | const items = this.container.querySelectorAll('.spot'); 59 | for(let i = 0; i < items.length; i++) { 60 | const item = items[i]; 61 | if(x === Number(item.dataset.x) && y === Number(item.dataset.y)) { 62 | return item; 63 | } 64 | } 65 | return null; 66 | } 67 | 68 | isOutOfBound(x, y) { 69 | return x < 0 || y < 0 || x >= BOUND_X || y >= BOUND_Y; 70 | } 71 | 72 | isEmpty(x, y) { 73 | return !this.isOutOfBound(x, y) && !this.getItem(x, y); 74 | } 75 | 76 | isAtSpot(bucket) { 77 | const spots = this.container.querySelectorAll('.spot'); 78 | for(let i = 0; i < spots.length; i++) { 79 | const spot = spots[i]; 80 | if(bucket.dataset.x === spot.dataset.x && bucket.dataset.y === spot.dataset.y) { 81 | return true; 82 | } 83 | } 84 | return false; 85 | } 86 | 87 | async move(direction = 'right') { 88 | const boxman = this.boxman; 89 | const x = Number(boxman.dataset.x), 90 | y = Number(boxman.dataset.y); 91 | 92 | let item = null; 93 | 94 | if(direction === 'left') { 95 | item = this.getItem(x - 1, y); 96 | } else if(direction === 'right') { 97 | item = this.getItem(x + 1, y); 98 | } else if(direction === 'up') { 99 | item = this.getItem(x, y - 1); 100 | } else if(direction === 'down') { 101 | item = this.getItem(x, y + 1); 102 | } 103 | 104 | if(!item) { 105 | if(this.onmove) this.onmove([boxman], direction); 106 | boxman.className = `boxman ${direction} walk`; 107 | await this.moveItem(boxman, direction); 108 | boxman.className = `boxman ${direction}`; 109 | } else if(item.className === 'bucket' 110 | && (direction === 'left' && this.isEmpty(x - 2, y) 111 | || direction === 'right' && this.isEmpty(x + 2, y) 112 | || direction === 'up' && this.isEmpty(x, y - 2) 113 | || direction === 'down' && this.isEmpty(x, y + 2))) { 114 | if(this.onmove) this.onmove([boxman, item], direction); 115 | boxman.className = `boxman ${direction} walk`; 116 | await Promise.all([ 117 | this.moveItem(boxman, direction), 118 | this.moveItem(item, direction), 119 | ]); 120 | boxman.className = `boxman ${direction}`; 121 | } else { 122 | boxman.className = `boxman ${direction}`; 123 | } 124 | } 125 | 126 | moveItem(item, direction = 'right') { 127 | let from, 128 | to, 129 | prop; 130 | if(direction === 'left' || direction === 'right') { 131 | from = Number(item.dataset.x); 132 | to = direction === 'left' ? from - 1 : from + 1; 133 | prop = 'left'; 134 | } else { 135 | from = Number(item.dataset.y); 136 | to = direction === 'up' ? from - 1 : from + 1; 137 | prop = 'top'; 138 | } 139 | 140 | return new Promise((resolve) => { 141 | const startTime = Date.now(); 142 | const that = this; 143 | requestAnimationFrame(function update() { 144 | const p = Math.min(1.0, (Date.now() - startTime) / 200); 145 | item.style[prop] = `${BoxGame.ITEM_WIDTH * ((1 - p) * from + p * to)}px`; 146 | if(p < 1.0) { 147 | requestAnimationFrame(update); 148 | } else { 149 | if(prop === 'left') that.moveTo(item, to, item.dataset.y); 150 | else that.moveTo(item, item.dataset.x, to); 151 | resolve(); 152 | } 153 | }); 154 | }); 155 | } 156 | 157 | isWin() { 158 | // 检查是否箱子都在spot中 159 | const buckets = this.container.querySelectorAll('.bucket'); 160 | return Array.from(buckets).every(bucket => this.isAtSpot(bucket)); 161 | } 162 | 163 | waitCommand() { 164 | return new Promise((resolve) => { 165 | if(this._command) window.removeEventListener('keydown', this._command); 166 | this._command = (event) => { 167 | const keyCode = event.keyCode; 168 | switch (keyCode) { 169 | case 37: 170 | resolve('left'); 171 | break; 172 | case 38: 173 | resolve('up'); 174 | break; 175 | case 39: 176 | resolve('right'); 177 | break; 178 | case 40: 179 | resolve('down'); 180 | break; 181 | default: 182 | resolve(null); 183 | break; 184 | } 185 | }; 186 | window.addEventListener('keydown', this._command, {once: true}); 187 | }); 188 | } 189 | 190 | clear() { 191 | this.container.innerHTML = ''; 192 | } 193 | 194 | async solve(level = this.level) { 195 | const key = `solved${level}`; 196 | const steps = localStorage.getItem(key); 197 | if(steps) { 198 | return steps.split(','); 199 | } 200 | 201 | const result = await solver(getData(level)); 202 | localStorage.setItem(key, result.join()); 203 | return result; 204 | } 205 | 206 | get level() { 207 | return this[_level]; 208 | } 209 | 210 | init(level = this.level) { 211 | const {trees, spots, buckets, man} = getData(level); 212 | this.clear(); 213 | trees.forEach(([x, y]) => this.addItem('tree', x, y)); 214 | spots.forEach(([x, y]) => this.addItem('spot', x, y)); 215 | buckets.forEach(([x, y]) => this.addItem('bucket', x, y)); 216 | this.addItem('boxman', ...man); 217 | } 218 | 219 | async autoPlay(steps, level = this.level) { 220 | this.init(level); 221 | /* eslint-disable no-await-in-loop */ 222 | for(let i = 0; i < steps.length; i++) { 223 | const direction = steps[i]; 224 | await this.move(direction); 225 | } 226 | /* eslint-enable no-await-in-loop */ 227 | if(this.onLevelComplete && this.isWin()) { 228 | await this.onLevelComplete(level); 229 | } 230 | } 231 | 232 | async load(level) { 233 | if(level <= 0) level = BoxGame.MAX_LEVEL; 234 | else if(Number.isNaN(level) || level > BoxGame.MAX_LEVEL) level = 1; 235 | this[_level] = level; 236 | 237 | this.init(level); 238 | if(this.onload) { 239 | this.onload(level); 240 | } 241 | /* eslint-disable no-await-in-loop */ 242 | do { 243 | const direction = await this.waitCommand(); 244 | if(direction) { 245 | await this.move(direction); 246 | } 247 | } while(!this.isWin()); 248 | /* eslint-enable no-await-in-loop */ 249 | 250 | if(this.onLevelComplete) { 251 | await this.onLevelComplete(level); 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/solver.js: -------------------------------------------------------------------------------- 1 | import greenlet from 'greenlet'; 2 | 3 | export default greenlet((data) => { 4 | const TREE = 1, 5 | EMPTY = 0; 6 | 7 | const BOUND_X = 15; 8 | const BOUND_Y = 10; 9 | 10 | const map = Array((BOUND_X + 1) * (BOUND_Y + 1)).fill(0); 11 | 12 | data.trees.forEach((t) => { 13 | map[t[1] * BOUND_X + t[0]] = TREE; 14 | }); 15 | 16 | const allBuckets = new Set(data.buckets.map(b => b[1] * BOUND_X + b[0])); 17 | const spots = data.spots.map(s => s[1] * BOUND_X + s[0]); 18 | 19 | function isEmpty(buckets, idx) { 20 | return map[idx] === EMPTY && !buckets.has(idx); 21 | } 22 | 23 | function isBucketInSpot(idx) { 24 | return spots.some(spot => spot === idx); 25 | } 26 | 27 | function deadBucket(buckets, bucket) { 28 | const fixed = new Set(); 29 | 30 | function isImmovable(idx) { 31 | return map[idx] === TREE || map[idx] == null 32 | || buckets.has(idx) && !canMove(idx); 33 | } 34 | 35 | function canMove(idx) { 36 | if(fixed.has(idx)) return false; 37 | fixed.add(idx); 38 | 39 | const left = idx % BOUND_X > 0 && isImmovable(idx - 1), 40 | right = idx % BOUND_X < BOUND_X - 1 && isImmovable(idx + 1), 41 | top = isImmovable(idx - BOUND_X), 42 | down = isImmovable(idx + BOUND_X); 43 | 44 | if((left && top) 45 | || (top && right) 46 | || (right && down) 47 | || (down && left)) { 48 | return false; 49 | } 50 | fixed.delete(idx); 51 | return true; 52 | } 53 | 54 | const movable = canMove(bucket); 55 | if(movable) return false; 56 | if(isBucketInSpot(bucket)) { 57 | return Array.from(fixed).some(bucket => !isBucketInSpot(bucket)); 58 | } 59 | return true; 60 | } 61 | 62 | const MOVE_MAN = 1, 63 | MOVE_BOX = 2; 64 | 65 | function testMove(buckets, nextnext, next) { 66 | buckets.delete(next); 67 | buckets.add(nextnext); 68 | if(deadBucket(buckets, nextnext)) { 69 | buckets.delete(nextnext); 70 | buckets.add(next); 71 | return 0; 72 | } 73 | return MOVE_BOX; 74 | } 75 | 76 | function makeDirectionXY(direction, delta = 1) { 77 | const getXYs = [ 78 | (x, y) => [x - delta, y], 79 | (x, y) => [x + delta, y], 80 | (x, y) => [x, y - delta], 81 | (x, y) => [x, y + delta], 82 | ]; 83 | return getXYs[direction]; 84 | } 85 | 86 | function getPos(x, y, direction) { 87 | if(x < 0 || x >= BOUND_X) return null; 88 | if(y < 0 || y >= BOUND_Y) return null; 89 | return y * BOUND_X + x; 90 | } 91 | 92 | function makeMove(direction) { 93 | const getNextXY = makeDirectionXY(direction); 94 | const getNextNextXY = makeDirectionXY(direction, 2); 95 | return (buckets, x, y) => { 96 | let pos = getNextXY(x, y); 97 | const next = getPos(pos[0], pos[1]); 98 | if(next && isEmpty(buckets, next)) { 99 | return MOVE_MAN; 100 | } 101 | if(next && buckets.has(next)) { 102 | pos = getNextNextXY(x, y); 103 | const nextnext = getPos(pos[0], pos[1]); 104 | if(nextnext && isEmpty(buckets, nextnext)) { 105 | return testMove(buckets, nextnext, next); 106 | } 107 | } 108 | return 0; 109 | }; 110 | } 111 | 112 | function checkSpots(buckets) { 113 | return spots.every((s) => { 114 | return buckets.has(s); 115 | }); 116 | } 117 | 118 | const LEFT = 0, 119 | RIGHT = 1, 120 | UP = 2, 121 | DOWN = 3; 122 | 123 | let results = null; 124 | const x = Number(data.man[0]), 125 | y = Number(data.man[1]); 126 | 127 | const recordSet = {}; 128 | function getRecord(b1, b2) { 129 | if(recordSet[b1] == null) return null; 130 | return recordSet[b1][b2]; 131 | } 132 | 133 | function setRecord(b1, b2, pos) { 134 | const poss = getRecord(b1, b2) || [0, 0, 0, 0, 0]; 135 | setPos(poss, pos); 136 | recordSet[b1] = recordSet[b1] || {}; 137 | recordSet[b1][b2] = poss; 138 | } 139 | 140 | function hasPos(poss, pos) { 141 | let idx = 0; 142 | while(pos >= 30) { 143 | pos -= 30; 144 | idx++; 145 | } 146 | return poss[idx] & (1 << pos); 147 | } 148 | 149 | function setPos(poss, pos) { 150 | let idx = 0; 151 | while(pos >= 30) { 152 | pos -= 30; 153 | idx++; 154 | } 155 | poss[idx] |= (1 << pos); 156 | } 157 | 158 | function pack({buckets, x, y, step, pre}) { 159 | const arr = new Uint32Array(4); 160 | buckets = Array.from(buckets).sort(); 161 | for(let i = 0; i < 8; i++) { 162 | let bucket = buckets[i]; 163 | if(bucket == null) bucket = 0xff; 164 | if(i < 4) { 165 | arr[0] |= bucket << (8 * i); 166 | } else { 167 | arr[1] |= bucket << (8 * (i - 4)); 168 | } 169 | } 170 | arr[2] |= x; 171 | arr[2] |= y << 8; 172 | if(pre !== 0xffffffff) { 173 | arr[2] |= step << 16; 174 | } 175 | arr[3] = pre; 176 | return arr; 177 | } 178 | 179 | function unpack(a, b, c, d) { 180 | let buckets = [ 181 | a & 0xff, 182 | (a >>> 8) & 0xff, 183 | (a >>> 16) & 0xff, 184 | (a >>> 24) & 0xff, 185 | b & 0xff, 186 | (b >>> 8) & 0xff, 187 | (b >>> 16) & 0xff, 188 | (b >>> 24) & 0xff, 189 | ]; 190 | buckets = new Set(buckets.filter(b => b !== 0xff)); 191 | const x = c & 0xff; 192 | const y = (c >> 8) & 0xff; 193 | let step = -1; 194 | if(d !== 0xffffffff) { 195 | step = (c >> 16) & 0xff; 196 | } 197 | return {buckets, x, y, step, pre: d}; 198 | } 199 | 200 | // 以两位Uint32来表示所有的8个buckets,以一位Uint32来表示x,y,direction,以一位Uint32来表示preIndex 201 | const list = new Uint32Array(256 * 1024 * 1024); 202 | const packed = pack({buckets: allBuckets, pre: -1, x, y}); 203 | list[0] = packed[0]; 204 | list[1] = packed[1]; 205 | list[2] = packed[2]; 206 | list[3] = packed[3]; 207 | 208 | setRecord(list[0], list[1], getPos(x, y)); 209 | 210 | function getSteps(idx) { 211 | const data = unpack(list[idx], list[idx + 1], list[idx + 2], list[idx + 3]); 212 | if(data.step >= 0) { 213 | return getSteps(data.pre).concat(data.step); 214 | } 215 | return []; 216 | } 217 | 218 | let count = 4; 219 | 220 | function bfs(buckets, i, x, y, direction) { 221 | const move = makeMove(direction); 222 | const getPosByXY = makeDirectionXY(direction); 223 | 224 | const mvb = new Set(buckets); 225 | const check = move(mvb, x, y); 226 | if(check) { 227 | const pos = getPosByXY(x, y); 228 | if(check === MOVE_BOX && checkSpots(mvb)) { 229 | results = getSteps(i).concat(direction); 230 | return true; 231 | } 232 | const packed = pack({buckets: mvb, pre: i, step: direction, x: pos[0], y: pos[1]}); 233 | const poss = getRecord(packed[0], packed[1]); 234 | if(!poss) { 235 | list[count] = packed[0]; 236 | list[count + 1] = packed[1]; 237 | list[count + 2] = packed[2]; 238 | list[count + 3] = packed[3]; 239 | count += 4; 240 | setRecord(packed[0], packed[1], getPos(pos[0], pos[1])); 241 | } else { 242 | const idx = getPos(pos[0], pos[1]); 243 | if(!hasPos(poss, idx)) { 244 | list[count] = packed[0]; 245 | list[count + 1] = packed[1]; 246 | list[count + 2] = packed[2]; 247 | list[count + 3] = packed[3]; 248 | count += 4; 249 | setPos(poss, idx); 250 | } 251 | } 252 | } 253 | return false; 254 | } 255 | 256 | for(let i = 0; i < list.length; i += 4) { 257 | if(list[i] === 0) { 258 | break; 259 | } 260 | const {buckets, x, y} = unpack(list[i], list[i + 1], list[i + 2], list[i + 3]); 261 | if(bfs(buckets, i, x, y, LEFT) 262 | || bfs(buckets, i, x, y, RIGHT) 263 | || bfs(buckets, i, x, y, UP) 264 | || bfs(buckets, i, x, y, DOWN)) break; 265 | } 266 | 267 | const m = ['left', 'right', 'up', 'down']; 268 | return results.map(r => m[r]); 269 | }); 270 | -------------------------------------------------------------------------------- /src/data.js: -------------------------------------------------------------------------------- 1 | const gameData = [{tree: '4,7|5,7|6,7|7,7|8,7|9,7|10,7|4,6|10,6|4,5|10,5|4,4|10,4|4,3|5,3|6,3|7,3|8,3|9,3|10,3', box: '8,6|6,5|8,5|6,4', goal: '5,6|9,6|5,4|9,4', boy: '7,5'}, {tree: '3,2|4,2|5,2|6,2|7,2|8,2|9,2|10,2|3,3|7,3|10,3|3,4|10,4|3,5|7,5|10,5|3,6|4,6|5,6|6,6|7,6|8,6|9,6|10,6', box: '7,4', goal: '9,4', boy: '8,4'}, {tree: '6,2|7,2|8,2|9,2|4,3|5,3|6,3|9,3|4,4|9,4|10,4|4,5|10,5|4,6|6,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '6,4|6,5', goal: '8,4|7,6', boy: '5,6'}, {tree: '5,1|6,1|7,1|8,1|9,1|10,1|4,2|5,2|10,2|4,3|8,3|10,3|4,4|10,4|4,5|7,5|9,5|10,5|4,6|5,6|9,6|5,7|6,7|7,7|8,7|9,7', box: '6,3|7,4|8,5', goal: '8,2|6,3|6,4', boy: '7,6'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|4,3|6,3|8,3|10,3|4,4|10,4|4,5|9,5|10,5|4,6|7,6|8,6|9,6|4,7|5,7|6,7|7,7', box: '8,4|6,5|7,5', goal: '7,2|7,3|5,5', boy: '8,2'}, {tree: '7,1|8,1|9,1|10,1|4,2|5,2|6,2|7,2|10,2|4,3|10,3|4,4|10,4|4,5|5,5|8,5|9,5|10,5|5,6|8,6|5,7|8,7|5,8|6,8|7,8|8,8', box: '7,3|8,3|6,6', goal: '7,3|7,5|7,7', boy: '9,2'}, {tree: '4,1|5,1|6,1|8,1|9,1|10,1|4,2|6,2|7,2|8,2|10,2|4,3|6,3|10,3|4,4|10,4|4,5|10,5|4,6|7,6|10,6|4,7|7,7|8,7|9,7|10,7|4,8|5,8|6,8|7,8', box: '6,4|7,4|7,5', goal: '5,2|9,2|9,3', boy: '9,4'}, {tree: '6,1|7,1|8,1|9,1|6,2|9,2|10,2|3,3|4,3|5,3|6,3|10,3|3,4|6,4|10,4|3,5|9,5|10,5|3,6|8,6|9,6|3,7|4,7|8,7|4,8|5,8|6,8|7,8|8,8', box: '7,4|8,4|7,6', goal: '4,4|4,6|5,7', boy: '8,2'}, {tree: '3,2|4,2|5,2|6,2|7,2|3,3|7,3|8,3|9,3|10,3|3,4|10,4|3,5|6,5|8,5|10,5|3,6|10,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '5,4|7,5|8,6', goal: '5,3|6,3|7,6', boy: '5,6'}, {tree: '6,1|7,1|8,1|9,1|10,1|4,2|5,2|6,2|10,2|4,3|8,3|10,3|4,4|10,4|4,5|7,5|10,5|4,6|9,6|10,6|4,7|8,7|9,7|4,8|5,8|6,8|7,8|8,8', box: '6,3|6,4|7,4', goal: '9,2|6,4|6,5', boy: '8,5'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|3,2|9,2|3,3|7,3|9,3|10,3|3,4|5,4|10,4|3,5|8,5|10,5|3,6|4,6|5,6|6,6|10,6|6,7|7,7|8,7|9,7|10,7', box: '6,3|7,4|7,5', goal: '4,2|8,2|8,4', boy: '7,2'}, {tree: '4,1|5,1|6,1|7,1|8,1|4,2|8,2|9,2|10,2|4,3|6,3|10,3|4,4|10,4|4,5|7,5|10,5|4,6|5,6|9,6|10,6|5,7|6,7|7,7|8,7|9,7', box: '7,3|8,3|6,5', goal: '5,2|7,2|5,3', boy: '8,4'}, {tree: '4,1|5,1|6,1|7,1|8,1|4,2|8,2|9,2|10,2|4,3|6,3|10,3|4,4|8,4|10,4|4,5|10,5|4,6|5,6|8,6|9,6|10,6|5,7|8,7|5,8|6,8|7,8|8,8', box: '6,5|7,5|8,5', goal: '5,2|6,4|7,5', boy: '6,6'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|10,2|3,3|5,3|7,3|10,3|3,4|10,4|3,5|4,5|5,5|6,5|7,5|10,5|7,6|10,6|7,7|8,7|9,7|10,7', box: '5,4|8,4|9,5', goal: '4,2|8,2|9,4', boy: '4,4'}, {tree: '3,1|4,1|5,1|6,1|3,2|6,2|3,3|6,3|7,3|8,3|9,3|10,3|3,4|10,4|3,5|4,5|10,5|4,6|6,6|8,6|9,6|10,6|4,7|8,7|4,8|5,8|6,8|7,8|8,8', box: '6,4|5,5|7,6', goal: '5,4|6,4|5,7', boy: '7,7'}, {tree: '4,1|5,1|6,1|7,1|8,1|4,2|8,2|9,2|10,2|3,3|4,3|10,3|3,4|10,4|3,5|4,5|6,5|8,5|9,5|10,5|4,6|8,6|4,7|5,7|6,7|7,7|8,7', box: '6,4|8,4|5,5', goal: '6,3|4,4|7,4', boy: '6,2'}, {tree: '5,1|6,1|7,1|8,1|9,1|4,2|5,2|9,2|4,3|7,3|9,3|4,4|9,4|10,4|4,5|10,5|4,6|5,6|7,6|10,6|5,7|9,7|10,7|5,8|6,8|7,8|8,8|9,8', box: '6,3|6,5|8,6', goal: '6,4|6,5|6,7', boy: '8,4'}, {tree: '4,1|5,1|6,1|7,1|3,2|4,2|7,2|8,2|9,2|10,2|3,3|10,3|3,4|5,4|10,4|3,5|7,5|10,5|3,6|4,6|5,6|6,6|7,6|10,6|7,7|8,7|9,7|10,7', box: '6,3|6,4|8,4', goal: '4,3|5,3|9,3', boy: '4,5'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|10,2|4,3|10,3|4,4|5,4|6,4|8,4|10,4|3,5|4,5|10,5|3,6|9,6|10,6|3,7|7,7|8,7|9,7|3,8|4,8|5,8|6,8|7,8', box: '8,3|7,4|6,6', goal: '7,2|9,3|7,4', boy: '8,2'}, {tree: '4,1|5,1|6,1|7,1|4,2|7,2|4,3|7,3|3,4|4,4|7,4|8,4|9,4|10,4|3,5|10,5|3,6|8,6|9,6|10,6|3,7|4,7|5,7|8,7|5,8|6,8|7,8|8,8', box: '5,5|6,5|6,6', goal: '5,4|7,5|9,5', boy: '5,2'}, {tree: '4,1|5,1|6,1|7,1|8,1|4,2|8,2|4,3|6,3|8,3|9,3|10,3|4,4|10,4|4,5|10,5|4,6|8,6|9,6|10,6|4,7|5,7|6,7|7,7|8,7', box: '6,4|7,4|7,5', goal: '5,2|6,4|8,5', boy: '7,6'}, {tree: '6,1|7,1|8,1|9,1|10,1|6,2|10,2|6,3|8,3|10,3|4,4|5,4|6,4|10,4|4,5|10,5|4,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '7,5|8,5|8,6', goal: '9,3|9,4|7,6', boy: '5,5'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|3,2|8,2|3,3|6,3|8,3|9,3|10,3|3,4|10,4|3,5|7,5|8,5|10,5|3,6|4,6|10,6|4,7|5,7|9,7|10,7|5,8|6,8|7,8|8,8|9,8', box: '5,3|5,4|7,4', goal: '5,4|5,6|8,6', boy: '7,2'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|10,2|4,3|7,3|10,3|4,4|10,4|4,5|8,5|10,5|4,6|5,6|6,6|10,6|6,7|7,7|8,7|9,7|10,7', box: '8,4|6,5|7,5', goal: '5,4|9,5|9,6', boy: '8,2'}, {tree: '5,2|6,2|7,2|8,2|3,3|4,3|5,3|8,3|3,4|8,4|9,4|10,4|3,5|10,5|3,6|4,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '7,5|8,5|8,6', goal: '6,3|5,4|6,6', boy: '9,6'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|3,2|4,2|9,2|3,3|9,3|3,4|6,4|9,4|10,4|3,5|6,5|10,5|3,6|4,6|5,6|6,6|8,6|10,6|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '5,3|6,3|7,3', goal: '6,2|7,3|9,5', boy: '5,2'}, {tree: '7,1|8,1|9,1|10,1|7,2|10,2|5,3|6,3|7,3|10,3|5,4|10,4|3,5|4,5|5,5|8,5|10,5|3,6|10,6|3,7|7,7|10,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '8,3|5,6|8,6', goal: '9,3|8,4|9,5', boy: '8,7'}, {tree: '3,1|4,1|5,1|6,1|7,1|3,2|7,2|8,2|9,2|3,3|9,3|3,4|6,4|7,4|9,4|10,4|3,5|4,5|7,5|10,5|4,6|10,6|4,7|7,7|8,7|9,7|10,7|4,8|5,8|6,8|7,8', box: '5,3|8,4|5,6', goal: '6,2|6,3|7,3', boy: '9,6'}, {tree: '5,1|6,1|7,1|8,1|5,2|8,2|5,3|8,3|9,3|10,3|3,4|4,4|5,4|10,4|3,5|7,5|10,5|3,6|10,6|3,7|4,7|5,7|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '6,5|7,6|8,6', goal: '7,4|8,4|6,6', boy: '8,7'}, {tree: '3,1|4,1|5,1|6,1|7,1|3,2|7,2|8,2|9,2|3,3|5,3|9,3|10,3|3,4|10,4|3,5|4,5|5,5|10,5|5,6|10,6|5,7|6,7|7,7|8,7|9,7|10,7', box: '7,3|6,4|6,5', goal: '7,3|6,4|9,6', boy: '8,3'}, {tree: '5,1|6,1|7,1|8,1|9,1|10,1|3,2|4,2|5,2|10,2|3,3|7,3|10,3|3,4|7,4|9,4|10,4|3,5|9,5|3,6|4,6|7,6|9,6|4,7|5,7|9,7|5,8|6,8|7,8|8,8|9,8', box: '5,3|6,4|6,5', goal: '7,2|8,3|6,5', boy: '6,3'}, {tree: '4,2|5,2|6,2|7,2|3,3|4,3|7,3|8,3|9,3|3,4|9,4|10,4|3,5|6,5|10,5|3,6|10,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '7,5|8,5|8,6', goal: '6,6|8,6|9,6', boy: '9,5'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|4,2|10,2|3,3|6,3|10,3|3,4|9,4|10,4|3,5|6,5|9,5|3,6|6,6|7,6|8,6|9,6|3,7|4,7|5,7|6,7', box: '5,4|6,4|7,4', goal: '4,3|8,4|5,5', boy: '5,2'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|10,2|3,3|5,3|7,3|8,3|10,3|3,4|5,4|10,4|3,5|10,5|3,6|4,6|5,6|6,6|7,6|10,6|7,7|10,7|7,8|8,8|9,8|10,8', box: '9,3|8,4|5,5', goal: '9,3|4,5|7,5', boy: '6,4'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|10,2|4,3|5,3|10,3|3,4|4,4|5,4|10,4|3,5|7,5|9,5|10,5|3,6|9,6|3,7|4,7|5,7|6,7|9,7|6,8|7,8|8,8|9,8', box: '6,3|5,5|8,5', goal: '7,4|5,6|8,6', boy: '5,2'}, {tree: '4,1|5,1|6,1|7,1|8,1|4,2|8,2|9,2|10,2|4,3|10,3|4,4|5,4|10,4|5,5|10,5|5,6|6,6|8,6|10,6|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '7,3|6,4|7,4', goal: '9,4|8,5|9,7', boy: '6,5'}, {tree: '3,1|4,1|5,1|6,1|7,1|3,2|7,2|8,2|9,2|10,2|3,3|10,3|3,4|6,4|10,4|3,5|6,5|7,5|9,5|10,5|3,6|6,6|7,6|9,6|3,7|9,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8', box: '5,3|6,3|8,6', goal: '5,4|7,4|8,7', boy: '5,7'}, {tree: '3,2|4,2|5,2|6,2|7,2|8,2|3,3|8,3|3,4|6,4|8,4|9,4|10,4|3,5|10,5|3,6|10,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '6,5|7,5|5,6', goal: '5,3|5,4|6,6', boy: '5,5'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|7,2|10,2|3,3|10,3|3,4|6,4|10,4|3,5|9,5|10,5|3,6|4,6|5,6|8,6|9,6|5,7|8,7|5,8|6,8|7,8|8,8', box: '6,3|7,4|6,5', goal: '6,2|5,3|8,3', boy: '5,2'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|4,2|10,2|3,3|10,3|3,4|7,4|8,4|9,4|10,4|3,5|6,5|7,5|3,6|6,6|3,7|6,7|3,8|4,8|5,8|6,8', box: '5,3|8,3|5,4', goal: '8,2|4,4|6,4', boy: '9,3'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|4,3|7,3|9,3|4,4|9,4|10,4|4,5|5,5|7,5|10,5|4,6|8,6|10,6|4,7|10,7|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '7,4|6,5|7,7', goal: '6,2|5,7|7,7', boy: '8,3'}, {tree: '6,1|7,1|8,1|9,1|10,1|3,2|4,2|5,2|6,2|10,2|3,3|10,3|3,4|7,4|10,4|3,5|5,5|10,5|3,6|7,6|8,6|9,6|10,6|3,7|4,7|5,7|6,7|7,7', box: '5,3|5,4|8,5', goal: '8,2|5,3|8,3', boy: '6,3'}, {tree: '5,2|6,2|7,2|8,2|3,3|4,3|5,3|8,3|9,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|5,6|6,6|10,6|6,7|7,7|8,7|9,7|10,7', box: '8,4|6,5|7,5', goal: '5,4|6,4|9,4', boy: '9,5'}, {tree: '7,1|8,1|9,1|10,1|7,2|10,2|3,3|4,3|5,3|6,3|7,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|5,6|10,6|5,7|6,7|7,7|8,7|9,7|10,7', box: '5,4|7,4|9,4', goal: '9,3|7,5|7,6', boy: '8,2'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|7,2|10,2|3,3|5,3|10,3|3,4|10,4|3,5|4,5|5,5|6,5|7,5|10,5|5,6|10,6|5,7|10,7|5,8|6,8|7,8|8,8|9,8|10,8', box: '7,3|9,3|7,4', goal: '6,3|8,5|9,7', boy: '9,6'}, {tree: '6,1|7,1|8,1|9,1|5,2|6,2|9,2|10,2|4,3|5,3|10,3|3,4|4,4|7,4|9,4|10,4|3,5|10,5|3,6|6,6|10,6|3,7|8,7|9,7|10,7|3,8|4,8|5,8|6,8|7,8|8,8', box: '6,4|8,4|7,5', goal: '8,3|9,3|8,5', boy: '7,2'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|3,2|8,2|3,3|7,3|8,3|9,3|10,3|3,4|10,4|3,5|4,5|6,5|8,5|10,5|3,6|8,6|10,6|3,7|10,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '5,3|6,3|5,4', goal: '7,4|7,5|4,6', boy: '7,2'}, {tree: '6,1|7,1|8,1|9,1|6,2|9,2|3,3|4,3|5,3|6,3|9,3|10,3|3,4|10,4|3,5|5,5|6,5|10,5|3,6|7,6|8,6|10,6|3,7|10,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '8,3|6,4|7,7', goal: '7,4|7,7|9,7', boy: '5,4'}, {tree: '6,1|7,1|8,1|9,1|10,1|6,2|10,2|4,3|5,3|6,3|10,3|4,4|9,4|10,4|3,5|4,5|9,5|3,6|7,6|9,6|3,7|9,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8', box: '6,4|8,4|6,5', goal: '4,6|4,7|5,7', boy: '8,2'}, {tree: '6,1|7,1|8,1|9,1|10,1|3,2|4,2|5,2|6,2|10,2|3,3|10,3|3,4|5,4|8,4|9,4|10,4|3,5|10,5|3,6|4,6|5,6|6,6|10,6|6,7|7,7|8,7|9,7|10,7', box: '7,3|5,5|7,5', goal: '7,2|6,3|9,5', boy: '9,2'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|7,2|10,2|3,3|5,3|10,3|3,4|7,4|10,4|3,5|4,5|10,5|4,6|7,6|8,6|9,6|10,6|4,7|5,7|6,7|7,7', box: '7,3|5,4|8,4', goal: '6,2|6,4|6,5', boy: '9,2'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|4,3|6,3|7,3|10,3|4,4|10,4|4,5|7,5|10,5|4,6|7,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '5,4|8,4|8,5', goal: '5,3|9,3|5,4', boy: '9,4'}, {tree: '3,1|4,1|5,1|6,1|3,2|6,2|3,3|6,3|3,4|6,4|7,4|8,4|9,4|10,4|3,5|10,5|3,6|8,6|10,6|3,7|4,7|5,7|10,7|5,8|6,8|7,8|8,8|9,8|10,8', box: '5,3|6,5|6,6', goal: '4,2|5,5|5,6', boy: '8,5'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|10,2|3,3|5,3|10,3|3,4|8,4|10,4|3,5|4,5|6,5|10,5|4,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '6,3|5,4|5,5', goal: '9,4|7,5|9,6', boy: '7,4'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|3,2|8,2|3,3|8,3|9,3|10,3|3,4|5,4|10,4|3,5|7,5|8,5|10,5|3,6|7,6|8,6|10,6|3,7|4,7|5,7|10,7|5,8|6,8|7,8|8,8|9,8|10,8', box: '6,4|7,4|5,6', goal: '6,2|8,4|4,5', boy: '4,6'}, {tree: '8,0|9,0|10,0|11,0|6,1|7,1|8,1|11,1|6,2|11,2|6,3|11,3|2,4|3,4|4,4|5,4|6,4|7,4|9,4|10,4|11,4|2,5|9,5|10,5|11,5|2,6|3,6|5,6|11,6|3,7|7,7|9,7|11,7|3,8|7,8|11,8|3,9|4,9|5,9|6,9|7,9|8,9|9,9|10,9|11,9', box: '9,3|7,6|9,6|5,7', goal: '9,1|10,1|9,2|10,2', boy: '3,5'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|3,2|8,2|9,2|10,2|11,2|3,3|11,3|3,4|4,4|11,4|4,5|5,5|6,5|7,5|9,5|11,5|7,6|11,6|7,7|8,7|9,7|10,7|11,7', box: '6,3|7,3|8,3|7,4', goal: '4,2|5,2|6,2|7,2', boy: '4,3'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|3,2|8,2|9,2|10,2|11,2|3,3|11,3|3,4|4,4|11,4|4,5|5,5|6,5|7,5|9,5|11,5|7,6|11,6|7,7|8,7|9,7|10,7|11,7', box: '6,3|7,3|8,3|7,4|8,5', goal: '4,2|5,2|6,2|7,2|10,3', boy: '4,3'}, {tree: '2,1|3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|2,2|6,2|7,2|10,2|2,3|10,3|11,3|2,4|7,4|11,4|2,5|7,5|11,5|2,6|5,6|7,6|8,6|9,6|10,6|11,6|2,7|3,7|7,7|3,8|4,8|5,8|6,8|7,8', box: '4,3|5,3|5,4|6,4|4,5|5,5', goal: '8,3|9,3|8,4|9,4|8,5|9,5', boy: '5,2'}, {tree: '2,0|3,0|4,0|5,0|2,1|5,1|6,1|7,1|2,2|7,2|8,2|9,2|10,2|11,2|12,2|2,3|12,3|2,4|3,4|4,4|7,4|8,4|9,4|12,4|2,5|3,5|4,5|7,5|11,5|12,5|2,6|11,6|2,7|7,7|8,7|11,7|2,8|6,8|7,8|8,8|11,8|2,9|3,9|4,9|5,9|6,9|8,9|9,9|10,9|11,9', box: '5,3|5,4|6,5|9,5|7,6|4,7|5,7', goal: '3,1|4,1|3,2|4,2|5,2|3,3|4,3', boy: '6,2'}, {tree: '3,0|4,0|5,0|6,0|7,0|8,0|9,0|10,0|11,0|2,1|3,1|7,1|8,1|11,1|2,2|7,2|8,2|11,2|2,3|5,3|6,3|7,3|8,3|11,3|2,4|8,4|11,4|2,5|5,5|8,5|11,5|2,6|7,6|8,6|11,6|2,7|3,7|4,7|11,7|4,8|5,8|6,8|7,8|11,8|7,9|8,9|9,9|10,9|11,9', box: '5,2|4,3|10,3|4,5|6,5|9,5|5,6|10,7', goal: '9,1|10,1|9,2|10,2|9,3|10,3|9,4|10,4', boy: '6,1'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|10,2|3,3|10,3|3,4|10,4|3,5|10,5|3,6|9,6|10,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7', box: '5,3|7,3|4,4|5,4|6,4|7,4|8,4|5,5', goal: '5,3|7,3|4,4|6,4|7,4|8,4|9,4|5,5', boy: '4,2'}, {tree: '5,1|6,1|7,1|8,1|9,1|10,1|5,2|10,2|3,3|4,3|5,3|10,3|3,4|10,4|3,5|8,5|10,5|3,6|6,6|8,6|9,6|10,6|3,7|8,7|3,8|4,8|5,8|6,8|7,8|8,8', box: '7,2|8,3|6,4|8,4|5,5|6,5|7,5', goal: '8,2|9,2|8,3|9,3|8,4|9,4|9,5', boy: '4,7'}, {tree: '4,1|5,1|6,1|7,1|8,1|3,2|4,2|8,2|9,2|10,2|11,2|3,3|11,3|3,4|8,4|11,4|2,5|3,5|5,5|6,5|11,5|2,6|6,6|10,6|11,6|2,7|8,7|9,7|10,7|2,8|3,8|4,8|5,8|6,8|7,8|8,8', box: '5,3|9,3|6,4|7,4|9,4|9,5|4,6', goal: '4,4|4,5|4,6|5,6|4,7|5,7|6,7', boy: '10,4'}, {tree: '3,0|4,0|5,0|6,0|7,0|8,0|3,1|8,1|2,2|3,2|8,2|9,2|2,3|5,3|9,3|2,4|7,4|9,4|10,4|2,5|6,5|7,5|10,5|11,5|12,5|2,6|3,6|12,6|3,7|4,7|5,7|6,7|12,7|6,8|7,8|8,8|9,8|10,8|11,8|12,8', box: '6,2|7,2|6,3|4,4|5,5|10,6', goal: '8,4|8,5|9,5|7,6|8,6|9,6', boy: '7,7'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|3,3|4,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '7,3|8,3|6,4|8,4|6,5|7,5', goal: '6,3|8,3|6,4|8,4|6,5|8,5', boy: '7,4'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|3,3|4,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|9,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7', box: '7,3|8,3|6,4|8,4|6,5|7,5', goal: '6,3|8,3|6,4|8,4|6,5|8,5', boy: '7,4'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|3,3|4,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '7,3|8,3|6,4|8,4|6,5|7,5', goal: '6,3|7,3|8,3|6,5|7,5|8,5', boy: '7,4'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|3,3|4,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|9,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7', box: '7,3|8,3|6,4|8,4|6,5|7,5', goal: '6,3|7,3|8,3|6,5|7,5|8,5', boy: '7,4'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|3,3|4,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '7,3|8,3|6,4|8,4|6,5|7,5', goal: '6,3|7,3|6,4|8,4|7,5|8,5', boy: '7,4'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|4,2|10,2|3,3|4,3|10,3|3,4|10,4|3,5|10,5|3,6|4,6|9,6|10,6|4,7|5,7|6,7|7,7|8,7|9,7', box: '7,3|8,3|6,4|8,4|6,5|7,5', goal: '6,3|7,3|6,4|8,4|7,5|8,5', boy: '7,4'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|3,2|9,2|10,2|3,3|10,3|3,4|10,4|3,5|9,5|10,5|3,6|9,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7', box: '5,3|6,3|7,3|8,3|5,4|5,5|6,5|7,5', goal: '5,3|6,3|5,4|6,4|7,4|5,5|6,5|7,5', boy: '6,4'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|3,2|9,2|10,2|3,3|10,3|3,4|7,4|10,4|3,5|9,5|10,5|3,6|9,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7', box: '6,3|7,3|8,3|5,4|6,5', goal: '5,3|6,3|5,4|5,5|6,5', boy: '8,4'}, {tree: '5,1|6,1|7,1|8,1|9,1|10,1|11,1|4,2|5,2|11,2|4,3|7,3|9,3|11,3|4,4|11,4|3,5|4,5|6,5|7,5|9,5|11,5|3,6|11,6|3,7|7,7|10,7|11,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '6,3|5,4|9,4|8,5|5,6', goal: '6,2|7,2|8,2|10,2|8,3', boy: '6,4'}, {tree: '5,1|6,1|7,1|8,1|9,1|10,1|11,1|4,2|5,2|11,2|4,3|7,3|9,3|11,3|4,4|9,4|11,4|3,5|4,5|6,5|7,5|9,5|11,5|3,6|11,6|3,7|7,7|10,7|11,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '8,3|8,5|8,6', goal: '6,2|7,2|8,2', boy: '4,7'}, {tree: '4,2|5,2|6,2|7,2|8,2|9,2|4,3|9,3|4,4|9,4|4,5|9,5|4,6|5,6|6,6|7,6|8,6|9,6', box: '5,4|6,4|7,4', goal: '6,3|5,5|7,5', boy: '8,5'}, {tree: '3,2|4,2|5,2|6,2|7,2|8,2|9,2|10,2|11,2|2,3|3,3|11,3|2,4|7,4|8,4|9,4|10,4|11,4|2,5|7,5|2,6|3,6|7,6|3,7|4,7|5,7|6,7|7,7', box: '6,3|5,4|6,4', goal: '8,3|9,3|10,3', boy: '7,3'}, {tree: '4,2|5,2|6,2|7,2|8,2|9,2|4,3|9,3|4,4|9,4|4,5|9,5|4,6|5,6|6,6|7,6|8,6|9,6', box: '5,4|6,4|7,4', goal: '7,3|8,3|5,5', boy: '8,5'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|4,3|6,3|9,3|4,4|9,4|4,5|8,5|9,5|4,6|7,6|8,6|4,7|5,7|6,7|7,7', box: '7,3|6,4|6,5', goal: '5,2|6,2|7,2', boy: '5,6'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|4,3|9,3|4,4|9,4|4,5|7,5|8,5|9,5|4,6|5,6|7,6|5,7|6,7|7,7', box: '6,3|7,4|6,5', goal: '8,3|6,4|5,5', boy: '6,6'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|4,3|9,3|4,4|5,4|7,4|9,4|4,5|9,5|4,6|9,6|4,7|9,7|4,8|5,8|6,8|7,8|8,8|9,8', box: '6,3|8,4|6,5|7,5|7,6', goal: '8,6|5,7|6,7|7,7|8,7', boy: '7,2'}, {tree: '6,1|7,1|8,1|9,1|10,1|6,2|10,2|5,3|6,3|8,3|10,3|11,3|3,4|4,4|5,4|11,4|3,5|9,5|11,5|3,6|4,6|5,6|7,6|11,6|5,7|6,7|7,7|8,7|9,7|10,7|11,7', box: '7,4|7,5|8,5', goal: '4,5|5,5|6,5', boy: '6,6'}, {tree: '6,1|7,1|8,1|9,1|10,1|5,2|6,2|10,2|5,3|8,3|10,3|5,4|10,4|3,5|4,5|5,5|8,5|10,5|3,6|8,6|10,6|3,7|4,7|6,7|10,7|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '7,4|6,5|6,6', goal: '4,6|5,6|6,6', boy: '5,7'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|7,2|10,2|3,3|10,3|11,3|3,4|4,4|11,4|4,5|5,5|6,5|11,5|6,6|10,6|11,6|6,7|7,7|10,7|7,8|8,8|9,8|10,8', box: '6,3|6,4|7,4|8,4|8,5', goal: '4,2|5,2|6,2|5,3|6,3', boy: '5,4'}, {tree: '2,1|3,1|4,1|5,1|6,1|7,1|8,1|9,1|2,2|9,2|2,3|9,3|10,3|2,4|3,4|4,4|10,4|11,4|12,4|3,5|12,5|3,6|12,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7|12,7|9,8|10,8|11,8|12,8', box: '6,2|4,3|7,3|6,4|5,5|7,5|8,5|9,5', goal: '6,2|5,3|7,3|6,4|7,4|5,5|6,5|7,5', boy: '8,2'}, {tree: '2,1|3,1|4,1|5,1|6,1|7,1|8,1|9,1|2,2|9,2|2,3|9,3|10,3|2,4|3,4|5,4|10,4|11,4|12,4|3,5|12,5|3,6|12,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7|12,7|9,8|10,8|11,8|12,8', box: '7,2|4,3|7,3|6,4|7,4|5,5|7,5|10,5', goal: '6,2|5,3|7,3|6,4|7,4|5,5|6,5|7,5', boy: '8,2'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|3,2|8,2|3,3|8,3|9,3|10,3|3,4|10,4|3,5|4,5|5,5|10,5|5,6|10,6|5,7|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '5,3|6,3|7,3|5,4|7,4|7,5|8,6', goal: '4,2|5,2|6,2|7,2|4,3|6,3|5,4', boy: '4,4'}, {tree: '3,1|4,1|5,1|6,1|7,1|3,2|7,2|8,2|3,3|8,3|9,3|10,3|3,4|10,4|3,5|4,5|5,5|10,5|5,6|10,6|5,7|6,7|7,7|10,7|7,8|8,8|9,8|10,8', box: '5,3|6,3|5,4|7,4|7,5|8,6', goal: '4,2|5,2|6,2|4,3|5,4|9,4', boy: '4,4'}, {tree: '3,2|4,2|5,2|6,2|7,2|8,2|9,2|10,2|11,2|12,2|2,3|3,3|12,3|2,4|7,4|8,4|9,4|10,4|11,4|12,4|2,5|7,5|2,6|3,6|7,6|3,7|4,7|5,7|6,7|7,7', box: '10,3|5,4|6,4', goal: '9,3|10,3|11,3', boy: '11,3'}, {tree: '5,2|6,2|7,2|8,2|9,2|10,2|4,3|5,3|10,3|4,4|8,4|10,4|4,5|10,5|4,6|7,6|9,6|10,6|4,7|9,7|4,8|5,8|6,8|7,8|8,8|9,8', box: '6,4|7,5|8,6', goal: '8,3|6,5|5,7', boy: '7,7'}, {tree: '4,2|5,2|6,2|7,2|8,2|9,2|10,2|4,3|10,3|4,4|6,4|8,4|10,4|4,5|10,5|4,6|9,6|10,6|4,7|7,7|8,7|9,7|4,8|5,8|6,8|7,8', box: '8,5|6,6|7,6', goal: '5,3|7,4|5,6', boy: '8,3'}, {tree: '4,1|5,1|6,1|8,1|9,1|10,1|4,2|6,2|7,2|8,2|10,2|4,3|6,3|10,3|4,4|10,4|4,5|10,5|4,6|7,6|10,6|4,7|7,7|8,7|9,7|10,7|4,8|5,8|6,8|7,8', box: '6,4|7,4|7,5', goal: '5,2|9,2|9,3', boy: '9,4'}, {tree: '6,1|7,1|8,1|9,1|6,2|9,2|10,2|3,3|4,3|5,3|6,3|10,3|3,4|6,4|10,4|3,5|9,5|10,5|3,6|8,6|9,6|3,7|4,7|8,7|4,8|5,8|6,8|7,8|8,8', box: '7,4|8,4|7,6', goal: '4,4|4,6|5,7', boy: '8,2'}, {tree: '3,2|4,2|5,2|6,2|7,2|3,3|7,3|8,3|9,3|10,3|3,4|10,4|3,5|6,5|8,5|10,5|3,6|10,6|3,7|4,7|5,7|6,7|7,7|8,7|9,7|10,7', box: '5,4|7,5|8,6', goal: '5,3|6,3|7,6', boy: '5,6'}, {tree: '3,2|4,2|5,2|6,2|7,2|8,2|9,2|3,3|9,3|3,4|7,4|9,4|10,4|3,5|5,5|10,5|3,6|8,6|10,6|3,7|4,7|5,7|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '6,4|7,5|7,6', goal: '4,3|8,3|8,5', boy: '7,3'}, {tree: '4,2|5,2|6,2|7,2|8,2|4,3|8,3|9,3|10,3|4,4|6,4|10,4|4,5|10,5|4,6|7,6|10,6|4,7|5,7|9,7|10,7|5,8|6,8|7,8|8,8|9,8', box: '7,4|8,4|6,6', goal: '5,3|7,3|5,4', boy: '8,5'}, {tree: '3,2|4,2|5,2|6,2|7,2|8,2|9,2|10,2|3,3|10,3|3,4|5,4|7,4|10,4|3,5|10,5|3,6|4,6|5,6|6,6|7,6|10,6|7,7|10,7|7,8|8,8|9,8|10,8', box: '5,5|8,5|9,6', goal: '4,3|8,3|9,5', boy: '4,5'}, {tree: '4,2|5,2|6,2|7,2|8,2|4,3|8,3|9,3|10,3|3,4|4,4|10,4|3,5|10,5|3,6|4,6|6,6|8,6|9,6|10,6|4,7|8,7|4,8|5,8|6,8|7,8|8,8', box: '6,5|8,5|5,6', goal: '6,4|4,5|7,5', boy: '6,3'}, {tree: '4,2|5,2|6,2|7,2|3,3|4,3|7,3|8,3|9,3|10,3|3,4|10,4|3,5|5,5|10,5|3,6|7,6|10,6|3,7|4,7|5,7|6,7|7,7|10,7|7,8|8,8|9,8|10,8', box: '6,4|6,5|8,5', goal: '4,4|5,4|9,4', boy: '4,6'}, {tree: '4,1|5,1|6,1|7,1|4,2|7,2|4,3|7,3|3,4|4,4|7,4|8,4|9,4|10,4|3,5|10,5|3,6|8,6|9,6|10,6|3,7|4,7|5,7|8,7|5,8|6,8|7,8|8,8', box: '5,5|6,5|6,6', goal: '5,4|7,5|9,5', boy: '5,2'}, {tree: '6,2|7,2|8,2|9,2|10,2|6,3|10,3|6,4|8,4|10,4|4,5|5,5|6,5|10,5|4,6|10,6|4,7|10,7|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '7,6|8,6|8,7', goal: '9,4|9,5|7,7', boy: '5,6'}, {tree: '4,2|5,2|6,2|7,2|8,2|9,2|4,3|9,3|10,3|4,4|7,4|10,4|4,5|10,5|4,6|8,6|10,6|4,7|5,7|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '8,5|6,6|7,6', goal: '5,5|9,6|9,7', boy: '7,3'}, {tree: '5,3|6,3|7,3|8,3|3,4|4,4|5,4|8,4|3,5|8,5|9,5|10,5|3,6|10,6|3,7|4,7|10,7|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '7,6|8,6|8,7', goal: '6,4|5,5|6,7', boy: '9,7'}, {tree: '7,1|8,1|9,1|10,1|7,2|10,2|5,3|6,3|7,3|10,3|5,4|10,4|3,5|4,5|5,5|8,5|10,5|3,6|10,6|3,7|7,7|10,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8|10,8', box: '8,3|5,6|8,6', goal: '9,3|8,4|9,5', boy: '9,7'}, {tree: '3,1|4,1|5,1|6,1|7,1|3,2|7,2|8,2|9,2|3,3|9,3|3,4|6,4|7,4|9,4|10,4|3,5|4,5|7,5|10,5|4,6|10,6|4,7|7,7|8,7|9,7|10,7|4,8|5,8|6,8|7,8', box: '5,3|8,4|5,6', goal: '6,2|6,3|7,3', boy: '9,6'}, {tree: '4,2|5,2|6,2|7,2|8,2|9,2|10,2|3,3|4,3|10,3|3,4|6,4|10,4|3,5|9,5|10,5|3,6|6,6|9,6|3,7|6,7|7,7|8,7|9,7|3,8|4,8|5,8|6,8', box: '5,5|6,5|7,5', goal: '4,4|8,5|5,6', boy: '5,3'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|4,2|9,2|10,2|4,3|5,3|10,3|3,4|4,4|5,4|10,4|3,5|7,5|9,5|10,5|3,6|9,6|3,7|4,7|5,7|6,7|9,7|6,8|7,8|8,8|9,8', box: '6,3|5,5|8,5', goal: '7,4|5,6|8,6', boy: '5,2'}, {tree: '4,1|5,1|6,1|7,1|8,1|4,2|8,2|9,2|10,2|4,3|10,3|4,4|5,4|10,4|5,5|10,5|5,6|6,6|8,6|10,6|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '7,3|6,4|7,4', goal: '9,4|8,5|9,7', boy: '6,5'}, {tree: '3,1|4,1|5,1|6,1|7,1|3,2|7,2|8,2|9,2|10,2|3,3|10,3|3,4|6,4|10,4|3,5|6,5|7,5|9,5|10,5|3,6|6,6|7,6|9,6|3,7|9,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8', box: '5,3|6,3|8,6', goal: '5,4|7,4|8,7', boy: '5,7'}, {tree: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|4,2|10,2|3,3|10,3|3,4|7,4|8,4|9,4|10,4|3,5|6,5|7,5|3,6|6,6|3,7|6,7|3,8|4,8|5,8|6,8', box: '5,3|8,3|5,4', goal: '8,2|4,4|6,4', boy: '9,3'}, {tree: '5,3|6,3|7,3|8,3|3,4|4,4|5,4|8,4|9,4|10,4|3,5|10,5|3,6|10,6|3,7|4,7|5,7|6,7|10,7|6,8|7,8|8,8|9,8|10,8', box: '8,5|6,6|7,6', goal: '5,5|6,5|9,5', boy: '9,6'}, {tree: '3,1|4,1|5,1|6,1|7,1|8,1|9,1|10,1|3,2|7,2|10,2|3,3|5,3|10,3|3,4|10,4|3,5|4,5|5,5|6,5|7,5|10,5|5,6|10,6|5,7|10,7|5,8|6,8|7,8|8,8|9,8|10,8', box: '7,3|9,3|7,4', goal: '6,3|8,5|9,7', boy: '9,5'}, {tree: '6,1|7,1|8,1|9,1|10,1|6,2|10,2|4,3|5,3|6,3|10,3|4,4|9,4|10,4|3,5|4,5|9,5|3,6|7,6|9,6|3,7|9,7|3,8|4,8|5,8|6,8|7,8|8,8|9,8', box: '6,4|8,4|6,5', goal: '4,6|4,7|5,7', boy: '9,3'}, {tree: '1,1|1,2|1,3|1,4|3,4|4,4|5,4|11,4|12,4|13,4|1,5|3,5|5,5|11,5|1,6|3,6|5,6|11,6|12,6|13,6|1,7|3,7|5,7|11,7|1,8|3,8|4,8|5,8|11,8|12,8|13,8', box: '4,1|5,1|6,1|7,1|8,1|9,1|10,1|11,1|12,1', goal: '7,4|9,4|7,5|9,5|7,6|9,6|7,7|9,7|8,8', boy: '8,5'}]; 2 | 3 | export default function getData(level) { 4 | const {tree, box, goal, boy} = gameData[level - 1]; 5 | const [trees, buckets, spots] = [tree, box, goal].map((data) => { 6 | return data.split('|').map(t => t.split(',').map(Number)); 7 | }); 8 | const man = boy.split(',').map(Number); 9 | return {trees, buckets, spots, man}; 10 | } -------------------------------------------------------------------------------- /js/app.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Boxman=t():e.Boxman=t()}(window,function(){return function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/js/",n(n.s=16)}([function(e,t,n){e.exports=n(8)},function(e,t,n){var o=n(9),r=n(10),i=n(11);e.exports=function(e,t){return o(e)||r(e,t)||i()}},function(e,t){function n(e,t,n,o,r,i,a){try{var s=e[i](a),u=s.value}catch(e){return void n(e)}s.done?t(u):Promise.resolve(u).then(o,r)}e.exports=function(e){return function(){var t=this,o=arguments;return new Promise(function(r,i){var a=e.apply(t,o);function s(e){n(a,r,i,s,u,"next",e)}function u(e){n(a,r,i,s,u,"throw",e)}s(void 0)})}}},function(e,t,n){(function(n){var o; 2 | /*! 3 | * howler.js v2.1.1 4 | * howlerjs.com 5 | * 6 | * (c) 2013-2018, James Simpson of GoldFire Studios 7 | * goldfirestudios.com 8 | * 9 | * MIT License 10 | */ 11 | /*! 12 | * howler.js v2.1.1 13 | * howlerjs.com 14 | * 15 | * (c) 2013-2018, James Simpson of GoldFire Studios 16 | * goldfirestudios.com 17 | * 18 | * MIT License 19 | */ 20 | !function(){"use strict";var r=function(){this.init()};r.prototype={init:function(){var e=this||i;return e._counter=1e3,e._html5AudioPool=[],e.html5PoolSize=10,e._codecs={},e._howls=[],e._muted=!1,e._volume=1,e._canPlayEvent="canplaythrough",e._navigator="undefined"!=typeof window&&window.navigator?window.navigator:null,e.masterGain=null,e.noAudio=!1,e.usingWebAudio=!0,e.autoSuspend=!0,e.ctx=null,e.autoUnlock=!0,e._setup(),e},volume:function(e){var t=this||i;if(e=parseFloat(e),t.ctx||f(),void 0!==e&&e>=0&&e<=1){if(t._volume=e,t._muted)return t;t.usingWebAudio&&t.masterGain.gain.setValueAtTime(e,i.ctx.currentTime);for(var n=0;n=0;t--)e._howls[t].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,f()),e},codecs:function(e){return(this||i)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||i;if(e.state=e.ctx&&e.ctx.state||"suspended",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{void 0===(new Audio).oncanplaythrough&&(e._canPlayEvent="canplay")}catch(t){e.noAudio=!0}else e.noAudio=!0;try{(new Audio).muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||i,t=null;try{t="undefined"!=typeof Audio?new Audio:null}catch(t){return e}if(!t||"function"!=typeof t.canPlayType)return e;var n=t.canPlayType("audio/mpeg;").replace(/^no$/,""),o=e._navigator&&e._navigator.userAgent.match(/OPR\/([0-6].)/g),r=o&&parseInt(o[0].split("/")[1],10)<33;return e._codecs={mp3:!(r||!n&&!t.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!n,opus:!!t.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!t.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),aac:!!t.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!t.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(t.canPlayType("audio/x-m4a;")||t.canPlayType("audio/m4a;")||t.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(t.canPlayType("audio/x-mp4;")||t.canPlayType("audio/mp4;")||t.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),webm:!!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),dolby:!!t.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(t.canPlayType("audio/x-flac;")||t.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_unlockAudio:function(){var e=this||i,t=/iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi|Chrome|Safari/i.test(e._navigator&&e._navigator.userAgent);if(!e._audioUnlocked&&e.ctx&&t){e._audioUnlocked=!1,e.autoUnlock=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var n=function(t){for(var o=0;o0?s._seek:n._sprite[e][0]/1e3),c=Math.max(0,(n._sprite[e][0]+n._sprite[e][1])/1e3-l),d=1e3*c/Math.abs(s._rate),_=n._sprite[e][0]/1e3,f=(n._sprite[e][0]+n._sprite[e][1])/1e3,p=!(!s._loop&&!n._sprite[e][2]);s._sprite=e,s._ended=!1;var h=function(){s._paused=!1,s._seek=l,s._start=_,s._stop=f,s._loop=p};if(!(l>=f)){var m=s._node;if(n._webAudio){var v=function(){n._playLock=!1,h(),n._refreshBuffer(s);var e=s._muted||n._muted?0:s._volume;m.gain.setValueAtTime(e,i.ctx.currentTime),s._playStart=i.ctx.currentTime,void 0===m.bufferSource.start?s._loop?m.bufferSource.noteGrainOn(0,l,86400):m.bufferSource.noteGrainOn(0,l,c):s._loop?m.bufferSource.start(0,l,86400):m.bufferSource.start(0,l,c),d!==1/0&&(n._endTimers[s._id]=setTimeout(n._ended.bind(n,s),d)),t||setTimeout(function(){n._emit("play",s._id),n._loadQueue()},0)};"running"===i.state?v():(n._playLock=!0,n.once("resume",v),n._clearTimer(s._id))}else{var y=function(){m.currentTime=l,m.muted=s._muted||n._muted||i._muted||m.muted,m.volume=s._volume*i.volume(),m.playbackRate=s._rate;try{var o=m.play();if(o&&"undefined"!=typeof Promise&&(o instanceof Promise||"function"==typeof o.then)?(n._playLock=!0,h(),o.then(function(){n._playLock=!1,m._unlocked=!0,t||(n._emit("play",s._id),n._loadQueue())}).catch(function(){n._playLock=!1,n._emit("playerror",s._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."),s._ended=!0,s._paused=!0})):t||(n._playLock=!1,h(),n._emit("play",s._id),n._loadQueue()),m.playbackRate=s._rate,m.paused)return void n._emit("playerror",s._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");"__default"!==e||s._loop?n._endTimers[s._id]=setTimeout(n._ended.bind(n,s),d):(n._endTimers[s._id]=function(){n._ended(s),m.removeEventListener("ended",n._endTimers[s._id],!1)},m.addEventListener("ended",n._endTimers[s._id],!1))}catch(e){n._emit("playerror",s._id,e)}},b=window&&window.ejecta||!m.readyState&&i._navigator.isCocoonJS;if(m.readyState>=3||b)y();else{n._playLock=!0;var g=function(){y(),m.removeEventListener(i._canPlayEvent,g,!1)};m.addEventListener(i._canPlayEvent,g,!1),n._clearTimer(s._id)}}return s._id}n._ended(s)},pause:function(e){var t=this;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"pause",action:function(){t.pause(e)}}),t;for(var n=t._getSoundIds(e),o=0;o=0?t=parseInt(r[0],10):e=parseFloat(r[0]):r.length>=2&&(e=parseFloat(r[0]),t=parseInt(r[1],10)),!(void 0!==e&&e>=0&&e<=1))return(n=t?o._soundById(t):o._sounds[0])?n._volume:0;if("loaded"!==o._state||o._playLock)return o._queue.push({event:"volume",action:function(){o.volume.apply(o,r)}}),o;void 0===t&&(o._volume=e),t=o._getSoundIds(t);for(var a=0;a0?o/l:o),d=Date.now();e._fadeTo=n,e._interval=setInterval(function(){var r=(Date.now()-d)/o;d=Date.now(),s+=u*r,s=Math.max(0,s),s=Math.min(1,s),s=Math.round(100*s)/100,a._webAudio?e._volume=s:a.volume(s,e._id,!0),i&&(a._volume=s),(nt&&s>=n)&&(clearInterval(e._interval),e._interval=null,e._fadeTo=null,a.volume(n,e._id),a._emit("fade",e._id))},c)},_stopFade:function(e){var t=this._soundById(e);return t&&t._interval&&(this._webAudio&&t._node.gain.cancelScheduledValues(i.ctx.currentTime),clearInterval(t._interval),t._interval=null,this.volume(t._fadeTo,e),t._fadeTo=null,this._emit("fade",e)),this},loop:function(){var e,t,n,o=arguments;if(0===o.length)return this._loop;if(1===o.length){if("boolean"!=typeof o[0])return!!(n=this._soundById(parseInt(o[0],10)))&&n._loop;e=o[0],this._loop=e}else 2===o.length&&(e=o[0],t=parseInt(o[1],10));for(var r=this._getSoundIds(t),i=0;i=0?t=parseInt(r[0],10):e=parseFloat(r[0])}else 2===r.length&&(e=parseFloat(r[0]),t=parseInt(r[1],10));if("number"!=typeof e)return(n=o._soundById(t))?n._rate:o._rate;if("loaded"!==o._state||o._playLock)return o._queue.push({event:"rate",action:function(){o.rate.apply(o,r)}}),o;void 0===t&&(o._rate=e),t=o._getSoundIds(t);for(var a=0;a=0?t=parseInt(o[0],10):n._sounds.length&&(t=n._sounds[0]._id,e=parseFloat(o[0]))}else 2===o.length&&(e=parseFloat(o[0]),t=parseInt(o[1],10));if(void 0===t)return n;if("loaded"!==n._state||n._playLock)return n._queue.push({event:"seek",action:function(){n.seek.apply(n,o)}}),n;var r=n._soundById(t);if(r){if(!("number"==typeof e&&e>=0)){if(n._webAudio){var a=n.playing(t)?i.ctx.currentTime-r._playStart:0,s=r._rateSeek?r._rateSeek-r._seek:0;return r._seek+(s+a*Math.abs(r._rate))}return r._node.currentTime}var u=n.playing(t);u&&n.pause(t,!0),r._seek=e,r._ended=!1,n._clearTimer(t),n._webAudio||!r._node||isNaN(r._node.duration)||(r._node.currentTime=e);var l=function(){n._emit("seek",t),u&&n.play(t,!0)};if(u&&!n._webAudio){var c=function(){n._playLock?setTimeout(c,0):l()};setTimeout(c,0)}else l()}return n},playing:function(e){if("number"==typeof e){var t=this._soundById(e);return!!t&&!t._paused}for(var n=0;n=0&&i._howls.splice(o,1);var r=!0;for(n=0;n=0){r=!1;break}return u&&r&&delete u[e._src],i.noAudio=!1,e._state="unloaded",e._sounds=[],e=null,null},on:function(e,t,n,o){var r=this["_on"+e];return"function"==typeof t&&r.push(o?{id:n,fn:t,once:o}:{id:n,fn:t}),this},off:function(e,t,n){var o=this["_on"+e],r=0;if("number"==typeof t&&(n=t,t=null),t||n)for(r=0;r=0;r--)o[r].id&&o[r].id!==t&&"load"!==e||(setTimeout(function(e){e.call(this,t,n)}.bind(this,o[r].fn),0),o[r].once&&this.off(e,o[r].fn,o[r].id));return this._loadQueue(e),this},_loadQueue:function(e){if(this._queue.length>0){var t=this._queue[0];t.event===e&&(this._queue.shift(),this._loadQueue()),e||t.action()}return this},_ended:function(e){var t=e._sprite;if(!this._webAudio&&e._node&&!e._node.paused&&!e._node.ended&&e._node.currentTime=0;n--){if(t<=e)return;this._sounds[n]._ended&&(this._webAudio&&this._sounds[n]._node&&this._sounds[n]._node.disconnect(0),this._sounds.splice(n,1),t--)}}},_getSoundIds:function(e){if(void 0===e){for(var t=[],n=0;n=0;if(i._scratchBuffer&&e.bufferSource&&(e.bufferSource.onended=null,e.bufferSource.disconnect(0),t))try{e.bufferSource.buffer=i._scratchBuffer}catch(e){}return e.bufferSource=null,this}};var s=function(e){this._parent=e,this.init()};s.prototype={init:function(){var e=this._parent;return this._muted=e._muted,this._loop=e._loop,this._volume=e._volume,this._rate=e._rate,this._seek=0,this._paused=!0,this._ended=!0,this._sprite="__default",this._id=++i._counter,e._sounds.push(this),this.create(),this},create:function(){var e=this._parent,t=i._muted||this._muted||this._parent._muted?0:this._volume;return e._webAudio?(this._node=void 0===i.ctx.createGain?i.ctx.createGainNode():i.ctx.createGain(),this._node.gain.setValueAtTime(t,i.ctx.currentTime),this._node.paused=!0,this._node.connect(i.masterGain)):(this._node=i._obtainHtml5Audio(),this._errorFn=this._errorListener.bind(this),this._node.addEventListener("error",this._errorFn,!1),this._loadFn=this._loadListener.bind(this),this._node.addEventListener(i._canPlayEvent,this._loadFn,!1),this._node.src=e._src,this._node.preload="auto",this._node.volume=t*i.volume(),this._node.load()),this},reset:function(){var e=this._parent;return this._muted=e._muted,this._loop=e._loop,this._volume=e._volume,this._rate=e._rate,this._seek=0,this._rateSeek=0,this._paused=!0,this._ended=!0,this._sprite="__default",this._id=++i._counter,this},_errorListener:function(){this._parent._emit("loaderror",this._id,this._node.error?this._node.error.code:0),this._node.removeEventListener("error",this._errorFn,!1)},_loadListener:function(){var e=this._parent;e._duration=Math.ceil(10*this._node.duration)/10,0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue()),this._node.removeEventListener(i._canPlayEvent,this._loadFn,!1)}};var u={},l=function(e){var t=e._src;if(u[t])return e._duration=u[t].duration,void _(e);if(/^data:[^;]+;base64,/.test(t)){for(var n=atob(t.split(",")[1]),o=new Uint8Array(n.length),r=0;r0?(u[t._src]=e,_(t,e)):n()};"undefined"!=typeof Promise&&1===i.ctx.decodeAudioData.length?i.ctx.decodeAudioData(e).then(o).catch(n):i.ctx.decodeAudioData(e,o,n)},_=function(e,t){t&&!e._duration&&(e._duration=t.duration),0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue())},f=function(){if(i.usingWebAudio){try{"undefined"!=typeof AudioContext?i.ctx=new AudioContext:"undefined"!=typeof webkitAudioContext?i.ctx=new webkitAudioContext:i.usingWebAudio=!1}catch(e){i.usingWebAudio=!1}i.ctx||(i.usingWebAudio=!1);var e=/iP(hone|od|ad)/.test(i._navigator&&i._navigator.platform),t=i._navigator&&i._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),n=t?parseInt(t[1],10):null;if(e&&n&&n<9){var o=/safari/.test(i._navigator&&i._navigator.userAgent.toLowerCase());(i._navigator&&i._navigator.standalone&&!o||i._navigator&&!i._navigator.standalone&&!o)&&(i.usingWebAudio=!1)}i.usingWebAudio&&(i.masterGain=void 0===i.ctx.createGain?i.ctx.createGainNode():i.ctx.createGain(),i.masterGain.gain.setValueAtTime(i._muted?0:1,i.ctx.currentTime),i.masterGain.connect(i.ctx.destination)),i._setup()}};void 0===(o=function(){return{Howler:i,Howl:a}}.apply(t,[]))||(e.exports=o),t.Howler=i,t.Howl=a,"undefined"!=typeof window?(window.HowlerGlobal=r,window.Howler=i,window.Howl=a,window.Sound=s):void 0!==n&&(n.HowlerGlobal=r,n.Howler=i,n.Howl=a,n.Sound=s)}(), 21 | /*! 22 | * Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported. 23 | * 24 | * howler.js v2.1.1 25 | * howlerjs.com 26 | * 27 | * (c) 2013-2018, James Simpson of GoldFire Studios 28 | * goldfirestudios.com 29 | * 30 | * MIT License 31 | */ 32 | function(){"use strict";var e;HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(e){if(!this.ctx||!this.ctx.listener)return this;for(var t=this._howls.length-1;t>=0;t--)this._howls[t].stereo(e);return this},HowlerGlobal.prototype.pos=function(e,t,n){return this.ctx&&this.ctx.listener?(t="number"!=typeof t?this._pos[1]:t,n="number"!=typeof n?this._pos[2]:n,"number"!=typeof e?this._pos:(this._pos=[e,t,n],void 0!==this.ctx.listener.positionX?(this.ctx.listener.positionX.setTargetAtTime(this._pos[0],Howler.ctx.currentTime,.1),this.ctx.listener.positionY.setTargetAtTime(this._pos[1],Howler.ctx.currentTime,.1),this.ctx.listener.positionZ.setTargetAtTime(this._pos[2],Howler.ctx.currentTime,.1)):this.ctx.listener.setPosition(this._pos[0],this._pos[1],this._pos[2]),this)):this},HowlerGlobal.prototype.orientation=function(e,t,n,o,r,i){if(!this.ctx||!this.ctx.listener)return this;var a=this._orientation;return t="number"!=typeof t?a[1]:t,n="number"!=typeof n?a[2]:n,o="number"!=typeof o?a[3]:o,r="number"!=typeof r?a[4]:r,i="number"!=typeof i?a[5]:i,"number"!=typeof e?a:(this._orientation=[e,t,n,o,r,i],void 0!==this.ctx.listener.forwardX?(this.ctx.listener.forwardX.setTargetAtTime(e,Howler.ctx.currentTime,.1),this.ctx.listener.forwardY.setTargetAtTime(t,Howler.ctx.currentTime,.1),this.ctx.listener.forwardZ.setTargetAtTime(n,Howler.ctx.currentTime,.1),this.ctx.listener.upX.setTargetAtTime(e,Howler.ctx.currentTime,.1),this.ctx.listener.upY.setTargetAtTime(t,Howler.ctx.currentTime,.1),this.ctx.listener.upZ.setTargetAtTime(n,Howler.ctx.currentTime,.1)):this.ctx.listener.setOrientation(e,t,n,o,r,i),this)},Howl.prototype.init=(e=Howl.prototype.init,function(t){return this._orientation=t.orientation||[1,0,0],this._stereo=t.stereo||null,this._pos=t.pos||null,this._pannerAttr={coneInnerAngle:void 0!==t.coneInnerAngle?t.coneInnerAngle:360,coneOuterAngle:void 0!==t.coneOuterAngle?t.coneOuterAngle:360,coneOuterGain:void 0!==t.coneOuterGain?t.coneOuterGain:0,distanceModel:void 0!==t.distanceModel?t.distanceModel:"inverse",maxDistance:void 0!==t.maxDistance?t.maxDistance:1e4,panningModel:void 0!==t.panningModel?t.panningModel:"HRTF",refDistance:void 0!==t.refDistance?t.refDistance:1,rolloffFactor:void 0!==t.rolloffFactor?t.rolloffFactor:1},this._onstereo=t.onstereo?[{fn:t.onstereo}]:[],this._onpos=t.onpos?[{fn:t.onpos}]:[],this._onorientation=t.onorientation?[{fn:t.onorientation}]:[],e.call(this,t)}),Howl.prototype.stereo=function(e,n){var o=this;if(!o._webAudio)return o;if("loaded"!==o._state)return o._queue.push({event:"stereo",action:function(){o.stereo(e,n)}}),o;var r=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===n){if("number"!=typeof e)return o._stereo;o._stereo=e,o._pos=[e,0,0]}for(var i=o._getSoundIds(n),a=0;a=0;--i){var a=this.tryEntries[i],s=a.completion;if("root"===a.tryLoc)return r("end");if(a.tryLoc<=this.prev){var u=o.call(a,"catchLoc"),l=o.call(a,"finallyLoc");if(u&&l){if(this.prev=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),S(n),p}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var o=n.completion;if("throw"===o.type){var r=o.arg;S(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(e,n,o){return this.delegate={iterator:L(e),resultName:n,nextLoc:o},"next"===this.method&&(this.arg=t),p}},e}(e.exports);try{regeneratorRuntime=o}catch(e){Function("r","regeneratorRuntime = r")(o)}},function(e,t){e.exports=function(e){if(Array.isArray(e))return e}},function(e,t){e.exports=function(e,t){var n=[],o=!0,r=!1,i=void 0;try{for(var a,s=e[Symbol.iterator]();!(o=(a=s.next()).done)&&(n.push(a.value),!t||n.length!==t);o=!0);}catch(e){r=!0,i=e}finally{try{o||null==s.return||s.return()}finally{if(r)throw i}}return n}},function(e,t){e.exports=function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t){e.exports=function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&a(e-1),n=e%o1&&void 0!==arguments[1]?arguments[1]:1;return[function(e,n){return[e-t,n]},function(e,n){return[e+t,n]},function(e,n){return[e,n-t]},function(e,n){return[e,n+t]}][e]}function p(e,t,n){return e<0||e>=o?null:t<0||t>=r?null:t*o+e}var h=null,m=Number(e.man[0]),v=Number(e.man[1]),y={};function b(e,t){return null==y[e]?null:y[e][t]}function g(e,t,n){var o=b(e,t)||[0,0,0,0,0];x(o,n),y[e]=y[e]||{},y[e][t]=o}function x(e,t){for(var n=0;t>=30;)t-=30,n++;e[n]|=1<>>8&255,e>>>16&255,e>>>24&255,255&t,t>>>8&255,t>>>16&255,t>>>24&255],i=-1;return 4294967295!==o&&(i=n>>16&255),{buckets:r=new Set(r.filter(function(e){return 255!==e})),x:255&n,y:n>>8&255,step:i,pre:o}}var T=new Uint32Array(268435456),k=w({buckets:a,pre:-1,x:m,y:v});T[0]=k[0],T[1]=k[1],T[2]=k[2],T[3]=k[3],g(T[0],T[1],p(m,v));var S=4;function I(e,t,n,o,r){var i=function(e){var t=f(e),n=f(e,2);return function(e,o,r){var i=t(o,r),a=p(i[0],i[1]);if(a&&u(e,a))return c;if(a&&e.has(a)){var s=p((i=n(o,r))[0],i[1]);if(s&&u(e,s))return _(e,s,a)}return 0}}(r),a=f(r),l=new Set(e),m=i(l,n,o);if(m){var v=a(n,o);if(m===d&&function(e){return s.every(function(t){return e.has(t)})}(l))return h=function e(t){var n=A(T[t],T[t+1],T[t+2],T[t+3]);return n.step>=0?e(n.pre).concat(n.step):[]}(t).concat(r),!0;var y=w({buckets:l,pre:t,step:r,x:v[0],y:v[1]}),k=b(y[0],y[1]);if(k){var I=p(v[0],v[1]);(function(e,t){for(var n=0;t>=30;)t-=30,n++;return e[n]&1<=15||t>=10}},{key:"isEmpty",value:function(e,t){return!this.isOutOfBound(e,t)&&!this.getItem(e,t)}},{key:"isAtSpot",value:function(e){for(var t=this.container.querySelectorAll(".spot"),n=0;n0&&void 0!==s[0]?s[0]:"right",n=this.boxman,o=Number(n.dataset.x),i=Number(n.dataset.y),a=null,"left"===t?a=this.getItem(o-1,i):"right"===t?a=this.getItem(o+1,i):"up"===t?a=this.getItem(o,i-1):"down"===t&&(a=this.getItem(o,i+1)),a){e.next=13;break}return this.onmove&&this.onmove([n],t),n.className="boxman ".concat(t," walk"),e.next=10,this.moveItem(n,t);case 10:n.className="boxman ".concat(t),e.next=22;break;case 13:if("bucket"!==a.className||!("left"===t&&this.isEmpty(o-2,i)||"right"===t&&this.isEmpty(o+2,i)||"up"===t&&this.isEmpty(o,i-2)||"down"===t&&this.isEmpty(o,i+2))){e.next=21;break}return this.onmove&&this.onmove([n,a],t),n.className="boxman ".concat(t," walk"),e.next=18,Promise.all([this.moveItem(n,t),this.moveItem(a,t)]);case 18:n.className="boxman ".concat(t),e.next=22;break;case 21:n.className="boxman ".concat(t);case 22:case"end":return e.stop()}},e,this)}));return function(){return e.apply(this,arguments)}}()},{key:"moveItem",value:function(t){var n,o,r,i=this,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"right";return"left"===a||"right"===a?(n=Number(t.dataset.x),o="left"===a?n-1:n+1,r="left"):(n=Number(t.dataset.y),o="up"===a?n-1:n+1,r="top"),new Promise(function(a){var s=Date.now(),u=i;requestAnimationFrame(function i(){var l=Math.min(1,(Date.now()-s)/200);t.style[r]="".concat(e.ITEM_WIDTH*((1-l)*n+l*o),"px"),l<1?requestAnimationFrame(i):("left"===r?u.moveTo(t,o,t.dataset.y):u.moveTo(t,t.dataset.x,o),a())})})}},{key:"isWin",value:function(){var e=this,t=this.container.querySelectorAll(".bucket");return Array.from(t).every(function(t){return e.isAtSpot(t)})}},{key:"waitCommand",value:function(){var e=this;return new Promise(function(t){e._command&&window.removeEventListener("keydown",e._command),e._command=function(e){switch(e.keyCode){case 37:t("left");break;case 38:t("up");break;case 39:t("right");break;case 40:t("down");break;default:t(null)}},window.addEventListener("keydown",e._command,{once:!0})})}},{key:"clear",value:function(){this.container.innerHTML=""}},{key:"solve",value:function(){var e=a()(r.a.mark(function e(){var t,n,o,i,a=arguments;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(t=a.length>0&&void 0!==a[0]?a[0]:this.level,n="solved".concat(t),!(o=localStorage.getItem(n))){e.next=5;break}return e.abrupt("return",o.split(","));case 5:return e.next=7,T(b(t));case 7:return i=e.sent,localStorage.setItem(n,i.join()),e.abrupt("return",i);case 10:case"end":return e.stop()}},e,this)}));return function(){return e.apply(this,arguments)}}()},{key:"init",value:function(){var e=this,t=b(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.level),n=t.trees,o=t.spots,r=t.buckets,i=t.man;this.clear(),n.forEach(function(t){var n=u()(t,2),o=n[0],r=n[1];return e.addItem("tree",o,r)}),o.forEach(function(t){var n=u()(t,2),o=n[0],r=n[1];return e.addItem("spot",o,r)}),r.forEach(function(t){var n=u()(t,2),o=n[0],r=n[1];return e.addItem("bucket",o,r)}),this.addItem.apply(this,["boxman"].concat(d()(i)))}},{key:"autoPlay",value:function(){var e=a()(r.a.mark(function e(t){var n,o,i,a=arguments;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:n=a.length>1&&void 0!==a[1]?a[1]:this.level,this.init(n),o=0;case 3:if(!(oe.MAX_LEVEL)&&(n=1),this[k]=n,this.init(n),this.onload&&this.onload(n);case 4:return t.next=6,this.waitCommand();case 6:if(!(o=t.sent)){t.next=10;break}return t.next=10,this.move(o);case 10:if(!this.isWin()){t.next=4;break}case 11:if(!this.onLevelComplete){t.next=14;break}return t.next=14,this.onLevelComplete(n);case 14:case"end":return t.stop()}},t,this)}));return function(e){return t.apply(this,arguments)}}()},{key:"boxman",get:function(){return this.container.querySelector(".boxman")}},{key:"level",get:function(){return this[k]}}]),e}();function I(e){return new Promise(function(t){setTimeout(t,e)})}v()(S,"ITEM_WIDTH",32),v()(S,"MAX_LEVEL",113),new l.Howl({src:["assets/bgsound.mp3"],loop:!0}).play();var L=new l.Howl({src:["assets/step.mp3"]}),E=new l.Howl({src:["assets/success.mp3"]}),O=document.getElementById("currentlevel"),P=document.getElementById("previouslevel"),M=document.getElementById("nextlevel"),H=document.getElementById("reset"),B=document.getElementById("autoplay"),F=Number(localStorage.getItem("playlevel"))||1,N=new S({container:document.getElementById("boxmap"),onload:function(e){O.value=e},onmove:function(e,t){var n=u()(e,2),o=(n[0],n[1]),r=L;if(o){var i=this.getXY(o),a=u()(i,2),s=a[0],l=a[1];"left"===t?s--:"right"===t?s++:"up"===t?l--:l++,this.getSpot(s,l)&&(r=E)}r.play()},onLevelComplete:function(){var e=a()(r.a.mark(function e(t){var n;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return localStorage.setItem("playlevel",t+1),(n=document.getElementById("game-result")).className="show",e.next=5,I(1300);case 5:return n.className="",e.next=8,I(200);case 8:this.load(t+1);case 9:case"end":return e.stop()}},e,this)}));return function(t){return e.apply(this,arguments)}}()});N.load(F),O.addEventListener("change",function(e){var t=e.target;N.load(Number(t.value))}),P.addEventListener("click",function(){N.load(N.level-1)}),M.addEventListener("click",function(){N.load(N.level+1)}),H.addEventListener("click",function(){N.load(N.level)}),B.addEventListener("click",a()(r.a.mark(function e(){var t;return r.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return B.disabled=!0,B.innerHTML="思考中...",e.next=4,N.solve(N.level);case 4:return t=e.sent,B.innerHTML="行动中...",e.next=8,N.autoPlay(t,N.level);case 8:B.disabled=!1,B.innerHTML="自动过关";case 10:case"end":return e.stop()}},e)}))),window.app=N}])}); --------------------------------------------------------------------------------