One of the most common voting systems for single-winner elections is the plurality voting method. Simply put, the candidate with the most votes wins. Plurality voting, however, is mathematically unsound and is liable to create situations in which voters are driven to vote for the "lesser of two evils" as opposed to the candidate they truly prefer.
In this game, you will write program that takes advantage of the plurality voting system. It will cast a vote for one of three candidates in an election. Each candidate is associated with a certain payoff for yourself, and your goal is to maximize your expected payoff.
The payoffs are "uniformly" randomly distributed, change with each election, and add to 100. Candidate A could have payoff 40, Candidate B could have payoff 27, and Candidate C could have payoff 33. Each player has a different set of payoffs.
When it is your turn to vote, you will have incomplete information. Listed below is the information that you will have available to you. Since you don't know what other player's individual payoffs are, it will be your challenge to predict how they would vote given the current poll results.
- The partial results of the election so far
- The number of entrants (excluding yourself), who haven't voted yet
- Your personal payoffs for each of the candidates
- The total group payoffs for each of the candidates
After each player has been given a chance to vote, the candidate with the most votes wins in accordance with plurality voting. Each player then receives the number of points that corresponds the their payoff from that candidate. If there is a tie in votes, then the number of points assigned will be the average of the tied candidates.
Tournament Structure
When first instantiated, the entrant will be told the number of elections held in the tournament. I will attempt to run an extremely large number of elections. Then, each election will be carried out one-by-one.
After the entrants are shuffled, each is given a turn to vote. They are given the limited information listed above and return a number signifying their vote. After each election is over, each bot is given the final poll results and their score increase from that election.
The victorious entrant will be the one with the highest total score after some large number of elections have been held. The controller also computes a "normalized" score for each contestant by comparing its score to the score distribution predicted for a randomly-voting bot.
Submission Details
Submissions will take the form of Java 8 classes. Each entrant must implement the following interface:
public interface Player
{
public String getName();
public int getVote(int [] voteCounts, int votersRemaining, int [] payoffs, int[] totalPayoffs);
public void receiveResults(int[] voteCounts, double result);
}
- Your constructor should take a single
int
as a parameter, which will represent the number of elections that will be held. - The
getName()
method returns the name to be used on the leaderboard. This allows you to have nicely-formatted names, just don't go crazy. - The
getVote(...)
method returns0
,1
, or2
to signify which candidate will receive the vote. - The
receiveResults(...)
method is mainly to enable the existence of more complex strategies that use historical data. - You are allowed to create pretty much any other methods / instance variables you wish to record and process the information given to you.
Tournament Cycle, Expanded
- The entrants are each instantiated with
new entrantName(int numElections)
. - For each election:
- The controller randomly determines the payoffs for each player for this election. The code for this is given below. Then, it shuffles players and has them start voting.
- The entrant's method
public int getVote(int [] voteCounts, int votersRemaining, int [] payoffs, int[] totalPayoffs)
is invoked, and the entrant returns their vote of0
,1
, or2
for the candidate of their choice. - Entrants whose
getVote(...)
method doesn't return a valid vote will be assigned a random vote. - After everyone has voted, the controller determines the election results by the plurality method.
- The entrants are informed of the final vote counts and their payoff by calling their method
public void receiveResults(int[] voteCounts, double result)
.
- After all elections have been held, the winner is the one with the highest score.
The Random Distribution of Payoffs
The exact distribution will have a significant effect on gameplay. I have chosen a distribution with a large standard deviation (about 23.9235) and which is capable of creating both very high and very low payoffs. I have checked that each of the three payoffs has an identical distribution.
public int[] createPlayerPayoffs()
{
int cut1;
int cut2;
do{
cut1 = rnd.nextInt(101);
cut2 = rnd.nextInt(101);
} while (cut1 + cut2 > 100);
int rem = 100 - cut1 - cut2;
int[] set = new int[]{cut1,cut2,rem};
totalPayoffs[0] += set[0];
totalPayoffs[1] += set[1];
totalPayoffs[2] += set[2];
return set;
}
More Rules
Here are some more generalized rules.
- Your program must not run/modify/instantiate any parts of the controller or other entrants or their memories.
- Since your program stays "live" for the whole tournament, don't create any files.
- Don't interact with, help, or target any other entrant programs.
- You may submit multiple entrants, as long as they are reasonably different, and as long as you follow the above rules.
- I haven't specified an exact time limit, but I would greatly appreciate runtimes that are significantly less than a second per call. I want to be able to run as many elections as feasible.
The Controller
The controller can be found here. The main program is Tournament.java
. There are also two simple bots, which will be competing, titled RandomBot
and PersonalFavoriteBot
. I will post these two bots in an answer.
Leaderboard
It looks like ExpectantBot is the current leader, followed by Monte Carlo and then StaBot.
Leaderboard - 20000000 elections:
767007688.17 ( 937.86) - ExpectantBot
766602158.17 ( 934.07) - Monte Carlo 47
766230646.17 ( 930.60) - StatBot
766054547.17 ( 928.95) - ExpectorBot
764671254.17 ( 916.02) - CircumspectBot
763618945.67 ( 906.19) - LockBot
763410502.67 ( 904.24) - PersonalFavoriteBot343
762929675.17 ( 899.75) - BasicBot
761986681.67 ( 890.93) - StrategicBot50
760322001.17 ( 875.37) - Priam
760057860.67 ( 872.90) - BestViableCandidate (2842200 from ratio, with 1422897 tie-breakers of 20000000 total runs)
759631608.17 ( 868.92) - Kelly's Favorite
759336650.67 ( 866.16) - Optimist
758564904.67 ( 858.95) - SometimesSecondBestBot
754421221.17 ( 820.22) - ABotDoNotForget
753610971.17 ( 812.65) - NoThirdPartyBot
753019290.17 ( 807.12) - NoClueBot
736394317.17 ( 651.73) - HateBot670
711344874.67 ( 417.60) - Follower
705393669.17 ( 361.97) - HipBot
691422086.17 ( 231.38) - CommunismBot0
691382708.17 ( 231.01) - SmashAttemptByEquality (on 20000000 elections)
691301072.67 ( 230.25) - RandomBot870
636705213.67 ( -280.04) - ExtremistBot
The tournament took 34573.365419071 seconds, or 576.2227569845166 minutes.
Here are some older tournament, but none of the bots have changed in functionality since these runs.
Leaderboard - 10000000 elections:
383350646.83 ( 661.14) - ExpectantBot
383263734.33 ( 659.99) - LearnBot
383261776.83 ( 659.97) - Monte Carlo 48
382984800.83 ( 656.31) - ExpectorBot
382530758.33 ( 650.31) - CircumspectBot
381950600.33 ( 642.64) - PersonalFavoriteBot663
381742600.33 ( 639.89) - LockBot
381336552.33 ( 634.52) - BasicBot
381078991.83 ( 631.12) - StrategicBot232
380048521.83 ( 617.50) - Priam
380022892.33 ( 617.16) - BestViableCandidate (1418072 from ratio, with 708882 tie-breakers of 10000000 total runs)
379788384.83 ( 614.06) - Kelly's Favorite
379656387.33 ( 612.31) - Optimist
379090198.33 ( 604.83) - SometimesSecondBestBot
377210328.33 ( 579.98) - ABotDoNotForget
376821747.83 ( 574.84) - NoThirdPartyBot
376496872.33 ( 570.55) - NoClueBot
368154977.33 ( 460.28) - HateBot155
355550516.33 ( 293.67) - Follower
352727498.83 ( 256.36) - HipBot
345702626.33 ( 163.50) - RandomBot561
345639854.33 ( 162.67) - SmashAttemptByEquality (on 10000000 elections)
345567936.33 ( 161.72) - CommunismBot404
318364543.33 ( -197.86) - ExtremistBot
The tournament took 15170.484259763 seconds, or 252.84140432938332 minutes.
I also ran a second 10m tournament, confirming ExpectantBot's lead.
Leaderboard - 10000000 elections:
383388921.83 ( 661.65) - ExpectantBot
383175701.83 ( 658.83) - Monte Carlo 46
383164037.33 ( 658.68) - LearnBot
383162018.33 ( 658.65) - ExpectorBot
382292706.83 ( 647.16) - CircumspectBot
381960530.83 ( 642.77) - LockBot
381786899.33 ( 640.47) - PersonalFavoriteBot644
381278314.83 ( 633.75) - BasicBot
381030871.83 ( 630.48) - StrategicBot372
380220471.33 ( 619.77) - BestViableCandidate (1419177 from ratio, with 711341 tie-breakers of 10000000 total runs)
380089578.33 ( 618.04) - Priam
379714345.33 ( 613.08) - Kelly's Favorite
379548799.83 ( 610.89) - Optimist
379289709.83 ( 607.46) - SometimesSecondBestBot
377082526.83 ( 578.29) - ABotDoNotForget
376886555.33 ( 575.70) - NoThirdPartyBot
376473476.33 ( 570.24) - NoClueBot
368124262.83 ( 459.88) - HateBot469
355642629.83 ( 294.89) - Follower
352691241.83 ( 255.88) - HipBot
345806934.83 ( 164.88) - CommunismBot152
345717541.33 ( 163.70) - SmashAttemptByEquality (on 10000000 elections)
345687786.83 ( 163.30) - RandomBot484
318549040.83 ( -195.42) - ExtremistBot
The tournament took 17115.327209018 seconds, or 285.25545348363335 minutes.
Array
containing a count of all the votes. Am I correct? \$\endgroup\$