endElection tallies votes, saves the winner, and broadcasts the result. adminUser may be nil for auto-end.
(adminUser *users.UserRecord)
| 224 | // endElection tallies votes, saves the winner, and broadcasts the result. |
| 225 | // adminUser may be nil for auto-end. |
| 226 | func (m *ElectionsModule) endElection(adminUser *users.UserRecord) { |
| 227 | el := m.state.ActiveElection |
| 228 | if el == nil { |
| 229 | return |
| 230 | } |
| 231 | |
| 232 | // Tally votes: count votes per nominee userId. |
| 233 | voteCounts := make(map[int]int, len(el.NomineeIds)) |
| 234 | for _, nomineeId := range el.NomineeIds { |
| 235 | voteCounts[nomineeId] = 0 |
| 236 | } |
| 237 | for _, nomineeId := range el.Votes { |
| 238 | voteCounts[nomineeId]++ |
| 239 | } |
| 240 | |
| 241 | m.state.ActiveElection = nil |
| 242 | |
| 243 | // No nominees or no votes cast — election ends with no winner. |
| 244 | if len(el.NomineeIds) == 0 || len(el.Votes) == 0 { |
| 245 | msg := electionAlert( |
| 246 | fmt.Sprintf(`The election for <ansi fg="white-bold">%s</ansi> has ended with no winner.`, el.Title), |
| 247 | ) |
| 248 | broadcastAlert(msg) |
| 249 | return |
| 250 | } |
| 251 | |
| 252 | // Find the highest vote count, collect all nominees tied at that count. |
| 253 | topVotes := 0 |
| 254 | for _, count := range voteCounts { |
| 255 | if count > topVotes { |
| 256 | topVotes = count |
| 257 | } |
| 258 | } |
| 259 | type candidate struct { |
| 260 | userId int |
| 261 | name string |
| 262 | } |
| 263 | var tied []candidate |
| 264 | for i, nomineeId := range el.NomineeIds { |
| 265 | if voteCounts[nomineeId] == topVotes { |
| 266 | tied = append(tied, candidate{userId: nomineeId, name: el.Nominees[i]}) |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | // Pick randomly among tied candidates. |
| 271 | winner := tied[util.Rand(len(tied))] |
| 272 | winnerUserId := winner.userId |
| 273 | winnerName := winner.name |
| 274 | |
| 275 | zoneKey := strings.ToLower(el.Zone) |
| 276 | m.state.Winners[zoneKey] = Winner{ |
| 277 | CharacterName: winnerName, |
| 278 | UserId: winnerUserId, |
| 279 | Title: el.Title, |
| 280 | LastElectionRound: util.GetRoundCount(), |
| 281 | } |
| 282 | |
| 283 | msg := electionAlert( |
no test coverage detected