| Class | MbraBar |
| In: |
app/models/competitions/mbra_bar.rb
|
| Parent: | Competition |
MBRA Best All-around Rider Competition. Calculates a BAR for each Discipline The BAR categories and disciplines are all configured in the databsase. Race categories need to have a bar_category_id to show up in the BAR; disciplines must exist in the disciplines table and discipline_bar_categories.
This class implements a number of MBRA-specific rules.
# File app/models/competitions/mbra_bar.rb, line 10
10: def MbraBar.calculate!(year = Date.today.year)
11: benchmark(name, Logger::INFO, false) {
12: transaction do
13: year = year.to_i if year.is_a?(String)
14: date = Date.new(year, 1, 1)
15:
16: # Age Graded BAR and Overall BAR do their own calculations
17: Discipline.find_all_bar.reject { |discipline|
18: discipline == Discipline[:age_graded] || discipline == Discipline[:overall]
19: }.each do |discipline|
20: bar = MbraBar.find(:first, :conditions => { :date => date, :discipline => discipline.name })
21: unless bar
22: bar = MbraBar.create!(
23: :name => "#{year} #{discipline.name} BAR",
24: :date => date,
25: :discipline => discipline.name
26: )
27: end
28: end
29:
30: MbraBar.find(:all, :conditions => { :date => date }).each do |bar|
31: bar.destroy_races
32: bar.create_races
33: bar.calculate_threshold_number_of_races
34: bar.calculate!
35: bar.after_create_all_results
36: end
37: end
38: }
39: # Don't return the entire populated instance!
40: true
41: end
# File app/models/competitions/mbra_bar.rb, line 43
43: def MbraBar.find_by_year_and_discipline(year, discipline_name)
44: MbraBar.find(:first, :conditions => { :date => Date.new(year), :discipline => discipline_name })
45: end
# File app/models/competitions/mbra_bar.rb, line 135
135: def after_create_all_results
136: # Riders upgrading during the season will take 1/2 of their points (up to 30 points max)
137: # with them to the higher category. The upgrading rider's accumulated points are allowed to stand at the
138: # lower category.
139: # After computing BAR results, look for Cat n BAR results for anyone in the Cat n - 1 BAR and add in half their Cat n points.
140: [
141: ["cat_up" => "Cat 1/2 Men", "cat_down" => "Cat 3 Men"],
142: ["cat_up" => "Cat 3 Men", "cat_down" => "Cat 4 Men"],
143: ["cat_up" => "Cat 4 Men", "cat_down" => "Cat 5 Men"],
144: ["cat_up" => "Cat 1/2/3 Women", "cat_down" => "Cat 4 Women"]
145: ].each do |category_pair|
146: cat = category_pair[0]["cat_up"]
147: cat_up_race = self.races.detect { |r| r.category.name == category_pair[0]["cat_up"] }
148: cat_down_race = self.races.detect { |r| r.category.name == category_pair[0]["cat_down"] }
149: cat_up_race.results.each do |up_result|
150: take_with_result = cat_down_race.results.detect { |down_result| down_result.person == up_result.person }
151: unless take_with_result.blank?
152: upgrade_points = (take_with_result.points/2).to_i
153: upgrade_points = 30 if upgrade_points > 30
154: up_result.points += upgrade_points
155: upgrade_note = "Point total includes #{upgrade_points} upgrade points."
156: if up_result.notes.blank?
157: up_result.notes = upgrade_note
158: else
159: up_result.notes += " #{upgrade_note}"
160: end
161: up_result.save!
162: end
163: end unless (cat_up_race.blank? || cat_down_race.blank?)
164:
165: end
166: end
# File app/models/competitions/mbra_bar.rb, line 118
118: def after_create_competition_results_for(race)
119: # 70% of the races (rounded to the nearest whole number) count in the
120: # individual series standings. Riders who compete in more than 70% of the
121: # races will throw out their weakest results.
122: race.results.each do |result|
123: # Don't bother sorting scores unless we need to drop some
124: if result.scores.size > @threshold_number_of_races
125: result.scores.sort! { |x, y| y.points <=> x.points }
126: for lowest_score in result.scores[@threshold_number_of_races..(result.scores.size - 1)]
127: result.scores.destroy(lowest_score)
128: end
129: # Rails destroys Score in database, but doesn't update the current association
130: result.scores(true)
131: end
132: end
133: end
Riders obtain points inversely proportional to the starting field size, plus bonuses for first, second and third place (6, 3, and 1 points respectively). DNF: 1/2 point
# File app/models/competitions/mbra_bar.rb, line 59
59: def calculate_point_schedule(field_size)
60: @point_schedule = [0]
61: field_size.downto(1) { |i| @point_schedule << i }
62: @point_schedule[1] += 6 if @point_schedule.length > 1
63: @point_schedule[2] += 3 if @point_schedule.length > 2
64: @point_schedule[3] += 1 if @point_schedule.length > 3
65: end
# File app/models/competitions/mbra_bar.rb, line 47
47: def calculate_threshold_number_of_races
48: # 70% of the races (rounded to the nearest whole number) count in the BAR standings.
49: @threshold_number_of_races = (Event.find_all_bar_for_discipline(self.discipline, self.date.year).size * 0.7).round.to_i
50: end
# File app/models/competitions/mbra_bar.rb, line 168
168: def create_races
169: Discipline[discipline].bar_categories.each do |category|
170: races.create!(:category => category)
171: logger.debug("#{self.class.name} created BAR race in discipline #{discipline} for category '#{category}'") if logger.debug?
172: end
173: end
# File app/models/competitions/mbra_bar.rb, line 179
179: def friendly_name
180: 'MBRA BAR'
181: end
# File app/models/competitions/mbra_bar.rb, line 52
52: def point_schedule
53: @point_schedule = @point_schedule || []
54: end
Apply points from point_schedule
# File app/models/competitions/mbra_bar.rb, line 102
102: def points_for(source_result, team_size = nil)
103: calculate_point_schedule(source_result.race.field_size)
104: points = 0
105: MbraBar.benchmark('points_for') {
106: if source_result.place.strip.downcase == "dnf"
107: points = 0.5
108: else
109: # if multiple riders got the same place (must be a TTT or tandem team or... ?), then they split the points...
110: #this screws up the scoring of match sprints where riders eliminatined in qualifying heats all earn the same place
111: #team_size = team_size || Result.count(:conditions => ["race_id =? and place = ?", source_result.race.id, source_result.place])
112: points = point_schedule[source_result.place.to_i] * source_result.race.bar_points #/ team_size.to_f
113: end
114: }
115: points
116: end
Source result = counts towards the BAR "race" and BAR results Example: Piece of Cake RR, 6th, Jon Knowlson
bar_result, bar_race = BAR itself and placing in the BAR Example: Senior Men BAR, 130th, Jon Knowlson, 45 points
BAR results add scoring results as scores Example: Senior Men BAR, 130th, Jon Knowlson, 18 points
- Piece of Cake RR, 6th, Jon Knowlson 10 points - Silverton RR, 8th, Jon Knowlson 8 points
# File app/models/competitions/mbra_bar.rb, line 78
78: def source_results(race)
79: race_disciplines = "'#{race.discipline}'"
80: category_ids = category_ids_for(race)
81:
82: Result.find(:all,
83: :include => [:race, {:person => :team}, :team, {:race => [{:event => { :parent => :parent }}, :category]}],
84: :conditions => [%Q{
85: (events.type in ('Event', 'SingleDayEvent', 'MultiDayEvent') or events.type is NULL)
86: and bar = true
87: and categories.id in (#{category_ids})
88: and (events.discipline in (#{race_disciplines})
89: or (events.discipline is null and parents_events.discipline in (#{race_disciplines}))
90: or (events.discipline is null and parents_events.discipline is null and parents_events_2.discipline in (#{race_disciplines})))
91: and (races.bar_points > 0
92: or (races.bar_points is null and events.bar_points > 0)
93: or (races.bar_points is null and events.bar_points is null and parents_events.bar_points > 0)
94: or (races.bar_points is null and events.bar_points is null and parents_events.bar_points is null and parents_events_2.bar_points > 0))
95: and events.date between '#{date.year}-01-01' and '#{date.year}-12-31'
96: }],
97: :order => 'person_id'
98: )
99: end