Skip to content

Instantly share code, notes, and snippets.

@umnikos
Last active February 13, 2023 20:21
Show Gist options
  • Save umnikos/59f6418619c80a042cdc3c3bedf068c2 to your computer and use it in GitHub Desktop.
Save umnikos/59f6418619c80a042cdc3c3bedf068c2 to your computer and use it in GitHub Desktop.
Kaboom superchording (https://pwmarcz.pl/kaboom/)
// ==UserScript==
// @name Kaboom superchording
// @namespace Kaboom
// @match https://pwmarcz.pl/kaboom/
// @grant none
// @version 0.6
// @author umnikos
// ==/UserScript==
// TODO:
// better ui for advanced superchording
// - numbers on higher values
// - red and green colorings indicating what will be resolved as safe or mine
// figure out why that one puzzle is impossible to superchord
// game saving
// css in js!
function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
function makeStyle() {
addGlobalStyle('.cell.label-plus::after { content: "☉"; }');
addGlobalStyle('.cell.label-minus::after { content: "🝰"; }');
addGlobalStyle('.cell.label-high-plus::after { content: "⊛"; }');
addGlobalStyle('.cell.label-low-minus::after { content: "♌︎"; }');
addGlobalStyle('.cell.super-highlight { background: #fff999; }');
}
function new_cellClick(e, x, y) {
e.preventDefault();
switch (e.button) {
case 0:
console.log("click!");
if (this.__proto__.superchording.advanced) {
this.chordAroundCell(x,y,1);
} else {
this.chordAroundCell(x,y,0);
}
if (!this.solver.hasSafeCells()) {
this.reveal(x,y);
}
break;
}
}
function new_cellMouseDown(e, x, y) {
switch(e.button) {
case 1:
e.preventDefault();
console.log("middle click!");
if (this.__proto__.superchording.advanced) {
this.resolveWhite();
this.resetSuperchording();
} else {
this.__proto__.superchording.advanced = true;
this.refreshMana();
}
break;
case 2:
e.preventDefault();
console.log("right click!");
if (this.__proto__.superchording.advanced) {
this.chordAroundCell(x,y,-1);
} else {
this.resetSuperchording();
}
break;
default:
e.preventDefault();
console.log("MYSTERY CLICK!");
break;
}
}
function new_cellDblClick(e, x, y) {
e.preventDefault();
console.log("double click!");
}
function new_chordAroundCell(x,y,n) {
if (!(this.state === State.PLAYING && this.map.labels[y][x] !== null)) {
return;
}
this.cells[y][x].className += " super-highlight";
let my_neighbors = Array.from(neighbors(x, y, this.width, this.height));
let neighborflags = my_neighbors.filter(([x0,y0])=>(this.flags[y0][x0])).length;
let value = this.map.labels[y][x] - neighborflags;
this.chordAround(my_neighbors,value,n);
}
function new_chordAround(my_neighbors, value, n) {
if (!(this.state === State.PLAYING)) {
return;
}
let increment = 1;
if (n != 0) {
increment = n;
}
let blackcounts = [];
let whitecounts = [];
let neighborflags = 0;
for (const [x0,y0] of my_neighbors) {
let mydot = this.__proto__.superchording.dots.get(x0 + "," + y0);
if (mydot < 0) {
blackcounts.push(mydot);
}
if (mydot > 0) {
whitecounts.push(mydot);
}
if (this.flags[y0][x0]) {
neighborflags += 1;
}
}
debugger;
if (n == 0 && blackcounts.length > 0 && whitecounts.length > 0) {
return;
}
console.log("da counts:");
console.log(whitecounts);
console.log(blackcounts);
console.log(this.__proto__.superchording)
if (n == 0 && whitecounts.length > 0) {
this.__proto__.superchording = this.negateDots();
}
console.log("gonna be adding to:")
console.log(this.__proto__.superchording)
this.__proto__.superchording.sum += increment*value;
for (const [x0,y0] of my_neighbors) {
let coords = [x0,y0]
if (!(this.map.labels[y0][x0] === null && !this.flags[y0][x0])) {
continue;
}
let current_dot = this.__proto__.superchording.dots.get(x0 + "," + y0);
if (current_dot === undefined) {
current_dot = 0;
}
this.__proto__.superchording.dots.set(x0 + "," + y0, current_dot+increment);
}
this.refreshMana();
this.refreshChording();
if (n == 0) {
this.resolveWhite();
}
}
function new_chordGlobal() {
let my_neighbors = [];
for (x=0; x<this.width; x++) {
for (y=0; y<this.height; y++) {
my_neighbors.push([x,y])
}
}
let neighborflags = my_neighbors.filter(([x0,y0])=>(this.flags[y0][x0])).length;
let value = this.numMines - neighborflags;
if (this.__proto__.superchording.advanced) {
this.chordAround(my_neighbors,value,1); // TODO - right click to subtract
} else {
this.chordAround(my_neighbors,value,0);
}
}
function new_refreshChording() {
for (const [coords, value] of this.__proto__.superchording.dots.entries()) {
let [x0,y0] = coords.split(",").map(Number);
if (value < -1) {
this.cells[y0][x0].className = "cell unknown label-low-minus";
}
if (value === -1) {
this.cells[y0][x0].className = "cell unknown label-minus";
}
if (value === 0) {
this.cells[y0][x0].className = "cell unknown";
}
if (value === 1) {
this.cells[y0][x0].className = "cell unknown label-plus";
}
if (value > 1) {
this.cells[y0][x0].className = "cell unknown label-high-plus";
}
}
}
function negateDots() {
console.log("NEGATE!");
let res = {
sum: -this.__proto__.superchording.sum,
dots: new Map()
}
for (const [coords, value] of this.__proto__.superchording.dots.entries()) {
res.dots.set(coords, -value);
}
return res;
}
function resolveWhite() {
if (this.__proto__.superchording.sum < 0) {
this.__proto__.superchording = this.negateDots();
}
let whitecounts = [];
let blackcounts = [];
console.log(this.__proto__.superchording.dots);
for (const [coords, value] of this.__proto__.superchording.dots.entries()) {
let [x0,y0] = coords.split(",").map(Number);
if (value < 0) {
blackcounts.push(value);
}
if (value > 0) {
whitecounts.push(value)
}
}
if (this.__proto__.superchording.sum == 0 && blackcounts.length == 0 && whitecounts.length > 0) {
this.__proto__.superchording = this.negateDots();
return this.resolveWhite();
}
blackcounts.sort((a,b)=>(b-a))
whitecounts.sort((a,b)=>(a-b))
console.log("counts:");
console.log(whitecounts);
console.log(blackcounts);
let resolved = 0;
let is_in = {}
while (true) {
if (whitecounts.length > 0) {
let biggest_white = whitecounts.pop()
let biggest_sum_without = whitecounts.reduce((a,b)=>a+b,0)
let smallest_sum_with = blackcounts.reduce((a,b)=>a+b,0) + biggest_white;
if (biggest_sum_without < this.__proto__.superchording.sum) {
// then it must be in
resolved += 1;
is_in[biggest_white] = true;
this.__proto__.superchording.sum -= biggest_white;
continue;
}
if (smallest_sum_with > this.__proto__.superchording.sum) {
// then it must be out
resolved += 1;
is_in[biggest_white] = false;
continue;
}
whitecounts.push(biggest_white);
}
if (blackcounts.length > 0) {
let smallest_black = blackcounts.pop();
let biggest_sum_with = whitecounts.reduce((a,b)=>a+b,0) + smallest_black;
let smallest_sum_without = blackcounts.reduce((a,b)=>a+b,0);
if (biggest_sum_with < this.__proto__.superchording.sum) {
// then it must be out
resolved += 1;
is_in[smallest_black] = false;
continue;
}
if (smallest_sum_without > this.__proto__.superchording.sum) {
// then it must be in
resolved += 1;
is_in[smallest_black] = true;
this.__proto__.superchording.sum -= smallest_black;
continue;
}
blackcounts.push(smallest_black)
}
// no `continue` was reached so no more deductions can be made
break;
}
for (const [coords, value] of this.__proto__.superchording.dots.entries()) {
let [x0,y0] = coords.split(",").map(Number);
if (is_in[value] == true) {
this.toggleFlag(x0,y0);
}
if (is_in[value] == false) {
this.reveal(x0, y0, true);
}
}
/*
if (this.__proto__.superchording.sum == whitecount) {
for (const [coords, value] of this.__proto__.superchording.dots.entries()) {
let [x0,y0] = coords.split(",").map(Number);
if (value < 0) {
this.reveal(x0, y0, true);
}
if (value > 0) {
this.toggleFlag(x0,y0);
}
}
this.resetSuperchording();
}
if (this.__proto__.superchording.sum == -blackcount) {
for (const [coords, value] of this.__proto__.superchording.dots.entries()) {
let [x0,y0] = coords.split(",").map(Number);
if (value > 0) {
this.reveal(x0, y0, true);
}
if (value < 0) {
this.toggleFlag(x0,y0);
}
}
this.resetSuperchording();
}
*/
if (resolved > 0) {
this.resetSuperchording();
}
}
function resetSuperchording() {
console.log("RESET");
this.__proto__.superchording = {
sum: 0,
dots: new Map(),
advanced: false
}
document.getElementById("game").children[1].onclick = function() { game.chordGlobal() }
this.refreshMana();
this.refresh();
}
function refreshMana() {
let label = "Mana: ";
if (this.__proto__.superchording.advanced) {
label = "[ADVANCED] " + label;
}
document.getElementById("mana").innerHTML = label + this.__proto__.superchording.sum;
}
function makeManaDisplay() {
let a = document.createElement("div");
a.id = "mana";
document.getElementsByClassName("card-body")[0].appendChild(a);
}
(function() {
makeStyle();
makeManaDisplay();
Game.prototype.chordAround = new_chordAround;
Game.prototype.cellClick = new_cellClick;
Game.prototype.cellDblClick = new_cellDblClick;
Game.prototype.cellMouseDown = new_cellMouseDown;
Game.prototype.negateDots = negateDots;
Game.prototype.resolveWhite = resolveWhite;
Game.prototype.refreshMana = refreshMana;
Game.prototype.resetSuperchording = resetSuperchording;
Game.prototype.chordGlobal = new_chordGlobal;
Game.prototype.refreshChording = new_refreshChording;
Game.prototype.chordAroundCell = new_chordAroundCell;
Game.prototype.resetSuperchording();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment