- // ==UserScript==
- // @name BvS WK Sync
- // @namespace BvS
- // @version 1.3
- // @history 1.3 New domain - animecubedgaming.com - Channel28
- // @history 1.2 Now https compatible (Updated by Channel28)
- // @history 1.1 Added grant permissions (Updated by Channel28)
- // @history 1.0 Initial Release
- // @description Attempts to solve World Kaiju sync.
- // @include http*://*animecubed.com/billy/bvs/worldkaiju-group.html
- // @include http*://*animecubedgaming.com/billy/bvs/worldkaiju-group.html
- // @licence MIT; http://www.opensource.org/licenses/mit-license.php
- // @copyright 2010, Daniel Karlsson
- // @grant GM_log
- // ==/UserScript==
-
- const TIMELIMIT = 5000; // ms
-
- var options = document.evaluate("//form[@name='groupcheck']/select[@name='c1']/option",
- document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
-
- var colours = [];
- for (var i = 0; i < options.snapshotLength; i++) {
- var value = parseInt(options.snapshotItem(i).value);
- var colour = options.snapshotItem(i).textContent;
- colours[value] = colour;
- }
-
- function find(val, arr)
- {
- for (var i in arr)
- if (arr[i] == val)
- return i;
- return -1;
- }
- function print(arr)
- {
- var xarr = [];
- for (var i in arr)
- xarr.push(colours[arr[i]]);
- return xarr.join(",");
- }
-
- function Mastermind(pegs, colours)
- {
- var my = this;
-
- my.colours = colours;
- my.pegs = pegs;
- my.prevGuesses = [];
-
- // Create array of all possible combinations
- my.combinations = [];
- for (var i = 0; i < Math.pow(my.colours, my.pegs); i++) {
- var n = i;
- var comb = [];
- for (var p = 0; p < my.pegs; p++) {
- comb.push(n % my.colours);
- n = Math.floor(n / my.colours);
- }
- my.combinations.push(comb);
- }
-
- my.appendGuess = function(g, s) {
- my.prevGuesses.push({guess: g, score: s});
- }
-
- // Determine score as [<correct colour, correct position>, <correct colour, wrong position>]
- my.score = function(guess, board) {
- var boardColours = [];
- var guessColours = [];
-
- for (var i = 0; i < my.colours; i++) {
- boardColours.push(0);
- guessColours.push(0);
- }
-
- var correctPosition = 0;
- for (var i = 0; i < my.pegs; i++) {
- if (board[i] == guess[i])
- correctPosition++;
- else {
- boardColours[board[i]]++;
- guessColours[guess[i]]++;
- }
- }
-
- var correctColour = 0;
- for (var c = 0; c < my.colours; c++)
- correctColour += Math.min(guessColours[c], boardColours[c]);
-
- return [correctPosition, correctColour];
- }
-
- my.possibleScores = [];
- for (var c = 0; c <= my.pegs; c++)
- for (var p = 0; p <= my.pegs - c; p++)
- my.possibleScores.push([p, c]);
-
- // Remove combinations based on guess and score
- my.eliminateCombinations = function(guess, score, splice) {
- var keepers = [];
- var removals = 0;
- for (var c in my.combinations) {
- var s = my.score(guess, my.combinations[c]);
- if (s[0] == score[0] && s[1] == score[1]) {
- if (splice)
- keepers.push(my.combinations[c]);
- } else {
- removals++;
- }
- }
- if (splice)
- my.combinations = keepers;
- return removals;
- }
-
- // Calculate minimum number of eliminations
- my.guessScore = function(guess) {
- var score = my.combinations.length + 1;
- for (var s in my.possibleScores) {
- var removals = my.eliminateCombinations(guess, my.possibleScores[s], false);
- score = Math.min(removals, score);
- }
- return score;
- }
-
- // Estimate time of bsetGuess brute force method
- my.estimateTime = function() {
- var t1 = new Date();
- var score = my.guessScore(my.combinations[0]);
- var t2 = new Date();
- var t = t2.getTime() - t1.getTime();
- return t * my.combinations.length;
- }
-
- // Brute force search of all possibilities
- my.bestGuess = function() {
- var bestGuess;
- var bestScore = -1;
- for (var guess in my.combinations) {
- var score = my.guessScore(my.combinations[guess]);
- if (score > bestScore) {
- bestScore = score;
- bestGuess = my.combinations[guess];
- }
- }
- my.bestScore = bestScore;
- my.bestGuess = bestGuess;
- return bestGuess;
- }
-
- // Try random guesses until we run out of time
- my.fastGuess = function(limit) {
- var t1 = new Date();
- t1 = t1.getTime();
- var bestGuess;
- var bestScore = -1;
- var time = 0;
- var tried = [];
- do {
- var guess;
- guess = Math.floor(Math.random() * my.combinations.length);
- while (find(guess, tried) >= 0)
- guess = (guess + 1) % my.combinations.length;
- tried.push(guess);
-
- var score = my.guessScore(my.combinations[guess]);
- if (score > bestScore) {
- bestScore = score;
- bestGuess = my.combinations[guess];
- }
- var t2 = new Date();
- time = t2.getTime() - t1;
-
- if (tried.length >= my.combinations.length)
- break;
- } while (time < limit)
- my.bestScore = bestScore;
- my.bestGuess = bestGuess;
- return bestGuess;
- }
- }
-
- var form = document.evaluate("//form[@name='groupcheck']",
- document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
- if (form) {
- form = form.singleNodeValue;
- var guesses = document.evaluate("//table/tbody/tr[count(descendant::td)=5]",
- document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
-
- var prevGuesses = 0;
- var board = new Mastermind(4, colours.length);
-
- // Legacy hint
- if (/You have a strong feeling that the first Chakra isn.t (\w+)/.test(form.textContent)) {
- GM_log("Legacy: " + RegExp.lastParen);
- var chakra = find(RegExp.lastParen, colours);
-
- if (chakra >= 0) {
- keepers = [];
- for (var i in board.combinations)
- if (board.combinations[i][0] != chakra)
- keepers.push(board.combinations[i]);
- GM_log("Kept " + keepers.length + " / " + board.combinations.length);
- board.combinations = keepers;
- }
- }
-
- for (var g = 0; g < guesses.snapshotLength; g++) {
- var tds = guesses.snapshotItem(g).getElementsByTagName("td");
- var guess = [];
- var res = []
- for (var i = 0; i < 4; i++) {
- var col = tds[i].textContent;
- if (find(col, colours))
- guess.push(find(col, colours));
- else
- continue;
- }
- var match = tds[4].textContent.match(/(\d+)[^\d]+(\d+)/);
- if (match && guess.length == 4) {
- res = [parseInt(match[1]), parseInt(match[2])];
- board.appendGuess(guess, res);
- board.eliminateCombinations(guess, res, true);
- prevGuesses++;
- }
- }
-
- var div = document.createElement("div");
- form.parentNode.insertBefore(div, form.nextSibling);
- div.textContent = "Searching...";
- setTimeout(function() {
- var limited = false;
- var bestGuess;
- if (board.estimateTime() > TIMELIMIT) {
- bestGuess = board.fastGuess(TIMELIMIT);
- limited = true;
- } else
- bestGuess = board.bestGuess();
-
- if (board.combinations.length > 0) {
- if (limited)
- div.textContent = "Guess (" + Math.round(TIMELIMIT / 1000) + " s search): " + print(bestGuess);
- else
- div.textContent = "Best guess: " + print(bestGuess);
- }
- }, 100);
- }