Skip to content

Instantly share code, notes, and snippets.

@Dan-Q
Last active April 29, 2024 08:34
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • 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++;
}
}
}
@ngoclong19
Copy link

ngoclong19 commented Jun 10, 2023

May I suggest increase the font size to 2rem from 14px, and move the text position to (0, 0) from (-5, 0).
It seems that the number is not shown up currently.

@AxelFP
Copy link

AxelFP commented Jun 11, 2023

May I suggest increase the font size to 2rem from 14px, and move the text position to (100, 100) from (-5, 0). It seems that the number is not shown up currently.
I also saw no numbers, but this does the trick indeed.

Thanks @Dan-Q and @ngoclong19, I really hate solving those Jigidi puzzles!

@f-o
Copy link

f-o commented Aug 28, 2023

It seems that the number is not shown up currently.

I can't believe I actually solved 3x 1h puzzles, without the edits from you.
No numbers showed up, and I was getting annoyed that the colors where too similar.

Thank you for this script, it's been awesome so far!

@binghamjc
Copy link

I changed lines 100 and 109 from
this.font = 'bold 14px sans-serif';
to
this.font = 'bold 2rem sans-serif';
And lines 102 and 111 from
this.fillText(${row+1}, -5, 0);
first to
this.fillText(${row+1}, 0, 0);
then to
this.fillText(${row+1}, 100, 100);
None of these changes caused any numbers to appear on the puzzle pieces.

@f-o
Copy link

f-o commented Jan 28, 2024

I was moving browsers a little while ago, and somehow lost my Userscripts in the process.
Because of this, I decided to now finally make some backups, starting with this little gem (which I am using a lot for Geocaching!).

I've made some changes to the script.
Above are some of the mentions, but I also switched the colours up a bit, to make them even more distinct from each other.

Below is a gist of my version. All rights reserved to Dan Q, of course.
Just figured other people might find this useful.

https://gist.github.com/f-o/1bf2dd8a3364d51c5a666119eb334a9b

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