From 52d8136e9df9e3a3882da10c08d3837f4fa1048c Mon Sep 17 00:00:00 2001 From: Joe MacMahon Date: Mon, 18 Jun 2012 20:11:54 +0100 Subject: [PATCH 1/4] Added voting on AV polls. No counting yet. --- modules/poll.js | 83 +++++++++++++++++++++++++++++++++++-------------- strings.json | 4 +++ 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/modules/poll.js b/modules/poll.js index cebb735..79ed33d 100644 --- a/modules/poll.js +++ b/modules/poll.js @@ -6,9 +6,10 @@ var poll = function(dbot) { var polls = dbot.db.polls; var commands = { '~newpoll': function(event) { - var name = event.input[1]; - var options = event.input[2].split(','); - var description = event.input[3]; + var av = event.input[1] != undefined; + var name = event.input[2]; + var options = event.input[3].split(','); + var description = event.input[4]; if(name === undefined || name === 'help') { event.reply(dbot.t('newpoll_usage')); @@ -16,13 +17,24 @@ var poll = function(dbot) { if(polls.hasOwnProperty(name)) { event.reply(dbot.t('poll_exists', {'name': name})); } else { - polls[name] = { - 'name': name, - 'description': description, - 'owner': event.user, - 'votes': {}, - 'votees': {} - }; + if(av) { + polls[name] = { + 'av': av, + 'name': name, + 'description': description, + 'owner': event.user, + 'votes': {}, + }; + } else { + polls[name] = { + 'av': av, + 'name': name, + 'description': description, + 'owner': event.user, + 'votes': {}, + 'votees': {} + }; + } for(var i=0;i Date: Mon, 18 Jun 2012 21:16:22 +0100 Subject: [PATCH 2/4] Downed tools for today --- modules/poll.js | 47 +++++++++++++++++++++++++++++++++++++++++------ snippets.js | 6 ++++++ strings.json | 4 ++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/modules/poll.js b/modules/poll.js index 79ed33d..dac4e73 100644 --- a/modules/poll.js +++ b/modules/poll.js @@ -24,7 +24,11 @@ var poll = function(dbot) { 'description': description, 'owner': event.user, 'votes': {}, + 'options': [] }; + for(var i=0;i Date: Tue, 19 Jun 2012 14:44:50 +0100 Subject: [PATCH 3/4] Added AV vote counting. --- modules/poll.js | 60 +++++++++++++++++++++++++++++++++++++++---------- snippets.js | 20 +++++++++++++++++ strings.json | 4 ++++ 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/modules/poll.js b/modules/poll.js index dac4e73..39d8a98 100644 --- a/modules/poll.js +++ b/modules/poll.js @@ -100,20 +100,19 @@ var poll = function(dbot) { if(polls.hasOwnProperty(name)) { if(polls[name].av) { var prefs = vote.split(','); + prefs = prefs.uniq(); var valid = true; prefs.each(function(pref) { - console.log(pref); - console.log(polls[name].options); - valid = valid && polls[name].options.hasOwnProperty(pref); + valid = valid && polls[name].options.indexOf(pref) != -1; }); if(valid){ if(polls[name].votes.hasOwnProperty(event.user)) { polls[name].votes[event.user] = prefs; - event.reply(dbot.t('av_changed_vote', {'vote': vote, 'poll': name, 'user': event.user})); + event.reply(dbot.t('av_changed_vote', {'vote': prefs.join(','), 'poll': name, 'user': event.user})); } else { polls[name].votes[event.user] = prefs; - event.reply(dbot.t('av_voted', {'vote': vote, 'poll': name, 'user': event.user})); + event.reply(dbot.t('av_voted', {'vote': prefs.join(','), 'poll': name, 'user': event.user})); } } else { event.reply(dbot.t('invalid_vote', {'vote': vote})); @@ -151,33 +150,70 @@ var poll = function(dbot) { } }, - '~count': function(event) { + '~winner': function(event) { var name = event.input[1]; if(polls.hasOwnProperty(name)) { + var winner; if(polls[name].av) { var finished = false; var rounds = []; var eliminated = []; + var voted; for(var roundn = 0; !finished; roundn++) { + var roundLoser; + // Populate candidates for this round rounds[roundn] = {}; polls[name].options.each(function (option) { - if(!eliminated.hasOwnProperty(option)) + if(eliminated.indexOf(option) == -1) rounds[roundn][option] = 0; }); // Count votes polls[name].votes.each(function (name, vote) { - console.log(name); + voted = false; + vote.each(function (pref) { + if(!voted && rounds[roundn].hasOwnProperty(pref)) { + rounds[roundn][pref]++; + voted = true; + } + }); }); - break; + + // Check for 50% + var max = 0; + var min = polls[name].votes.length() + rounds[roundn].each(function (option, count) { + if(count > max) { + winner = option; + max = count; + } + + if(count < min) { + roundLoser = option; + min = count; + } + }); + if((2*max) > polls[name].votes.length()) { + finished = true; + break; + } + + // Eliminate loser + eliminated.push(roundLoser); } - } else { - event.reply("Not yet implemented."); + var max = 0; + polls[name].votes.each(function (name, count) { + if(count > max) { + winner = name; + max = count; + } + }); } + event.reply(dbot.t('winner', {'poll': name, 'description': polls[name].description, 'winner': winner})); } else { event.reply(dbot.t('poll_unexistent', {'name': name})); } @@ -188,7 +224,7 @@ var poll = function(dbot) { commands['~rmoption'].regex = [/~rmoption ([^ ]+) ([^ ]+)/, 3]; commands['~vote'].regex = [/~vote ([^ ]+) ([^ ]+)/, 3]; commands['~pdesc'].regex = [/~pdesc ([^ ]+)/, 2]; - commands['~count'].regex = [/~count ([^ ]+)/, 2]; + commands['~winner'].regex = [/~winner ([^ ]+)/, 2]; return { 'name': 'poll', diff --git a/snippets.js b/snippets.js index fe97050..13d1f00 100644 --- a/snippets.js +++ b/snippets.js @@ -48,6 +48,18 @@ Array.prototype.allGroupings = function() { return groupings; } +Array.prototype.uniq = function() { + var hash = {} + var result = []; + this.each(function(item) { + if(!hash.hasOwnProperty(item)){ + hash[item] = true; + result.push(item); + } + }); + return result; +} + /*** String ***/ String.prototype.valMatch = function(regex, expLength) { @@ -158,6 +170,14 @@ Object.prototype.each = function(fun) { fun(key, this[key]); }; +Object.prototype.length = function() { + var l = 0; + for(key in this) + if(this.hasOwnProperty(key)) + l++; + return l; +} + /*** Integer ***/ Number.prototype.chanceIn = function(x, y) { diff --git a/strings.json b/strings.json index 4029099..3cee76d 100644 --- a/strings.json +++ b/strings.json @@ -253,5 +253,9 @@ "av_changed_vote": { "english": "{user} changed their vote in {poll} to '{vote}'.", "spanish" : "{user} cambió su voto en {poll} a '{vote}'." + }, + "winner": { + "english": "The winner of poll '{poll}' ({description}) is: '{winner}'.", + "spanish": "La ganera de la votación '{poll}' ({description}) es: '{winner}'." } } From e6ac8558aca844ac40b55b0a18b140ff9e3868d1 Mon Sep 17 00:00:00 2001 From: Joe MacMahon Date: Tue, 19 Jun 2012 23:39:26 +0100 Subject: [PATCH 4/4] Added running-orders, not just winners --- modules/poll.js | 38 +++++++++++++++----------------------- strings.json | 6 +++--- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/modules/poll.js b/modules/poll.js index 39d8a98..e8deed1 100644 --- a/modules/poll.js +++ b/modules/poll.js @@ -150,18 +150,18 @@ var poll = function(dbot) { } }, - '~winner': function(event) { + '~count': function(event) { var name = event.input[1]; if(polls.hasOwnProperty(name)) { - var winner; + var order; if(polls[name].av) { var finished = false; var rounds = []; var eliminated = []; var voted; - for(var roundn = 0; !finished; roundn++) { + for(var roundn = 0; roundn < polls[name].options.length; roundn++) { var roundLoser; // Populate candidates for this round @@ -182,38 +182,30 @@ var poll = function(dbot) { }); }); - // Check for 50% - var max = 0; - var min = polls[name].votes.length() + // Find the loser + var min = polls[name].votes.length() + 1; rounds[roundn].each(function (option, count) { - if(count > max) { - winner = option; - max = count; - } - if(count < min) { roundLoser = option; min = count; } }); - if((2*max) > polls[name].votes.length()) { - finished = true; - break; - } // Eliminate loser eliminated.push(roundLoser); } + order = eliminated.reverse().join(', ') } else { - var max = 0; - polls[name].votes.each(function (name, count) { - if(count > max) { - winner = name; - max = count; - } + var votesArr = []; + polls[name].votes.each(function(option, count) { + votesArr.push([option, count]); }); + + votesArr = votesArr.sort(function(a, b) { return b[1] - a[1]; }); + + order = votesArr.map(function(vote) { return vote[0]; }); } - event.reply(dbot.t('winner', {'poll': name, 'description': polls[name].description, 'winner': winner})); + event.reply(dbot.t('count', {'poll': name, 'description': polls[name].description, 'places': order})); } else { event.reply(dbot.t('poll_unexistent', {'name': name})); } @@ -224,7 +216,7 @@ var poll = function(dbot) { commands['~rmoption'].regex = [/~rmoption ([^ ]+) ([^ ]+)/, 3]; commands['~vote'].regex = [/~vote ([^ ]+) ([^ ]+)/, 3]; commands['~pdesc'].regex = [/~pdesc ([^ ]+)/, 2]; - commands['~winner'].regex = [/~winner ([^ ]+)/, 2]; + commands['~count'].regex = [/~count ([^ ]+)/, 2]; return { 'name': 'poll', diff --git a/strings.json b/strings.json index 3cee76d..15f955b 100644 --- a/strings.json +++ b/strings.json @@ -254,8 +254,8 @@ "english": "{user} changed their vote in {poll} to '{vote}'.", "spanish" : "{user} cambió su voto en {poll} a '{vote}'." }, - "winner": { - "english": "The winner of poll '{poll}' ({description}) is: '{winner}'.", - "spanish": "La ganera de la votación '{poll}' ({description}) es: '{winner}'." + "count": { + "english": "The running-order of poll '{poll}' ({description}) is: {places}.", + "spanish": "" } }