// ==UserScript== // @name Porko Solver // @namespace kol.interface.unfinished // @description Helps you play Porko optimally in the Kingdom of Loathing // @include http://*kingdomofloathing.com/choice.php* // @include http://*kingdomofloathing.com/spaaace.php* // @include http://127.0.0.1:*/choice.php* // @include http://127.0.0.1:*/spaaace.php* // @version 1.41 // @grant GM_getValue // @grant GM_setValue // @downloadURL https://update.greasyfork.icu/scripts/4204/Porko%20Solver.user.js // @updateURL https://update.greasyfork.icu/scripts/4204/Porko%20Solver.meta.js // ==/UserScript== //Version 1.41 // - add @grant, change GM_log to console.log //Version 1.4 // - added a repeat game option to replay multiple times //Version 1.3 // - changed top arrows so they point diagonally if appropriate for the first move //Version 1.21 // - fixed weird bug in FF4/5, where apparently it counts differently //Version 1.2 // - added a link to auto-select/play one unit (turn/3-plays) //Version 1.1 // - added colours to show deterministic and unreachable areas function doPage(root) { if (root) { var snap = document.evaluate( '//p[contains(.,"You hand Juliedriel your isotope.")]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (!snap.singleNodeValue) { GM_setValue('porkorepeat',Number(GM_getValue('porkorepeat',1))-1); } else GM_setValue('porkorepeat','0'); addDoAll3(snap.singleNodeValue,makeChoice(solveGrid(makeGrid(root)),root)); } else { GM_setValue('repeatgame',0); GM_setValue('repeatinggame',0); GM_setValue('porkorepeat',0); } } var grids = []; function addDoAll3(snap,maxahref) { if (snap) { if (GM_getValue('repeatinggame',0)>0 && maxahref) { GM_setValue('porkorepeat','3'); window.location.pathname = maxahref; } else { var span = document.createElement('span'); span.setAttribute('style','font-size:10px;'); span.appendChild(document.createTextNode('\u00A0\u00A0')); var b = document.createElement('a'); b.setAttribute('href','#'); b.appendChild(document.createTextNode('Auto-play this game')); b.addEventListener('click',doAgain,false); if (maxahref) b.setAttribute('href',maxahref); span.appendChild(b); snap.appendChild(span); } } else repeatit(); } function doAgain() { GM_setValue('porkorepeat','3'); if (this.getAttribute('href')) { window.location.pathname = this.getAttribute('href'); } } function makeGrid(root) { var grid = []; var cell = 0; var row = 0; var started = false; var ts = document.evaluate('.//div',root,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0;i16) { cell = 0; row++; } } } showUnreachable(grid); return grid; } function solveGrid(grid) { var colors = ['LightYellow','PeachPuff','LightSalmon','Tomato']; var ming = []; var maxg = []; var p = 1; for (var j=0;j<17;j+=2) { grid[grid.length-2][j] = grid[grid.length-1][j]; ming[j] = grid[grid.length-2][j]; maxg[j] = grid[grid.length-2][j]; if (!grids[grid.length-2][j].style.backgroundColor) { grids[grid.length-2][j].setAttribute('title',grid[grid.length-2][j]); grids[grid.length-2][j].style.backgroundColor = colors[ming[j]]; grids[grid.length-2][j].innerHTML = '↓'; } } grid[-1] = []; for (var i=grid.length-3;i>=-1;i--) { for (var j=p;j<17;j+=2) { var gl = Number((j>0) ? grid[i+1][j-1] : grid[i+1][j+1]); var gr = Number((j<16) ? grid[i+1][j+1] : grid[i+1][j-1]); switch(Number(grid[i+1][j])) { case 1: grid[i][j] = gr; ming[j] = Number((j<16) ? ming[j+1] : ming[j-1]); maxg[j] = Number((j<16) ? maxg[j+1] : maxg[j-1]); if (i>=0 && !grids[i][j].style.backgroundColor) grids[i][j].innerHTML = (j<16) ? '↘' : '↙'; break; case 2: grid[i][j] = gl; ming[j] = Number((j>0) ? ming[j-1] : ming[j+1]); maxg[j] = Number((j>0) ? maxg[j-1] : maxg[j+1]); if (i>=0 && !grids[i][j].style.backgroundColor) grids[i][j].innerHTML = (j>0) ? '↙' : '↘'; break; case 3: grid[i][j] = (gl + gr)/2.0; ming[j] = Math.min(Number((j>0) ? ming[j-1] : ming[j+1]),Number((j<16) ? ming[j+1] : ming[j-1])); maxg[j] = Math.max(Number((j>0) ? maxg[j-1] : maxg[j+1]),Number((j<16) ? maxg[j+1] : maxg[j-1])); if (i>=0 && !grids[i][j].style.backgroundColor) grids[i][j].innerHTML = (j==0) ? '↘' : ((j==16) ? '↙' : '.'); break; default: console.log('error! '+grid[i][j]); } if (i>=0 && !grids[i][j].style.backgroundColor) { if (ming[j]==maxg[j]) { grids[i][j].setAttribute('title','Payout='+grid[i][j]); grids[i][j].style.backgroundColor = colors[ming[j]]; //grids[i][j].style.opacity = '0.8'; } else grids[i][j].setAttribute('title','E(payout)='+grid[i][j]+', min='+ming[j]+', max='+maxg[j]); } } p = 1-p; } return {e:grid,m:ming,x:maxg}; } function showUnreachable(grid) { var p = 0; var reach = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]; for (var i=-1;i0) reach2[j-1] = 1; else reach2[j+1] = 1; break; case 3: if (j>0) reach2[j-1] = 1; if (j<16) reach2[j+1] = 1; break; default: console.log('error! '+grid[i][j]); } } } p = 1-p; reach = reach2; for (var j=p;j<17;j+=2) { if (reach[j]==0) { grids[i+1][j].style.backgroundColor = '#EEEEEE'; grids[i+1][j].setAttribute('title','Unreachable'); } } } } function makeChoice(grid,root) { var max = 0.0; var maxa; for (var i=0;i<17;i+=2) { if (grid.e[-1][i]>max) max = grid.e[-1][i]; } var ts = document.evaluate('.//div[@class="start"]',root,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0;i0) window.location.pathname = maxa.getAttribute('href'); return maxa.getAttribute('href'); } } function playAgain() { var s = document.getElementById('playporkoagain'); if (s) { var times = s.options[s.options.selectedIndex].value; if (times=='Forever') { times = 99999999; // not quite forever, but close enough } GM_setValue('repeatgame',(times-1)); var x = document.getElementById('playporkolink'); if (x) { window.location.pathname = x.getAttribute('href'); GM_setValue('repeatinggame',1); } else { GM_setValue('repeatgame',0); GM_setValue('repeatinggame',0); console.log('lost sync, giving up'); } } } function repeatit() { var doit = document.evaluate( '//a[contains(.,"Care to play again?")]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE,null); if (doit.singleNodeValue) { var r = GM_getValue('repeatgame',0); if (r==0) { GM_setValue('repeatinggame',0); var b = document.createElement('input'); b.setAttribute('type','button'); b.setAttribute('value','Auto-Repeat Play'); var s = document.createElement('select'); s.setAttribute('id','playporkoagain'); b.addEventListener('click',playAgain,false); for (var i=0;i<30;i++) { var option = document.createElement('option'); option.appendChild(document.createTextNode(String(i+1))); option.setAttribute('value',i+1); s.appendChild(option); } var option = document.createElement('option'); option.appendChild(document.createTextNode('Forever')); option.setAttribute('value','Forever'); option.setAttribute('title','Repeat until you run out of turns or the Transpondent effect.'); s.appendChild(option); var p = doit.singleNodeValue.parentNode; doit.singleNodeValue.setAttribute('id','playporkolink'); var c = document.createElement('p'); c.appendChild(b); c.appendChild(document.createTextNode('\u00A0\u00A0')); c.appendChild(s); p.appendChild(c); } else { GM_setValue('repeatgame',(r-1)); GM_setValue('repeatinggame',1); window.location.pathname = doit.singleNodeValue.getAttribute('href'); } } } doPage(document.getElementById('porko'));