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 Binairo solution // @description auto solve Binairo problem // @author preciousmouse // @copyright 2020, preciousmouse (https://openuserjs.org/users/preciousmouse) // @license MIT // @version 1.2 // @updateURL https://openuserjs.org/meta/preciousmouse/Binairo_solution.meta.js // @downloadURL https://openuserjs.org/install/preciousmouse/Binairo_solution.user.js // @supportURL https://github.com/puzzle-resolution/Binairo // @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-binairo.com/ // @include https://cn.puzzle-binairo.com/?* // @grant none // ==/UserScript== // ==OpenUserJS== // @author preciousmouse // ==/OpenUserJS== "use strict"; function submitAnswer() { var t; null === (t = document.querySelector("#btnReady")) || void 0 === t || t.click(); } try { window.useRobot = !0; } catch (t) {} class Binairo { constructor(t) { this.getBlockType = t => ({ [-1]: "Space", 0: "White", 1: "Black" }[t]), this.cloneState = function(t) { return t.map((t => t.map((t => JSON.parse(JSON.stringify(t)))))); }, this.checkBoundary = t => !(t.x < 0 || t.x >= this.graph.length || t.y < 0 || t.y >= this.graph[0].length), this.clonePosition = t => Object.assign({}, t), this.leftPosition = t => ({ x: t.x, y: t.y - 1 }), this.rightPosition = t => ({ x: t.x, y: t.y + 1 }), this.topPosition = t => ({ x: t.x - 1, y: t.y }), this.bottomPosition = t => ({ x: t.x + 1, y: t.y }), this.initState = t => ({ blockState: t.map((t => t.map((t => this.getBlockType(t))))) }), this.available = (t, e, i, s = !1) => { const {blockState: o} = t, {x: a, y: n} = e; if ("Space" !== o[a][n] && o[a][n] !== i) return !1; if (!s) { if (o[a].length / 2 - o[a].filter((t => t === i)).length <= 0) return !1; if (o.length / 2 - o.slice().map((t => t[n])).filter((t => t === i)).length <= 0) return !1; } const same = (t, ...e) => e.every((e => e === t)); return (!this.checkBoundary({ x: a + 2, y: n }) || !same(i, o[a + 1][n], o[a + 2][n])) && (!(this.checkBoundary({ x: a - 1, y: n }) && this.checkBoundary({ x: a + 1, y: n }) && same(i, o[a - 1][n], o[a + 1][n])) && ((!this.checkBoundary({ x: a - 2, y: n }) || !same(i, o[a - 2][n], o[a - 1][n])) && ((!this.checkBoundary({ x: a, y: n + 2 }) || !same(i, o[a][n + 1], o[a][n + 2])) && (this.checkBoundary({ x: a, y: n - 1 }), (!this.checkBoundary({ x: a, y: n + 1 }) || !same(i, o[a][n - 1], o[a][n + 1])) && (!this.checkBoundary({ x: a, y: n - 2 }) || !same(i, o[a][n - 2], o[a][n - 1])))))); }, this.updateAllPoints = t => { let e = new Set; for (let i = 0; i < this.graph.length; i++) for (let s = 0; s < this.graph[0].length; s++) this.updatePoint(t, e, { x: i, y: s }); return this.clearUpdateQueue(t, e); }, this.addPointToQueue = (t, e, i) => this.appendToUpdateQueue(t, e, this.availbleSpace(i).filter((t => t)).map((e => e ? "Space" === t.blockState[e.x][e.y] ? e : this.restSpace(t, e).filter((t => t)) : e)).flat()), this.updatePoint = (t, e, i) => { const {blockState: s} = t, {x: o, y: a} = i; return "Space" !== s[o][a] || (this.available(t, i, "Black") ? this.available(t, i, "White") || (s[o][a] = "Black", this.addPointToQueue(t, e, i)) : (s[o][a] = "White", this.addPointToQueue(t, e, i))), !0; }, this.solvelc = t => { const action = e => { const i = { Black: "White", White: "Black", Space: "Space" }[e], s = t.length / 2 - t.filter((t => t === e)).length; if (0 === s) return t.slice().map((t => "Space" === t ? i : t)); if (s < 0) throw "pRest<0"; const inBoundary = e => 0 <= e && e < t.length, isSpace = e => "Space" === t[e]; let o = [], a = []; for (let [e, s] of t.entries()) s === i ? (inBoundary(e - 2) && isSpace(e - 2) && isSpace(e - 1) && o.push({ s: e - 2, e: e - 1 }), inBoundary(e - 1) && inBoundary(e + 1) && isSpace(e - 1) && isSpace(e + 1) && o.push({ s: e - 1, e: e + 1 }), inBoundary(e + 2) && isSpace(e + 1) && isSpace(e + 2) && o.push({ s: e + 1, e: e + 2 })) : "Space" === s && inBoundary(e - 1) && inBoundary(e + 1) && isSpace(e - 1) && isSpace(e + 1) && a.push({ s: e - 1, e: e + 1 }); o.sort(((t, e) => t.s - e.s)), a.sort(((t, e) => t.s - e.s)); let n = [], r = -1; for (let {s: t, e: e} of o.values()) t > r && (n.push({ s: t, e: e }), r = e); let l = new Set(n.map((({s: t, e: e}) => [ ...Array(e - t + 1).keys() ].map((e => e + t)))).flat()); for (let {s: t, e: e} of a.values()) l.has(t) || l.has(e) || (n.push({ s: t, e: e }), [ ...Array(e - t + 1).keys() ].map((e => e + t)).map((t => l.add(t)))); return n.length === s && t.slice().map(((t, e) => "Space" !== t || l.has(e) ? t : i)); }; return action("Black") || action("White") || t.slice(); }, this.updateLine = (t, e, i) => { const s = t.blockState[i].slice(), o = this.solvelc(s); for (let [s, a] of t.blockState[i].entries()) if ("Space" === a && "Space" !== o[s]) t.blockState[i][s] = o[s], this.addPointToQueue(t, e, { x: i, y: s }); else if (a !== o[s]) return o[s], !1; return !0; }, this.updateColumn = (t, e, i) => { const s = t.blockState.slice().map((t => t[i])), o = this.solvelc(s); for (let [s, a] of t.blockState.entries()) { const n = a[i]; if ("Space" === n && "Space" !== o[s]) t.blockState[s][i] = o[s], this.addPointToQueue(t, e, { x: s, y: i }); else if (n !== o[s]) return o[s], !1; } return !0; }, this.updateLineRule3 = (t, e, i) => { const {blockState: s} = t, o = s[i].slice(), a = o.length / 2 - o.filter((t => "Black" === t)).length, n = o.length / 2 - o.filter((t => "White" === t)).length; if (1 === a && 1 === n) { const stringify = t => t.slice().map((t => ({ Black: 1, White: 0, Space: "n" }[t]))).join(""), a = s.filter((t => t.every((t => "Space" !== t)))), [n, r] = o.slice().map(((t, e) => "Space" === t ? e : void 0)).filter((t => void 0 !== t)); let l = o.slice(), c = o.slice(); l[n] = "Black", l[r] = "White", c[n] = "White", c[r] = "Black"; const h = stringify(l), u = stringify(c); for (let o of a) { const a = stringify(o); if (a === h) return s[i][n] = "White", s[i][r] = "Black", this.addPointToQueue(t, e, { x: i, y: n }), this.addPointToQueue(t, e, { x: i, y: r }), !0; if (a === u) return s[i][n] = "Black", s[i][r] = "White", this.addPointToQueue(t, e, { x: i, y: n }), this.addPointToQueue(t, e, { x: i, y: r }), !0; } } return !1; }, this.updateColumnRule3 = (t, e, i) => { const {blockState: s} = t, o = s.slice().map((t => t[i])), a = s.length / 2 - o.filter((t => "Black" === t)).length, n = s.length / 2 - o.filter((t => "White" === t)).length; if (1 === a && 1 === n) { const stringify = t => t.slice().map((t => ({ Black: 1, White: 0, Space: "n" }[t]))).join(""), a = s.filter((t => t.every((t => "Space" !== t)))), [n, r] = o.slice().map(((t, e) => "Space" === t ? e : void 0)).filter((t => void 0 !== t)); let l = o.slice(), c = o.slice(); l[n] = "Black", l[r] = "White", c[n] = "White", c[r] = "Black"; const h = stringify(l), u = stringify(c); for (let o of a) { const a = stringify(o); if (a === h) return s[n][i] = "White", s[r][i] = "Black", this.addPointToQueue(t, e, { x: n, y: i }), this.addPointToQueue(t, e, { x: r, y: i }), !0; if (a === u) return s[n][i] = "Black", s[r][i] = "White", this.addPointToQueue(t, e, { x: n, y: i }), this.addPointToQueue(t, e, { x: r, y: i }), !0; } } return !1; }, this.updateLines = t => { let e = new Set; for (let i = 0; i < this.graph.length; i++) if (!this.updateLineRule3(t, e, i) && !this.updateLine(t, e, i)) return !1; for (let i = 0; i < this.graph[0].length; i++) if (!this.updateColumnRule3(t, e, i) && !this.updateColumn(t, e, i)) return !1; return this.clearUpdateQueue(t, e); }, this.loop = t => { let e = 0; for (;;) { if (++e, this.verificate(t)) return t; if (!this.updateLines(t)) break; if (e > 100) break; } return !1; }, this.solve = () => { let t = this.initState(this.graph); return this.updateAllPoints(t), this.verificate(t) || (t = this.loop({ blockState: this.cloneState(t.blockState) })), this.answer = t ? this.generaterAnawer(t.blockState) : "failed"; }, this.generaterAnawer = t => t.map((t => t.map((t => ({ Black: 1, White: 0, Space: "n" }[t]))).join(""))).join(""), this.graph = t; } aroundTRBL(t, e = (() => !0)) { let i = [ void 0, void 0, void 0, void 0 ]; const s = this.topPosition(t); e(this.clonePosition(s)) && (i[0] = s); const o = this.rightPosition(t); e(this.clonePosition(o)) && (i[1] = o); const a = this.bottomPosition(t); e(this.clonePosition(a)) && (i[2] = a); const n = this.leftPosition(t); return e(this.clonePosition(n)) && (i[3] = n), i; } availbleSpace(t) { if (!this.checkBoundary(t)) return [ void 0, void 0, void 0, void 0 ]; return this.aroundTRBL(t, (t => this.checkBoundary(t))); } restSpace(t, e) { if (!this.checkBoundary(e)) return [ void 0, void 0, void 0, void 0 ]; return this.aroundTRBL(e, (e => this.checkBoundary(e) && "Space" === t.blockState[e.x][e.y])); } appendToUpdateQueue(t, e, i) { for (let {x: s, y: o} of i) { const i = `${s},${o}`; this.checkBoundary({ x: s, y: o }) && (e.has(i) || "Space" === t.blockState[s][o] && e.add(i)); } return !0; } clearUpdateQueue(t, e) { try { for (;e.size > 0; ) { const i = [ ...e.keys() ][0]; e.delete(i); const [s, o] = i.split(",").map((t => +t)); if (!this.updatePoint(t, e, this.clonePosition({ x: s, y: o }))) return !1; } } catch (t) { return !1; } return !0; } verificate(t) { const {blockState: e} = t; for (let i = 0; i < e.length; i++) for (let s = 0; s < e[0].length; s++) { if ("Space" === e[i][s]) return !1; if (!this.available(t, { x: i, y: s }, e[i][s], !0)) return !1; } return !0; } } (() => { const t = `\n ${Binairo.toString()} \n onmessage=${(t => { const {tasks: e, puzzleSize: i} = JSON.parse(t.data), s = new Binairo(e).solve(); postMessage(s); }).toString()}\n `, e = task, i = Game.task; console.info("task", e, i); const s = new Date; !function registerWorkerWithBlob(t) { const {scriptStr: e, postMessageStr: i, onMessage: s} = t, o = new Blob([ e ], { type: "text/javascript" }), a = URL.createObjectURL(o), n = new Worker(a); n.onmessage = s, n.postMessage(i); }({ scriptStr: t, postMessageStr: JSON.stringify({ tasks: i }), onMessage: t => { const e = new Date, i = t.data; console.info("answer", i), console.info("耗时", e.valueOf() - s.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")); }(i), window.submit = submitAnswer, window.useRobot && submitAnswer(); } }); })()