NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name TheGuardian Crossword checker // @version 3.4 // @description Check solution! - Check This -> Enter, Empty cell -> shift, Numbers -> Column/Row number, Space -> Change direction // @author Denis Papec // @author Jason Woods // @match https://www.theguardian.com/crosswords/quick/* // @grant none // @license MIT // @require http://code.jquery.com/jquery-3.1.1.min.js // @require https://raw.githubusercontent.com/csudcy/jquery.fireworks/master/jquery.fireworks.js // @require https://raw.githubusercontent.com/sindresorhus/screenfull.js/gh-pages/src/screenfull.js // ==/UserScript== // ==OpenUserJS== // @author denis.papec // @author jason.woods // ==/OpenUserJS== (function(run) { var interval = setInterval(function() { var lastControl = $('div.crossword__controls__grid button').last(); if (lastControl.text() == 'Clear all') { clearInterval(interval); run(); } }, 1000); })(function() { 'use strict'; var lastControl = $('div.crossword__controls__grid button').last(), fullscreenControl = lastControl.clone().prop('id', 'fullscreen').removeClass('button--secondary'), randomControl = lastControl.clone().prop('id', 'random').removeClass('button--secondary'), overlay = $('<div id="overlay"> </div>'), crosswordDiv = $('div.js-crossword'), crosswordControls = $('.crossword__controls'), checkThisSelector = "button:contains('Check this')", checkAllSelector = "button:contains('Check all')", highlightedCellSelector = '.crossword__cell--highlighted', focusedCellSelector = '.crossword__cell-text--focussed', confirmCheckAllSelector = "button:contains('Confirm check all')", clueNumbers = $("div.crossword__clue__number"), crosswordCellText = $('.crossword__grid text.crossword__cell-text'), clickEvent = new Event('click'), bruteForceMessage = $('<div class="crossword__clues"><div class="crossword__clue"></div></div>'), lastAttemptMessage = $('<div class="crossword__clues"><div class="crossword__clue"></div></div>'), harlemSound = false, easterEggs = [ doTheFireworks, //doTheHarlemShake, ]; var getRandomCrossword = function() { let crossNum = []; for (var storageKey in window.localStorage){ if (storageKey.includes('crosswords.crosswords/quick/')) { crossNum.push(storageKey.match(/\d+/g)[0]); } } let maxCrossword = Math.max(...crossNum.map(Number)), minCrossword = 9093, newCrossword = Math.floor(Math.random() * (maxCrossword - minCrossword)) + minCrossword; if (window.localStorage.getItem('crosswords.crosswords/quick/'+newCrossword) !== null) { newCrossword = getRandomCrossword(); } return newCrossword; } lastControl.after(randomControl.text('Random Crossword')); lastControl.after(fullscreenControl.text('Fullscreen')); randomControl.on('click', () => { window.location.href = 'https://www.theguardian.com/crosswords/quick/'+getRandomCrossword(); }); fullscreenControl.on('click', () => { if (screenfull.enabled) { screenfull.request(crosswordDiv[0]); } }); crosswordDiv.css({'margin': 'auto', 'width': '100%', 'height': '100%', 'background-color': '#fff', 'padding': '20px'}); var numberMap = [], direction = [], letterMap = [], lastFocus = null, bruteForceMap = {}, cheatCodes = { cruciverbalist: 'getNumberStartedQuickCrosswords()' }; var clueFilter = function(clue) { return clueNumbers.filter(function() { return $(this).text() === clue; }); }; var getDirection = function(clue) { if (direction.includes(clue)) { direction = direction.filter(function(items) { return items !== clue }); return 0; } direction.push(clue); return 1; }; var clickButton = function(button) { crosswordControls.find(button).click(); }; var getNumberStartedQuickCrosswords = function() { var i = 0; for (var storageKey in window.localStorage){ if (storageKey.includes('crosswords.crosswords/quick/')) { i++; } } alert('Total number of resolved crosswords: '+i); } var cheatCodeDetector = function(newLetter) { var foundTrail = false; letterMap.push(newLetter); for (var cheat in cheatCodes) { if (!cheat.includes(letterMap.join(''))) { continue; } foundTrail = true; if (cheat !== letterMap.join('')) { continue; } eval(cheatCodes[cheat]); } if (!foundTrail) { letterMap = []; letterMap.push(newLetter); } }; var checkBruteForce = function(activeCell, didType) { var cellX = activeCell.attr('x'), cellY = activeCell.attr('y'), letter = activeCell.text(); if (!didType && !letter) { // clicked empty cell bruteForceMessage.remove(); return; } if (!bruteForceMap[cellX]) { bruteForceMap[cellX] = {}; } if (!bruteForceMap[cellX][cellY]) { bruteForceMap[cellX][cellY] = []; } if (didType && bruteForceMap[cellX][cellY].indexOf(letter) === -1) { bruteForceMap[cellX][cellY].push(letter); } if (bruteForceMap[cellX][cellY].length > 5) { var result = ''; 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').forEach(function(entry) { if (result) { result += ' / '; } if (bruteForceMap[cellX][cellY].indexOf(entry) === -1) { result += '<span style="opacity: 0.5">' + entry + '</span>'; } else { result += entry; } }); bruteForceMessage.find('.crossword__clue').html('<b>Brute forced so far:</b> ' + result); if (bruteForceMessage.parent().length == 0) { $('.crossword__clues--wrapper').append(bruteForceMessage); } } else { bruteForceMessage.remove(); } }; var getCurrentWord = function() { var cells = $('.crossword__cell--highlighted ~ .crossword__cell-text'), result = ''; cells.each(function(index, cell) { var letter = $(cell).text(); if (result) { result += ' '; } if (letter) { result += letter; } else { result += '_'; } }); return result; }; crosswordDiv.click(function(event) { lastAttemptMessage.remove(); var activeCell = $(focusedCellSelector); if (activeCell.length === 1) { checkBruteForce(activeCell, false); } }); crosswordDiv.keyup(function(event) { if (event.keyCode === 13) { // enter var lastAttempt = getCurrentWord(); clickButton(checkThisSelector); window.requestAnimationFrame(function () { var lastAttemptResult = getCurrentWord(); if (lastAttemptResult != lastAttempt) { lastAttemptMessage.find('.crossword__clue').html('<b>Last attempt:</b> ' + lastAttempt); if (lastAttemptMessage.parent().length == 0) { $('.crossword__clues--wrapper').append(lastAttemptMessage); } return; } lastAttemptMessage.remove(); if (isCrosswordFull()) { clickButton(checkAllSelector); window.requestAnimationFrame(function () { clickButton(confirmCheckAllSelector); window.requestAnimationFrame(function () { if (isCrosswordFull()) { if (screenfull.enabled) { screenfull.exit(); } window.requestAnimationFrame(function () { document.body.scrollIntoView(); window.requestAnimationFrame(function () { //let egg = easterEggs[Math.floor(Math.random() * easterEggs.length)]; //eval(egg); doTheFireworks(); }); }); } }); }); } }); } if (event.keyCode === 16) { // shift var cell = $(highlightedCellSelector).parent().children('text').filter(':empty').first(); if (cell.length > 0) { cell.parent()[0].dispatchEvent(clickEvent); } } if (event.keyCode === 27) { // escape overlay.css('display', 'none'); } if (event.keyCode === 32) { // space $(focusedCellSelector).parent()[0].dispatchEvent(clickEvent); } if (lastFocus.length > 0) { checkBruteForce(lastFocus, true); } if (/[a-zA-Z]/i.test(event.key)) { cheatCodeDetector(event.key); } }); crosswordDiv.keydown(function(event) { if (/[0-9]/i.test(event.key)) { event.preventDefault(); numberMap.push(event.key); let elements = clueFilter(numberMap.join('')); if (elements.length == 0) { numberMap = [event.key]; elements = clueFilter(event.key); } elements.first().click(); } lastFocus = $(focusedCellSelector); }); overlay.keyup(closeOverlay); $(document).keyup(closeOverlay); var closeOverlay = function(event) { if (event.keyCode === 27) { // escape overlay.css('display', 'none'); } }; var isCrosswordFull = function (){ return crosswordCellText.filter(':empty').length == 0; }; var doTheFireworks = function () { overlay.css({ 'position': 'fixed', 'top': '0', 'left': '0', 'width': '100%', 'height': '100%', 'background-color': '#000', 'filter': 'alpha(opacity=80)', '-moz-opacity': '0.8', '-khtml-opacity': '0.8', 'opacity': '0.8', 'z-index': '10000' }); overlay.appendTo(document.body) overlay.fireworks(); }; var doingTheHarlemShake = false; var endTheHarlemShake = function () { doingTheHarlemShake = false; }; var doTheHarlemShake = function () { if (doingTheHarlemShake) { return; } doingTheHarlemShake = true; (function () { function c() { var e = document.createElement("link"); e.setAttribute("type", "text/css"); e.setAttribute("rel", "stylesheet"); e.setAttribute("href", f); e.setAttribute("class", l); document.body.appendChild(e) } function h() { var e = document.getElementsByClassName(l); for (var t = 0; t < e.length; t++) { document.body.removeChild(e[t]) } } function p() { var e = document.createElement("div"); e.setAttribute("class", a); document.body.appendChild(e); setTimeout(function () { document.body.removeChild(e) }, 100) } function d(e) { return { height: e.offsetHeight, width: e.offsetWidth } } function v(i) { var s = d(i); return s.height > e && s.height < n && s.width > t && s.width < r } function m(e) { var t = e; var n = 0; while ( !! t) { n += t.offsetTop; t = t.offsetParent } return n } function g() { var e = document.documentElement; if ( !! window.innerWidth) { return window.innerHeight } else if (e && !isNaN(e.clientHeight)) { return e.clientHeight } return 0 } function y() { if (window.pageYOffset) { return window.pageYOffset } return Math.max(document.documentElement.scrollTop, document.body.scrollTop) } function E(e) { var t = m(e); return t >= w && t <= b + w } function S() { if (harlemSound) { S_sound(); } else { S_nosound(); } } function S_nosound() { x(k); setTimeout(function () { N(); p(); for (var e = 0; e < O.length; e++) { T(O[e]) } }, 10000); setTimeout(function () { N(); h(); endTheHarlemShake(); }, 30000); } function S_sound() { var e = document.createElement("audio"); e.setAttribute("class", l); e.src = i; e.loop = false; e.addEventListener("canplay", function () { setTimeout(function () { x(k) }, 500); setTimeout(function () { N(); p(); for (var e = 0; e < O.length; e++) { T(O[e]) } }, 15500) }, true); e.addEventListener("ended", function () { N(); h(); endTheHarlemShake(); }, true); e.innerHTML = " <p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p> <p>"; document.body.appendChild(e); e.play() } function x(e) { e.className += " " + s + " " + o } function T(e) { e.className += " " + s + " " + u[Math.floor(Math.random() * u.length)] } function N() { var e = document.getElementsByClassName(s); var t = new RegExp("\\b" + s + "\\b"); for (var n = 0; n < e.length;) { e[n].className = e[n].className.replace(t, "") } } var e = 30; var t = 30; var n = 350; var r = 350; var i = "https://s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.mp3"; var s = "mw-harlem_shake_me"; var o = "im_first"; var u = ["im_drunk", "im_baked", "im_trippin", "im_blown"]; var a = "mw-strobe_light"; var f = "https://s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css"; var l = "mw_added_css"; var b = g(); var w = y(); var C = document.getElementsByTagName("*"); var k = null, kpool = document.getElementsByClassName('new-header__logo'); for (var L = 0; L < kpool.length; L++) { var A = kpool[L]; if (v(A)) { if (E(A)) { k = A; break } } } if (A === null) { console.warn("Could not find a node of the right size. Please try a different page."); return } c(); S(); var O = []; for (var L = 0; L < C.length; L++) { var A = C[L]; if (v(A)) { O.push(A) } } })(); }; });