How to go about doing voting in multiplayer?

Godot Version

4.3.0

Question

I’m attempting to implement a stage selection system in my game, but I’m having trouble how to logic out the voting. There is an Autoload called StageManager that, well, manages my stages. It has an array called stages that is full of dictionaries, each dictionary being a stage. These dictionaries include the name, scene, and a preview of the stages.

I want each player (4 total) to be able to vote on any stage in the game, which will be all of the stages that are in this StageManager and in the stages array. When a player votes, their vote gets added to a dictionary that goes player_id : stage_index and it’s replicated across all clients.

Now what I’m having trouble is how to use that dictionary to actually select the stage. I can get all of the votes by themselves using .values(), but then what? The votes will all be in the form of integers since they are in the form of an index from an array. If everyone votes for stage 3, how will I have the function choose stage 3? Or if two people vote for stage 0, and one person votes for stage 1, and one person votes for stage 2, how do I have the function return that stage 2 was chosen?

There’s also the problem of tiebreaking. In the event that two or four maps were voted for equally, I would like to have the function randomly choose from the voted from maps. Is there a built in way to choose a random value from an array?

array.pick_random()

You can see it in the methods in the docs for Array here:

2 Likes

To count the votes, run through your dictionary taking each vote one at a time. Create a new array or dictionary for results, so stage_index: votes_cast.

If the value that the player voted for is in the dictionary as an index, increment its votes_cast value. If it is not in the dictionary already, add it and set votes cast to 1.

At the end run through your results dictionary, to get the stage index with the highest value.

Finally, check through again to see if there was more than one with the highest value. If so, take those and pick a random one.

TBH this seems fairly straight forward. Have I missed something that adds a complexity I am not taking into account?

Finally, to match the chosen stage index to the the stage, I presume you have an stages_offered array stored somewhere of the stages being offered in the first place. I also presume the stage_index indicates the index of the stage being voted for in that stages_offered array. So just look it up with winning index.

So you have this:

# Stages offered
var stages_offered = {
    "1": "Stage 1",
    "2": "Stage 2",
    "3": "Stage 3",
    "4": "Stage 4",
}

# Votes cast
var player_stage_votes = {
    "player1": 1,
    "player2": 2,
    "player3": 1,
    "player4": 4,
    "player5": 2,
}

# Results table
var voting_results = {
    "1": 2,
    "2": 2,
    "4":1,
}

# remove all but the highest values

var voting_results = {
    "1": 2,
    "2": 2,
 }

# Count them, if just one, you have a winner
# More than one, pick a random one
# Look up index in stages_offered for whatever stage reference you are using
2 Likes

It is straight forward! Which is why it has been absolutely killing me that I couldn’t figure out how to do it. I can calculate circular rotation to make hitboxes knock stuff back perpendicularly, but I can’t make a function that finds the highest number?

This makes a lot of sense, but how would I go out removing all of the stages that don’t have the highest amount of votes? I can sort the values within the dictionary, but I’m not sure how to go about checking if multiple have the same highest value?

1 Like

I know the feeling when you get stuck on something that turns out to be straight forward enough. Given that you can get the voting results, this script functions perfectly for testing. You should be able to get the approach from this.

extends Node2D

var highest_vote_count = -INF
var highest_voted_stages = []
var vote_winner

# Testing results - change these to test
var voting_results = {
	"1": 2,
	"2": 2,
	"3": 1,
	"4": 1,
	"5": 1,
}


func _ready():
	randomize()
	get_vote_winner()


func get_vote_winner():
	# Prep our comparators first (just in case)
	highest_voted_stages.clear()
	highest_vote_count = -INF
	
	#Create our array of highest 'voted for' stages
	for stage_index in voting_results:
		var new_vote_count = voting_results[stage_index]
		if new_vote_count > highest_vote_count:
			# New highest vote found
			highest_voted_stages.clear()
			highest_vote_count = new_vote_count
			highest_voted_stages.append(stage_index)
		elif new_vote_count == highest_vote_count:
			# Matching highest vote count found
			highest_voted_stages.append(stage_index)

	# How many stages had the highest vote
	if highest_voted_stages.size() > 1:
		vote_winner = highest_voted_stages.pick_random()
	else:
		vote_winner = highest_voted_stages[0]

	# Do whatever you need to do with the winner
	print("Vote winning stage index is: ", vote_winner)

Best wishes,

Paul

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.