Part of the Eurovision Song Contest is the voting process to determine the winner of the contest. Each country gives between 1 and 12 points to its 10 most favorite songs. When all the points have been calculated, the presenters of the show call upon each voting country in turn to invite them to announce the results of their vote. Once all the countries have announced their votes, the country with the most points is declared the winner of the contest.
Since 2011, the voting order is determined by an algorithm so as to create as much suspense as possible when the votes were revealed. I don't know what algorithm is used, so I tried to come up with an algorithm of my own to calculate the voting order. And this is my code:
def voting_order(score_board, countries):
'''
Reorders the voting order to make the voting more "exciting".
The algorithm is based on the observation that if a certain country
awarded x points to the 1st place of the scoreboard and y points to the
2nd place, and the difference x - y is the same as the difference between
1st place's score and 2nd place's score, then removing this country's vote
from the scoreboard will leave it with 1st place and 2nd place having the
same score, i.e. a tie. Therefore we look for the country with the smallest
difference between (x - y) and (1st place's score - 2nd place's score). If
there are more than one country with the same minimal difference, we look
at the differences between 2nd place and 3rd place, and so on. (If we
reached the last place and still have two or more countries with the same
differences, we choose one of them.)
So the idea is to work backwards, starting with the full scoreboard and
removing at every iteration the "best candidate" that will leave the
remaining scoreboard with scores as close as possible. The voting order is
the reverse order in which the countries have been removed from the
scoreboard (the first country to be removed is the last one to vote, etc.)
'''
#We sort the scoreboard by scores so that it's easier to get the scores of
#1st, 2nd etc. places.
sorted_board = sort_scoreboard(score_board)
voting_order = []
while len(countries) > 0:
best_candidate = find_best_candidate(countries, sorted_board)
remove_from_scoreboard(sorted_board, countries.index(best_candidate))
voting_order.insert(0, best_candidate)
countries.remove(best_candidate)
sorted_board = sort_scoreboard(sorted_board)
return voting_order
def sort_scoreboard(scoreboard):
return sorted(scoreboard, key=lambda row: sum(row), reverse=True)
def find_best_candidate(candidates, scoreboard):
init_cands = candidates
scores = [sum(row) for row in scoreboard]
place = 0
while len(candidates) > 1 and place < len(scoreboard):
diff_score = scores[place] - scores[place+1]
cand_diffs = [abs(scoreboard[place][init_cands.index(c)] -
scoreboard[place+1][init_cands.index(c)] - diff_score)
for c in candidates]
candidates = [c[0] for c in zip(candidates, cand_diffs)
if c[1] == min(cand_diffs)]
place += 1
return candidates[0]
def remove_from_scoreboard(scoreboard, column_index):
for row in scoreboard:
row.pop(column_index)
if __name__ == '__main__':
#Eurovision 2014 scoreboard. 1st column is Albania's vote, 2nd column is Armenia's vote, etc.
VOTING_COUNTRIES = ['Albania', 'Armenia', 'Austria', 'Azerbaijan', 'Belarus', 'Belgium', 'Denmark', 'Estonia', 'FYR Macedonia', 'Finland', 'France',
'Georgia', 'Germany', 'Greece', 'Hungary', 'Iceland', 'Ireland', 'Israel', 'Italy', 'Latvia', 'Lithuania', 'Malta', 'Moldova',
'Montenegro', 'Norway', 'Poland', 'Portugal', 'Romania', 'Russia', 'San Marino', 'Slovenia', 'Spain', 'Sweden', 'Switzerland',
'Netherlands', 'Ukraine', 'United Kingdom']
SCOREBOARD = [
[ 0, 0, 5, 10, 8, 4, 1, 8, 0, 2, 0, 6, 0, 5, 2, 0, 0, 5, 10, 7, 5, 0, 10, 7, 0, 5, 0, 0, 7, 0, 0, 6, 0, 0, 0, 0, 0],
[ 0, 8, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, 0, 5, 1, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 6, 0],
[ 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 12, 0, 0, 0, 0, 0, 1, 0],
[ 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 7, 0, 2, 0, 5, 0, 0, 0, 7, 0, 0, 0, 0, 0, 6, 0, 0, 0, 1, 8, 0, 1, 4, 0, 6, 0, 4],
[ 0, 0, 1, 0, 4, 0, 6, 3, 0, 7, 2, 0, 5, 3, 0, 1, 7, 0, 0, 5, 8, 2, 0, 0, 0, 7, 3, 1, 0, 0, 5, 0, 3, 5, 10, 0, 0],
[ 0, 0, 8, 6, 1, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 2, 8, 5, 0, 0, 8, 12, 0, 4, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0],
[ 0, 0, 12, 0, 10, 0, 2, 5, 8, 4, 12, 12, 6, 7, 7, 2, 0, 6, 0, 10, 0, 6, 3, 10, 0, 1, 4, 7, 8, 6, 0, 4, 5, 0, 7, 10, 0],
[ 6, 12, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 2, 7, 0, 0, 0, 5, 0, 5, 0, 10, 1, 3, 3, 0, 0, 8, 0, 0, 0, 2, 4, 2, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 7, 0],
[ 2, 7, 0, 4, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 2, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 2],
[ 5, 0, 0, 1, 0, 12, 8, 4, 3, 12, 10, 10, 7, 12, 10, 10, 12, 12, 12, 6, 10, 10, 7, 2, 10, 0, 12, 8, 5, 0, 12, 12, 12, 12, 12, 8, 12],
[ 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 2, 0, 0, 2, 0, 0, 7, 0, 5, 0],
[ 7, 0, 6, 0, 0, 10, 12, 10, 0, 10, 4, 2, 0, 2, 8, 7, 4, 10, 0, 8, 7, 7, 6, 3, 8, 4, 8, 12, 2, 10, 8, 10, 0, 6, 8, 12, 7],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[ 0, 10, 0, 12, 12, 0, 0, 1, 6, 0, 0, 8, 0, 10, 0, 0, 0, 3, 0, 2, 6, 5, 8, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0],
[10, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 4, 0, 0, 3, 4, 6, 0, 0, 0, 0, 4, 0, 6, 5, 0, 0, 6, 3, 0, 0, 0, 0, 7, 3, 0, 0, 0, 3, 0, 0, 6, 4, 2, 0, 6],
[12, 2, 0, 0, 0, 2, 0, 2, 0, 0, 6, 0, 1, 0, 0, 0, 6, 4, 0, 4, 4, 0, 0, 0, 5, 2, 0, 5, 0, 0, 4, 0, 0, 8, 0, 2, 5],
[ 0, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 4, 1, 0, 5, 0, 2, 0, 2, 3, 0, 5, 0, 10, 7, 6, 0, 0, 3, 0, 0, 0, 3, 0, 1],
[ 8, 0, 7, 8, 5, 7, 3, 7, 10, 5, 0, 0, 0, 6, 0, 6, 1, 7, 0, 1, 0, 0, 4, 12, 0, 0, 6, 10, 6, 7, 0, 2, 7, 1, 4, 3, 0],
[ 1, 0, 0, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5, 0, 10],
[ 0, 1, 0, 0, 0, 6, 0, 0, 0, 6, 3, 0, 8, 0, 0, 8, 0, 0, 0, 0, 1, 0, 0, 0, 1, 6, 5, 4, 0, 1, 6, 3, 8, 3, 1, 0, 3],
[ 0, 4, 10, 0, 2, 8, 10, 12, 7, 8, 8, 0, 12, 8, 12, 12, 10, 0, 4, 12, 12, 0, 0, 0, 12, 12, 10, 3, 3, 2, 10, 7, 10, 10, 0, 0, 8],
[ 3, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 3, 0, 0, 0, 4, 8, 0, 0, 0, 0, 4, 0, 0, 3, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0]
]
print(voting_order(SCOREBOARD, VOTING_COUNTRIES))
I feel that this code is not perfect and could be improved, but I'm not sure how. Any advice would be appreciated.