NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @namespace https://openuserjs.org/users/preciousmouse // @name Light Up solution // @description auto solve Light Up problem // @author preciousmouse // @copyright 2020, preciousmouse (https://openuserjs.org/users/preciousmouse) // @license MIT // @version 1.1 // @updateURL https://openuserjs.org/meta/preciousmouse/Light_Up_solution.user.js // @downloadURL https://openuserjs.org/install/preciousmouse/Light_Up_solution.user.js // @supportURL https://github.com/puzzle-resolution/LightUp // @require https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.18.2/babel.js // @require https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.js // @require http://requirejs.org/docs/release/2.1.5/comments/require.js // @include https://cn.puzzle-light-up.com/ // @include https://cn.puzzle-light-up.com/?* // @grant none // ==/UserScript== // ==OpenUserJS== // @author preciousmouse // ==/OpenUserJS== console.log("light up solution. set 'window.useRobot = false' to disable auto submiting.") "use strict"; function submitAnswer() { var t; null === (t = document.querySelector("#btnReady")) || void 0 === t || t.click(); } window.useRobot = !0; class LightUp { constructor(t) { this.graph = t, this.blackBlocks = this.initBlackBlocks(t); } initBlackBlocks(t) { let i = []; for (let s of t.keys()) for (let o of t[s].keys()) -1 !== t[s][o] && -2 !== t[s][o] && i.push({ x: s, y: o, count: t[s][o] }); return i; } initState(t) { let i = [], s = []; for (let o of t.keys()) { i[o] = [], s[o] = []; for (let e of t[o].keys()) -1 === t[o][e] ? (i[o][e] = 0, s[o][e] = -1) : (i[o][e] = -2, s[o][e] = 0); } return [ i, s ]; } cloneState(t) { return t.map((t => t.map((t => t)))); } checkBoundary(t) { return !(t.x < 0 || t.x >= this.graph.length || t.y < 0 || t.y >= this.graph[0].length); } clonePosition(t) { return Object.assign({}, t); } leftPosition(t) { return { x: t.x, y: t.y - 1 }; } rightPosition(t) { return { x: t.x, y: t.y + 1 }; } topPosition(t) { return { x: t.x - 1, y: t.y }; } bottomPosition(t) { return { x: t.x + 1, y: t.y }; } listTRBL(t, i, s) { let o = []; for (let e = this.leftPosition(t); this.checkBoundary(e) && !i(this.clonePosition(e)); e = this.leftPosition(e)) s(this.clonePosition(e)) && o.push(this.clonePosition(e)); for (let e = this.rightPosition(t); this.checkBoundary(e) && !i(this.clonePosition(e)); e = this.rightPosition(e)) s(this.clonePosition(e)) && o.push(this.clonePosition(e)); for (let e = this.topPosition(t); this.checkBoundary(e) && !i(this.clonePosition(e)); e = this.topPosition(e)) s(this.clonePosition(e)) && o.push(this.clonePosition(e)); for (let e = this.bottomPosition(t); this.checkBoundary(e) && !i(this.clonePosition(e)); e = this.bottomPosition(e)) s(this.clonePosition(e)) && o.push(this.clonePosition(e)); return o; } listAccessableBlank(t, i) { if (!this.checkBoundary(i)) return []; const {blankState: s} = t; return this.listTRBL(i, (t => -1 !== this.graph[t.x][t.y]), (t => -1 === this.graph[t.x][t.y] && 0 === s[t.x][t.y])); } listUnlightBlank(t, i) { if (!this.checkBoundary(i)) return []; const {blankState: s} = t; return this.listTRBL(i, (t => -1 !== this.graph[t.x][t.y]), (t => -1 === this.graph[t.x][t.y] && 2 !== s[t.x][t.y] && 1 !== s[t.x][t.y])); } aroundTRBL(t, i) { let s = [ void 0, void 0, void 0, void 0 ]; const o = this.topPosition(t); i(this.clonePosition(o)) && (s[0] = o); const e = this.rightPosition(t); i(this.clonePosition(e)) && (s[1] = e); const n = this.bottomPosition(t); i(this.clonePosition(n)) && (s[2] = n); const r = this.leftPosition(t); return i(this.clonePosition(r)) && (s[3] = r), s; } restBlankCanChoose(t, i) { if (!this.checkBoundary(i)) return [ void 0, void 0, void 0, void 0 ]; if (-1 === this.graph[i.x][i.y]) return [ void 0, void 0, void 0, void 0 ]; const {blankState: s} = t; return this.aroundTRBL(i, (t => this.checkBoundary(t) && -1 === this.graph[t.x][t.y] && 0 === s[t.x][t.y])); } restBlackTotal(t) { if (!this.checkBoundary(t)) return [ void 0, void 0, void 0, void 0 ]; if (-1 === this.graph[t.x][t.y]) return [ void 0, void 0, void 0, void 0 ]; return this.aroundTRBL(t, (t => this.checkBoundary(t) && -1 === this.graph[t.x][t.y])); } restBlackFinished(t, i) { if (!this.checkBoundary(i)) return [ void 0, void 0, void 0, void 0 ]; if (-1 === this.graph[i.x][i.y]) return [ void 0, void 0, void 0, void 0 ]; return this.aroundTRBL(i, (i => this.checkBoundary(i) && -1 === this.graph[i.x][i.y] && 1 === t.blankState[i.x][i.y])); } calcBlackState(t, i) { if (!this.checkBoundary(i)) return -1; return this.restBlackFinished(t, this.clonePosition(i)).filter((t => t)).length; } restBlackUnsolved(t, i) { if (!this.checkBoundary(i)) return [ void 0, void 0, void 0, void 0 ]; const {blackState: s} = t; return this.aroundTRBL(i, (t => this.checkBoundary(t) && -1 !== this.graph[t.x][t.y] && -2 !== this.graph[t.x][t.y] && 0 !== this.graph[t.x][t.y] && s[t.x][t.y] !== this.graph[t.x][t.y])); } disablePosition(t, i, s) { const {x: o, y: e} = s; if (!this.checkBoundary(s)) return !1; if (-1 !== this.graph[o][e]) return !1; if (0 === t.blankState[o][e]) { t.blankState[o][e] = -1, this.appendToUpdateQueue(t, i, [ { x: o, y: e } ]); const s = this.restBlackUnsolved(t, { x: o, y: e }); this.appendToUpdateQueue(t, i, s.filter((t => t))); const n = this.listUnlightBlank(t, { x: o, y: e }); return this.appendToUpdateQueue(t, i, n), !0; } return !0; } lightPosition(t, i, s) { t.blankState[s.x][s.y] = 2; const o = this.restBlackUnsolved(t, s); this.appendToUpdateQueue(t, i, o.filter((t => t))); const e = this.listUnlightBlank(t, s); return this.appendToUpdateQueue(t, i, e), !0; } choosePosition(t, i, s) { const {x: o, y: e} = s; if (!this.checkBoundary(s)) return !1; if (-1 !== this.graph[o][e]) return !1; if (0 === t.blankState[o][e]) { t.blankState[o][e] = 1; const s = this.restBlackUnsolved(t, { x: o, y: e }); this.appendToUpdateQueue(t, i, s.filter((t => t))); return this.listUnlightBlank(t, { x: o, y: e }).map((s => this.lightPosition(t, i, s))), !0; } return 1 === t.blankState[o][e]; } updateEqual(t, i, s) { if (!this.checkBoundary(s)) return !1; const {x: o, y: e} = s; let {blankState: n, blackState: r} = t; switch (this.graph[o][e]) { case -1: if (0 === n[o][e]) { if (0 === this.listAccessableBlank(t, s).length && !this.choosePosition(t, i, s)) return !1; } else if (-1 === n[o][e]) { const o = this.listAccessableBlank(t, s); if (0 === o.length) return !1; if (1 === o.length && !this.choosePosition(t, i, this.clonePosition(o[0]))) return !1; } break; case -2: break; default: const h = this.calcBlackState(t, { x: o, y: e }); if (r[o][e] = h, this.graph[o][e] < h) return !1; const a = this.graph[o][e] - h, l = this.restBlankCanChoose(t, s), c = l.filter((t => void 0 !== t)).length; if (c === a) { for (const s of l) if (s && !this.choosePosition(t, i, s)) return !1; } else { if (c < a) return !1; if (0 === a) this.disablePosition(t, i, this.leftPosition({ x: o, y: e })), this.disablePosition(t, i, this.topPosition({ x: o, y: e })), this.disablePosition(t, i, this.rightPosition({ x: o, y: e })), this.disablePosition(t, i, this.bottomPosition({ x: o, y: e })); else if (1 === a && 2 === c) { const [s, n, r, h] = l; if (void 0 !== s && void 0 !== r || void 0 !== n && void 0 !== h) ; else if (void 0 !== s && void 0 !== n) this.disablePosition(t, i, this.topPosition(this.rightPosition({ x: o, y: e }))); else if (void 0 !== n && void 0 !== r) this.disablePosition(t, i, this.rightPosition(this.bottomPosition({ x: o, y: e }))); else if (void 0 !== r && void 0 !== h) this.disablePosition(t, i, this.bottomPosition(this.leftPosition({ x: o, y: e }))); else { if (void 0 === h || void 0 === s) throw new Error("assert 2"); this.disablePosition(t, i, this.leftPosition(this.topPosition({ x: o, y: e }))); } } else if (1 === a && 3 === c) ; else if (1 === a && 4 === c) ; else if (2 === a && 3 === c) { const [s, n, r, h] = l; if (void 0 === s) this.disablePosition(t, i, this.rightPosition(this.bottomPosition({ x: o, y: e }))), this.disablePosition(t, i, this.bottomPosition(this.leftPosition({ x: o, y: e }))); else if (void 0 === n) this.disablePosition(t, i, this.bottomPosition(this.leftPosition({ x: o, y: e }))), this.disablePosition(t, i, this.leftPosition(this.topPosition({ x: o, y: e }))); else if (void 0 === r) this.disablePosition(t, i, this.leftPosition(this.topPosition({ x: o, y: e }))), this.disablePosition(t, i, this.topPosition(this.rightPosition({ x: o, y: e }))); else { if (void 0 !== h) throw new Error("assert 3"); this.disablePosition(t, i, this.topPosition(this.rightPosition({ x: o, y: e }))), this.disablePosition(t, i, this.rightPosition(this.bottomPosition({ x: o, y: e }))); } } else if (2 === a && 4 === c) ; else { if (3 !== a || 4 !== c) throw new Error("assert 4"); this.disablePosition(t, i, { x: o - 1, y: e + 1 }), this.disablePosition(t, i, { x: o + 1, y: e + 1 }), this.disablePosition(t, i, { x: o - 1, y: e - 1 }), this.disablePosition(t, i, { x: o + 1, y: e - 1 }); } } } return !0; } isSolvedPosition(t, i) { const {x: s, y: o} = i; switch (this.graph[s][o]) { case -1: return 1 === t.blankState[s][o] || 2 === t.blankState[s][o]; case 0: return !0; default: return t.blackState[s][o] === this.graph[s][o]; } } appendToUpdateQueue(t, i, s) { for (let {x: o, y: e} of s) { const s = `${o},${e}`; i.has(s) || (this.isSolvedPosition(t, { x: o, y: e }) || i.add(s)); } return !0; } clearUpdateQueue(t, i) { try { for (;i.size > 0; ) { const s = [ ...i.keys() ][0]; i.delete(s); const [o, e] = s.split(",").map((t => +t)); if (!this.updateEqual(t, i, this.clonePosition({ x: o, y: e }))) return !1; } } catch (t) { return !1; } return !0; } findNext(t) { const {blankState: i} = t; for (let t of this.graph.keys()) for (let s of this.graph[t].keys()) if (-1 === this.graph[t][s] && 2 !== i[t][s] && 1 !== i[t][s] && -1 !== i[t][s]) return { x: t, y: s }; return !1; } verificate(t) { const {blackState: i, blankState: s} = t; for (let t of this.graph.keys()) for (let o of this.graph[t].keys()) if (-1 === this.graph[t][o]) { if (2 !== s[t][o] && 1 !== s[t][o]) return !1; } else if (-2 !== this.graph[t][o] && i[t][o] !== this.graph[t][o]) return !1; return !0; } getPositionCases(t, i) { const s = this.listAccessableBlank(t, i); return 0 === t.blankState[i.x][i.y] ? 0 !== s.length ? [ { position: this.clonePosition(i), choose: !0 }, { position: this.clonePosition(i), choose: !1 } ] : [ { position: this.clonePosition(i), choose: !0 } ] : 0 !== s.length ? [ { position: this.clonePosition(i), choose: !1 } ] : []; } applyPositionCase(t, i, s) { const {position: o, choose: e} = s; return e ? this.choosePosition(t, i, o) : this.disablePosition(t, i, o); } recu(t) { const {currentRecuIndex: i} = t; let s = new Set; if (0 == i) { for (let {x: i, y: o, count: e} of this.blackBlocks.values()) if (!this.updateEqual(t, s, { x: i, y: o })) return !1; if (this.clearUpdateQueue(t, s)) { const s = { currentRecuIndex: i, blankState: this.cloneState(t.blankState), blackState: this.cloneState(t.blackState) }; return this.recu(Object.assign(Object.assign({}, s), { currentRecuIndex: s.currentRecuIndex + 1 })); } return !1; } { const o = this.findNext(t); if (o) { const e = this.getPositionCases(t, o); if (0 == e.length) return !1; for (let o of e) { const e = { currentRecuIndex: i, blankState: this.cloneState(t.blankState), blackState: this.cloneState(t.blackState) }, n = new Set(s); if (this.applyPositionCase(e, n, o) && this.clearUpdateQueue(e, n)) { const t = this.recu(Object.assign(Object.assign({}, e), { currentRecuIndex: e.currentRecuIndex + 1 })); if (t) return t; } } return !1; } return !!this.verificate(t) && t; } } solve() { const [t, i] = this.initState(this.graph), s = this.recu({ blankState: this.cloneState(t), blackState: this.cloneState(i), currentRecuIndex: 0 }); return this.answer = s ? this.generaterAnawer(s.blankState) : "failed"; } generaterAnawer(t) { let i = []; for (let s of this.graph[0].keys()) for (let o of this.graph.keys()) 1 === t[o][s] && i.push({ x: o, y: s }); return i.map((t => `${t.y},${t.x}`)).join(";"); } } (() => { const t = `\n\n ${LightUp.toString()} \n onmessage=${(t => { const i = JSON.parse(t.data), s = new LightUp(i).solve(); postMessage(s); }).toString()}\n `, i = task, s = Game.task; console.info("task", i, s); const o = new Date; !function registerWorkerWithBlob(t) { const {scriptStr: i, postMessageStr: s, onMessage: o} = t, e = new Blob([ i ], { type: "text/javascript" }), n = URL.createObjectURL(e), r = new Worker(n); r.onmessage = o, r.postMessage(s); }({ scriptStr: t, postMessageStr: JSON.stringify(s), onMessage: t => { const i = new Date, s = t.data; console.info("answer", s), console.info("耗时", i.valueOf() - o.valueOf(), "ms"), function replaceAnswer(t) { document && $ && ($("#puzzleForm").attr("onsubmit", `console.log('customer onsubmit');\n Game.saveState();\n Game.tickTimer();\n this.jstimerPersonal.value = Game.getTimer();\n this.ansH.value = '${t}';`), $("#btnReady").off("click"), window.useRobot && $("#robot").attr("value", "1")); }(s), window.submit = submitAnswer, window.useRobot && submitAnswer(); } }); })();