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();
}
});
})()