Created
April 21, 2016 20:24
-
-
Save RGBD/d8ad8e25f0e78f840ff5494c119c91bb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name rubylovo | |
// @namespace rubylovo.rubyroidlabs.com/ | |
// @description rubylovo bot | |
// @include http://rubylovo.rubyroidlabs.com/ | |
// @version 1 | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// ==/UserScript== | |
//# data | |
var gem_names = [ | |
'Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', | |
'Hotel', 'India', 'Juliet', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', | |
'Papa', 'Quebec', 'Romeo', 'Sierra', 'Tango', 'Uniform', 'Victor', | |
'Whiskey', 'X-Ray', 'Yankee', 'Zulu', 'Abba', 'Abac', 'Arab', 'Bic', 'Boo', | |
'Bay', 'Ba', 'Bac', 'Brac', 'Baobab', 'Baboeb', 'Can', 'Cia', 'Cidr', | |
'Ciria', 'Ccc', 'Cab', 'Aacc', 'AcAc', 'Creon', 'Corn', 'Cans', 'Crc', | |
'Clic', 'Clac', 'Club', 'Coub', 'Calf', 'Carab' | |
]; // TODO: replace with real ones | |
var alphabet = "abcdefghijklmnopqrstuvwxyz".split(""); | |
//# abstract functions | |
function get_randint(min, max) { | |
return Math.floor(Math.random() * (max - min) + min); | |
} | |
function get_sample(ary) { | |
return ary[get_randint(0, ary.length)]; | |
} | |
function get_gems_fl(gem_names) { | |
var gems_fl = {}; | |
alphabet.forEach(function(first) { | |
gems_fl[first] = {}; | |
alphabet.forEach(function(last) { | |
gems_fl[first][last] = []; | |
}) | |
}); | |
gem_names.forEach(function(name) { | |
name = name.toLowerCase(); | |
first = name[0]; | |
last = name[name.length - 1]; | |
gems_fl[first][last].push(name.toLowerCase()); | |
}); | |
return gems_fl; | |
} | |
function gems_fl_size(gems_fl) { | |
var result = 0; | |
alphabet.forEach(function(first) { | |
alphabet.forEach(function(last) { | |
result += gems_fl[first][last].length; | |
}) | |
}); | |
return result; | |
} | |
function gems_fl_size_each_char(gems_fl) { | |
var result = {}; | |
alphabet.forEach(function(first) { | |
result[first] = 0; | |
alphabet.forEach(function(last) { | |
result[first] += gems_fl[first][last].length; | |
}) | |
}); | |
return result; | |
} | |
function get_cum_sums(ary) { | |
cum_sums = []; | |
sum = 0; | |
ary.forEach(function(value) { | |
sum += value; | |
cum_sums.push(sum); | |
}); | |
return cum_sums; | |
} | |
function bin_search(ary, value) { | |
var left = 0; | |
var right = ary.length - 1; | |
if (value >= ary[ary.length - 1]) return ary.length; | |
while (left < right) { | |
//console.log(left + " " + right); | |
var mid = Math.floor((left + right) / 2); | |
if (value >= ary[mid]) { | |
left = mid + 1; | |
} else { | |
right = mid; | |
} | |
} | |
return left; | |
} | |
function get_weighted_random(gems_fl, first) { | |
var counts = []; | |
alphabet.forEach(function(last) { | |
counts.push(gems_fl[first][last].length); | |
}); | |
var cum_sums = get_cum_sums(counts); | |
if (cum_sums[cum_sums.length - 1] == 0) { | |
//TODO: alert | |
console.log("no more names starting with '" + first + "'"); | |
return first + '_not_found'; | |
} | |
var pick = get_randint(0, cum_sums[cum_sums.length - 1]); | |
var idx = bin_search(cum_sums, pick); | |
var shift = null; | |
if (idx == 0) { | |
shift = pick; | |
} else { | |
shift = pick - cum_sums[idx - 1]; | |
} | |
var last = String.fromCharCode('a'.charCodeAt(0) + idx); | |
//console.log('pick ' + pick + ' idx ' + idx + ' shift ' + shift + ' last ' + | |
// last + ' result ' + gems_fl[first][last][shift]) | |
return gems_fl[first][last][shift]; | |
} | |
function get_endgame_last(gems_fl, first) { | |
var sizes = gems_fl_size_each_char(gems_fl); | |
var sortable = []; | |
for (var c in sizes) { | |
sortable.push([c, sizes[c]]); | |
} | |
sortable.sort(function(a, b) {return a[1] - b[1]}); | |
for (var i in sortable) { | |
var c = sortable[i][0]; | |
if (gems_fl[first][c].length != 0) return c; | |
} | |
console.log("get_endgame_last: no more suggestions, giving up"); | |
return null; | |
} | |
function get_endgame_pick(gems_fl, first) { | |
var last = get_endgame_last(gems_fl, first); | |
if (last == null) { | |
//TODO: alert | |
console.log("no more names starting with '" + first + "'"); | |
return first + '_not_found'; | |
} | |
return gems_fl[first][last][0]; | |
} | |
function discard_name(gems_fl, name) { | |
name = name.toLowerCase(); | |
first = name[0]; | |
last = name[name.length - 1]; | |
gems_fl[first][last] = | |
gems_fl[first][last].filter(function(n) {return n != name }); | |
} | |
function discard_names(gems_fl, names) { | |
names.forEach(function(name) { | |
discard_name(gems_fl, name); | |
}); | |
} | |
function load_gems_fl() { | |
console.log('load_gems_fl: begin'); | |
var result = JSON.parse(GM_getValue('gems_fl')); | |
console.log('load_gems_fl: end'); | |
return result; | |
} | |
function store_gems_fl(gems_fl) { | |
console.log('store_gems_fl: begin'); | |
GM_setValue('gems_fl', JSON.stringify(gems_fl)); | |
console.log('store_gems_fl: end'); | |
} | |
//# parsers and selectors | |
function get_mutation_target() { | |
return document.querySelector('.word-input'); | |
} | |
function get_answer_input() { | |
var input_list = | |
document.querySelectorAll('input[data-behavior="answer_pusher"]'); | |
if (input_list.length != 1) { | |
alert('not single input' + input_list); | |
return null; | |
} | |
var input = input_list[0]; | |
console.log(input); | |
return input | |
} | |
function get_submit_button() { | |
var button_list = document.querySelectorAll('button[type="submit"]'); | |
if (button_list.length != 1) { | |
alert('not single submit' + button_list); | |
return null; | |
} | |
var button = button_list[0]; | |
console.log(button); | |
return button; | |
} | |
function click_button(button) { | |
if(document.createEvent) | |
{ | |
var click = document.createEvent("MouseEvents"); | |
click.initMouseEvent("click", true, true, window, | |
0, 0, 0, 0, 0, false, false, false, false, 0, null); | |
button.dispatchEvent(click); | |
button.focus(); | |
} else if (document.documentElement.fireEvent) { | |
button.fireEvent("onclick"); | |
button.focus(); | |
} | |
} | |
function trigger_mutation(target) { | |
target.setAttribute('first-letter', | |
target.getAttribute('first-letter')); | |
} | |
function last_submitter_name() { | |
container = document.querySelector('.user_answers-container'); | |
name_link = container.querySelector('.user-answer') | |
.querySelector('.user-name').getElementsByTagName('a')[0]; | |
return name_link.innerText; | |
} | |
function last_submitted_names() { | |
container = document.querySelector('.user_answers-container'); | |
children = container.getElementsByClassName('user_answer-text'); | |
var results = []; | |
children = [].slice.call(children); | |
children.forEach(function(child) { | |
results.push(child.innerText); | |
}) | |
return results; | |
} | |
//# bound to globals | |
function mutation_callback(mutations) { | |
mutations.forEach(function(mutation) { | |
if (mutation.type != 'attributes' || | |
mutation.attributeName != 'first-letter') { | |
console.log('false mutation, giving up'); | |
return; | |
} | |
console.log('mutation_callback'); | |
var first = | |
mutation.target.getAttribute('first-letter').toLowerCase(); | |
//var suggestion = get_weighted_random(gems_fl, first); | |
var suggestion = get_endgame_pick(gems_fl, first); | |
console.log(suggestion); | |
answer_input.value = suggestion.substring(1); | |
if (autosubmit) { | |
console.log('autosubmitting'); | |
var names_to_discard = last_submitted_names(); | |
names_to_discard.push(suggestion); | |
console.log('names_to_discard'); | |
console.log(names_to_discard); | |
discard_names(gems_fl, names_to_discard); | |
store_gems_fl(gems_fl); | |
console.log('>>>>>>>>start with ' + first + ' ' + gems_fl_size_each_char(gems_fl)[first]); | |
console.log('>>>>>>>>fl group ' + first + ' ' + last + ' ' + | |
gems_fl[first][last].length); | |
console.log('clicking_button'); | |
setTimeout(function() { | |
click_button(submit_button); | |
}, 700); | |
console.log('button_will_be_clicked'); | |
} | |
}) | |
} | |
function create_mutation_observer(target) { | |
var observer = new MutationObserver(mutation_callback); | |
var config = { attributes: true }; | |
observer.observe(target, config); | |
return observer; | |
} | |
//# real code | |
//TODO: load_db | |
console.log("fuu"); | |
//var gems_fl = get_gems_fl(gem_names); | |
var gems_fl = load_gems_fl(); | |
console.log("bar"); | |
var answer_input = get_answer_input(); | |
var submit_button = get_submit_button(); | |
var mutation_target = get_mutation_target(); | |
var observer = create_mutation_observer(mutation_target); | |
var self_name = 'Oleg Zubchenko'; | |
var autosubmit = true; | |
if (last_submitter_name() != self_name) { | |
setTimeout(function() { | |
trigger_mutation(mutation_target); | |
}, 100); | |
} | |
console.log('gems_fl size ' + gems_fl_size(gems_fl)); | |
console.log('each char: '); | |
console.log(gems_fl_size_each_char(gems_fl)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment