11defmodule PointingParty.VoteCalculator do
2-
32 def calculate_votes ( users ) do
43 case winning_vote ( users ) do
54 top_two when is_list ( top_two ) -> { "tie" , top_two }
@@ -8,30 +7,64 @@ defmodule PointingParty.VoteCalculator do
87 end
98
109 def winning_vote ( users ) do
11- votes = Enum . map ( users , fn { _username , % { metas: [ % { points: points } ] } } -> points end )
12- calculated_votes = Enum . reduce ( votes , % { } , fn vote , acc ->
13- acc
14- |> Map . get_and_update ( vote , & ( { & 1 , ( & 1 || 0 ) + 1 } ) )
15- |> elem ( 1 )
16- end )
17- total_votes = length ( votes )
18-
19- majority_share = total_votes / 2 |> Float . floor ( )
20- majority = Enum . reduce_while ( calculated_votes , nil , fn { point , vote_count } , _acc ->
21- if vote_count == total_votes or rem ( vote_count , total_votes ) > majority_share do
22- { :halt , point }
23- else
24- { :cont , nil }
25- end
26- end )
27-
28- if is_nil ( majority ) do
29- calculated_votes
30- |> Enum . sort_by ( & elem ( & 1 , 1 ) )
31- |> Enum . take ( 2 )
32- |> Enum . map ( & elem ( & 1 , 0 ) )
33- else
34- majority
35- end
10+ initial_score_card ( )
11+ |> get_points ( users )
12+ |> calculate_vote_ratios ( )
13+ |> calculate_majority ( )
14+ |> handle_tie ( )
15+ end
16+
17+ def initial_score_card do
18+ % { votes: nil , calculated_votes: nil , majority: nil }
19+ end
20+
21+ defp get_points ( score_card , users ) do
22+ votes =
23+ users
24+ |> Enum . map ( fn { _username , % { metas: [ % { points: points } ] } } ->
25+ points
26+ end )
27+
28+ update_score_card ( score_card , :votes , votes )
29+ end
30+
31+ defp calculate_vote_ratios ( % { votes: votes } = score_card ) do
32+ calculated_votes =
33+ Enum . reduce ( votes , % { } , fn vote , acc ->
34+ acc
35+ |> Map . get_and_update ( vote , & { & 1 , ( & 1 || 0 ) + 1 } )
36+ |> elem ( 1 )
37+ end )
38+
39+ update_score_card ( score_card , :calculated_votes , calculated_votes )
40+ end
41+
42+ defp calculate_majority ( score_card ) do
43+ total_votes = length ( score_card . votes )
44+ majority_share = ( total_votes / 2 ) |> Float . floor ( )
45+
46+ majority =
47+ Enum . reduce_while ( score_card . calculated_votes , nil , fn { point , vote_count } , _acc ->
48+ if vote_count == total_votes or rem ( vote_count , total_votes ) > majority_share do
49+ { :halt , point }
50+ else
51+ { :cont , nil }
52+ end
53+ end )
54+
55+ update_score_card ( score_card , :majority , majority )
56+ end
57+
58+ defp handle_tie ( % { majority: nil , calculated_votes: calculated_votes } ) do
59+ calculated_votes
60+ |> Enum . sort_by ( & elem ( & 1 , 1 ) )
61+ |> Enum . take ( 2 )
62+ |> Enum . map ( & elem ( & 1 , 0 ) )
63+ end
64+
65+ defp handle_tie ( % { majority: majority } ) , do: majority
66+
67+ defp update_score_card ( score_card , key , value ) do
68+ Map . put ( score_card , key , value )
3669 end
3770end
0 commit comments