Skip to content

Instantly share code, notes, and snippets.

@Dan-Q
Last active January 16, 2025 14:01
Show Gist options
  • Save Dan-Q/b5e4dbb45851b07042b6a57ebe1005a7 to your computer and use it in GitHub Desktop.
Save Dan-Q/b5e4dbb45851b07042b6a57ebe1005a7 to your computer and use it in GitHub Desktop.
Userscript to streamline Jigidi solving

Jigidi "Magic Stripes" Userscript Helper

( by Dan Q / gmd7z3jyedson2vpgiav )

Installation

  1. Install a userscript manager into your browser (it's just a browser plugin!). I use Violentmonkey. A userscript manager makes it easier to run custom Javascript on specific web pages.
  2. Install the userscript below into your userscript manager. Once your userscript manager's installed, simply going to that link will probably prompt you to install it.

Usage

  1. You'll need a Jigidi account. Make a throwaway one in case it gets banned. The Jigidi account is required because this script has to refresh the page a few times and not lose your jigsaw progress; progress gets saved in a Jigidi account!
  2. Go to the jigsaw you want to solve. You'll see a new "Magic Stripes" section is added by the userscript in the sidebar. By default, it's "off" (0). Changing the number and pressing "Go" tells it which column you want help solving. "+1 and Go" increments the number by one.
  3. Press"+1 and Go". The page will refresh and the first column's pieces will be highlighted and numbered with their positions; all the other column's pieces will fade out so they don't get in your way.
  4. Solve the first column.
  5. Press "+1 and Go" again and the page will refresh (this is why you need a Jigidi account: to keep the first column saved!). Now you're working on the second column. The previous column's pieces stay highlighted, but in a lighter colour (this aids matching with the second column's pieces, so you can link them up).
  6. Repeat for every other column.
// ==UserScript==
// @name Jigidi Magic Stripes
// @namespace me.danq.com.jigidi.magicstripes
// @match https://www.jigidi.com/solve/*
// @grant GM_getValue
// @grant GM_setValue
// @version 1.0
// @author Dan Q <https://danq.me>
// @description 23/03/2023, 14:32:30
// ==/UserScript==
/*
RainbowVis-JS ()Eclipse Public License - v 1.0) | https://github.com/anomal/RainbowVis-JS/blob/master/rainbowvis.js
*/
function Rainbow(){"use strict";var gradients=null;var minNum=0;var maxNum=100;var colours=['ff0000','ffff00','00ff00','0000ff'];setColours(colours);function setColours(spectrum){if(spectrum.length<2){throw new Error('Rainbow must have two or more colours.')}else{var increment=(maxNum-minNum)/(spectrum.length-1);var firstGradient=new ColourGradient();firstGradient.setGradient(spectrum[0],spectrum[1]);firstGradient.setNumberRange(minNum,minNum+increment);gradients=[firstGradient];for(var i=1;i<spectrum.length-1;i++){var colourGradient=new ColourGradient();colourGradient.setGradient(spectrum[i],spectrum[i+1]);colourGradient.setNumberRange(minNum+increment*i,minNum+increment*(i+1));gradients[i]=colourGradient}
colours=spectrum}}
this.setSpectrum=function(){setColours(arguments);return this}
this.setSpectrumByArray=function(array){setColours(array);return this}
this.colourAt=function(number){if(isNaN(number)){throw new TypeError(number+' is not a number')}else if(gradients.length===1){return gradients[0].colourAt(number)}else{var segment=(maxNum-minNum)/(gradients.length);var index=Math.min(Math.floor((Math.max(number,minNum)-minNum)/segment),gradients.length-1);return gradients[index].colourAt(number)}}
this.colorAt=this.colourAt;this.setNumberRange=function(minNumber,maxNumber){if(maxNumber>minNumber){minNum=minNumber;maxNum=maxNumber;setColours(colours)}else{throw new RangeError('maxNumber ('+maxNumber+') is not greater than minNumber ('+minNumber+')')}
return this}}
function ColourGradient(){"use strict";var startColour='ff0000';var endColour='0000ff';var minNum=0;var maxNum=100;this.setGradient=function(colourStart,colourEnd){startColour=getHexColour(colourStart);endColour=getHexColour(colourEnd)}
this.setNumberRange=function(minNumber,maxNumber){if(maxNumber>minNumber){minNum=minNumber;maxNum=maxNumber}else{throw new RangeError('maxNumber ('+maxNumber+') is not greater than minNumber ('+minNumber+')')}}
this.colourAt=function(number){return calcHex(number,startColour.substring(0,2),endColour.substring(0,2))+calcHex(number,startColour.substring(2,4),endColour.substring(2,4))+calcHex(number,startColour.substring(4,6),endColour.substring(4,6))}
function calcHex(number,channelStart_Base16,channelEnd_Base16){var num=number;if(num<minNum){num=minNum}
if(num>maxNum){num=maxNum}
var numRange=maxNum-minNum;var cStart_Base10=parseInt(channelStart_Base16,16);var cEnd_Base10=parseInt(channelEnd_Base16,16);var cPerUnit=(cEnd_Base10-cStart_Base10)/numRange;var c_Base10=Math.round(cPerUnit*(num-minNum)+cStart_Base10);return formatHex(c_Base10.toString(16))}
function formatHex(hex){if(hex.length===1){return'0'+hex}else{return hex}}
function isHexColour(string){var regex=/^#?[0-9a-fA-F]{6}$/i;return regex.test(string)}
function getHexColour(string){if(isHexColour(string)){return string.substring(string.length-6,string.length)}else{var name=string.toLowerCase();if(colourNames.hasOwnProperty(name)){return colourNames[name]}
throw new Error(string+' is not a valid colour.')}}
var colourNames={aliceblue:"F0F8FF",antiquewhite:"FAEBD7",aqua:"00FFFF",aquamarine:"7FFFD4",azure:"F0FFFF",beige:"F5F5DC",bisque:"FFE4C4",black:"000000",blanchedalmond:"FFEBCD",blue:"0000FF",blueviolet:"8A2BE2",brown:"A52A2A",burlywood:"DEB887",cadetblue:"5F9EA0",chartreuse:"7FFF00",chocolate:"D2691E",coral:"FF7F50",cornflowerblue:"6495ED",cornsilk:"FFF8DC",crimson:"DC143C",cyan:"00FFFF",darkblue:"00008B",darkcyan:"008B8B",darkgoldenrod:"B8860B",darkgray:"A9A9A9",darkgreen:"006400",darkgrey:"A9A9A9",darkkhaki:"BDB76B",darkmagenta:"8B008B",darkolivegreen:"556B2F",darkorange:"FF8C00",darkorchid:"9932CC",darkred:"8B0000",darksalmon:"E9967A",darkseagreen:"8FBC8F",darkslateblue:"483D8B",darkslategray:"2F4F4F",darkslategrey:"2F4F4F",darkturquoise:"00CED1",darkviolet:"9400D3",deeppink:"FF1493",deepskyblue:"00BFFF",dimgray:"696969",dimgrey:"696969",dodgerblue:"1E90FF",firebrick:"B22222",floralwhite:"FFFAF0",forestgreen:"228B22",fuchsia:"FF00FF",gainsboro:"DCDCDC",ghostwhite:"F8F8FF",gold:"FFD700",goldenrod:"DAA520",gray:"808080",green:"008000",greenyellow:"ADFF2F",grey:"808080",honeydew:"F0FFF0",hotpink:"FF69B4",indianred:"CD5C5C",indigo:"4B0082",ivory:"FFFFF0",khaki:"F0E68C",lavender:"E6E6FA",lavenderblush:"FFF0F5",lawngreen:"7CFC00",lemonchiffon:"FFFACD",lightblue:"ADD8E6",lightcoral:"F08080",lightcyan:"E0FFFF",lightgoldenrodyellow:"FAFAD2",lightgray:"D3D3D3",lightgreen:"90EE90",lightgrey:"D3D3D3",lightpink:"FFB6C1",lightsalmon:"FFA07A",lightseagreen:"20B2AA",lightskyblue:"87CEFA",lightslategray:"778899",lightslategrey:"778899",lightsteelblue:"B0C4DE",lightyellow:"FFFFE0",lime:"00FF00",limegreen:"32CD32",linen:"FAF0E6",magenta:"FF00FF",maroon:"800000",mediumaquamarine:"66CDAA",mediumblue:"0000CD",mediumorchid:"BA55D3",mediumpurple:"9370DB",mediumseagreen:"3CB371",mediumslateblue:"7B68EE",mediumspringgreen:"00FA9A",mediumturquoise:"48D1CC",mediumvioletred:"C71585",midnightblue:"191970",mintcream:"F5FFFA",mistyrose:"FFE4E1",moccasin:"FFE4B5",navajowhite:"FFDEAD",navy:"000080",oldlace:"FDF5E6",olive:"808000",olivedrab:"6B8E23",orange:"FFA500",orangered:"FF4500",orchid:"DA70D6",palegoldenrod:"EEE8AA",palegreen:"98FB98",paleturquoise:"AFEEEE",palevioletred:"DB7093",papayawhip:"FFEFD5",peachpuff:"FFDAB9",peru:"CD853F",pink:"FFC0CB",plum:"DDA0DD",powderblue:"B0E0E6",purple:"800080",red:"FF0000",rosybrown:"BC8F8F",royalblue:"4169E1",saddlebrown:"8B4513",salmon:"FA8072",sandybrown:"F4A460",seagreen:"2E8B57",seashell:"FFF5EE",sienna:"A0522D",silver:"C0C0C0",skyblue:"87CEEB",slateblue:"6A5ACD",slategray:"708090",slategrey:"708090",snow:"FFFAFA",springgreen:"00FF7F",steelblue:"4682B4",tan:"D2B48C",teal:"008080",thistle:"D8BFD8",tomato:"FF6347",turquoise:"40E0D0",violet:"EE82EE",wheat:"F5DEB3",white:"FFFFFF",whitesmoke:"F5F5F5",yellow:"FFFF00",yellowgreen:"9ACD32"}}
// Are we logged-in?
const loggedIn = !document.querySelector('account-status.guest');
console.log(`Magic Stripes: loggedIn=${loggedIn ? 'true' : 'false'}`);
// Prepare Magic Stripes UI
const jigidiMagicStripes = document.createElement('div');
jigidiMagicStripes.id = 'jigidi-magic-stripes';
// Inject Magic Stripes UI
const creatorElem = document.getElementById('info-creator');
creatorElem.before(jigidiMagicStripes);
if(!loggedIn){
// Magic Stripes UI only works if logged in (we need Jigidi's state saving through page refreshes)
jigidiMagicStripes.innerHTML = '<p><strong>Magic Stripes</strong><br>Disabled. <a href="https://www.jigidi.com/login.php">Sign in to Jigidi</a> to enable.</p>';
} else {
// Logged in: jigsaw ID and settings for this jigsaw, enumerate lengths of jigsaw dimensions, and update Magic Stripes UI
const jigsawId = window.location.href.match(/solve\/(\w+)\//)[1];
const magicStripesSettings = GM_getValue(`magicStripesSettings_${jigsawId}`, { col: 0 });
const jDimensions = creatorElem.innerText.match(/(\d+)×(\d+)/);
const jCols = parseInt(jDimensions[1]);
const jRows = parseInt(jDimensions[2]);
console.log(`Magic Stripes: jCols=${jCols} jRows=${jRows}`);
jigidiMagicStripes.innerHTML = `
<p>
<strong>Magic Stripes</strong><br>
<label for="magicStripesCol">Help with column? (0 to disable)</label><br>
<input type="number" id="magicStripesCol" value="${magicStripesSettings.col}" min="0" max="${jCols}" style="width: 4em;">
<button id="magicStripesGo">Go</button>
<button id="magicStripesPlusOne">+1 and Go</button>
</p>
`;
const magicStripesCol = document.getElementById('magicStripesCol');
const magicStripesGo = document.getElementById('magicStripesGo');
magicStripesGo.addEventListener('click', ()=>{
magicStripesSettings.col = parseInt(magicStripesCol.value);
GM_setValue(`magicStripesSettings_${jigsawId}`, magicStripesSettings);
window.location.reload();
});
document.getElementById('magicStripesPlusOne').addEventListener('click', ()=>{
magicStripesCol.value = (parseInt(magicStripesCol.value) + 1) % (jCols + 1);
magicStripesGo.dispatchEvent(new Event('click'));
});
// Generate spectrum to use:
var rainbow = new Rainbow();
let jColors = [];
rainbow.setNumberRange(1, jRows);
rainbow.setSpectrum('red', 'violet');
for(var i = 1; i <= jRows; i++) {
jColors.push(`#${rainbow.colourAt(i)}`);
}
let jC = 0;
const targetCol = parseInt(magicStripesSettings.col);
if(targetCol > 0) {
// Override putImageData with a manipulated version for THIS page load
CanvasRenderingContext2D.prototype.putImageData = function(imageData, dx, dy){
console.log('Magic Stripes: putImageData');
const targetCol = parseInt(magicStripesSettings.col);
const col = jC % jCols;
const row = Math.floor(jC / jCols);
if((col + 1) === targetCol) {
// Target column: color and number
this.fillStyle = jColors[row % jColors.length];
this.fillRect(-1000,-1000,2000,2000);
this.font = 'bold 14px sans-serif';
this.fillStyle = 'black';
this.fillText(`${row+1}`, -5, 0);
} else if ((col + 2) === targetCol) {
// Previous column: lightly color, don't number
this.fillStyle = jColors[row % jColors.length];
this.fillRect(-1000,-1000,2000,2000);
this.fillStyle = '#ffffffbb';
this.fillRect(-1000,-1000,2000,2000);
this.font = 'bold 14px sans-serif';
this.fillStyle = 'black';
this.fillText(`${row+1}`, -5, 0);
} else {
// Other columns: white-out
this.fillStyle = '#ffffffdd';
this.fillRect(-1000,-1000,2000,2000);
}
jC++;
}
}
}
@ba47-development
Copy link

@ngoclong19: no, actually its Firefox; I don't like Chrome very much. ;-) I ran the script with Violentmonkey, but finally detected my mistake:

I used the script in another language, not English. It works fine, after I switched back.
Thanks for your help.

@AxelFP
Copy link

AxelFP commented Dec 19, 2024

I had the same, took a while before I found the problem.
The script doesn't work for languages other than English on jigidi, remove the language abbreviation from the URL and it will work. E.g. https://www.jigidi.com/fr/therestoftheurl ==> https://www.jigidi.com/therestoftheurl

@ngoclong19
Copy link

@ba47-development, @AxelFP: You could add this line after the original @match line. The user script will work for languages other than English.
// @match https://www.jigidi.com/*/solve/*

@ElgorGc
Copy link

ElgorGc commented Dec 24, 2024

The 'Magic stripes' section is not shown with puzlle like this one https://www.jigidi.com/s/swm1hf/
Thanks for your help

@dieterv
Copy link

dieterv commented Jan 5, 2025

To show row numbers for the previous and target column, change line 100 and 109 from:
this.font = 'bold 14px sans-serif';
to:
this.font = 'bold 2rem sans-serif';

and change line 102 and 111 from:
this.fillText(`${row+1}`, -5, 0);
to:
this.fillText(`${row+1}`, dx+35, dy+45);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment