You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
45 lines
1.2 KiB
45 lines
1.2 KiB
require_relative "rank_king/web"
|
|
require_relative "rank_king/models"
|
|
require_relative "rank_king/open_skill"
|
|
|
|
module RankKing
|
|
OS = OpenSkill.new
|
|
Match = Data.define(:a, :b)
|
|
|
|
def self.find_match(axis:)
|
|
items = axis.pool.items
|
|
|
|
items.combination(2).sort_by {|combo|
|
|
ratings = combo.map {|item| os_rating(axis:, item:) }
|
|
Math.sqrt(
|
|
[ratings, ratings.reverse]
|
|
.map {|game| [game, OS.rate(game.map {[_1]}).flatten] }
|
|
.sum {|pre,post| pre.zip(post).sum { (_1.sigma - _2.sigma)**2 }}
|
|
)
|
|
}.last
|
|
end
|
|
|
|
def self.rank(axis:, winner:, loser:)
|
|
fail unless [winner, loser].all? { _1.pool == axis.pool }
|
|
|
|
game = [winner, loser].map { os_rating(axis:, item: _1) }
|
|
result = OS.rate(game.map { [_1] }).flatten
|
|
|
|
DB.transaction do
|
|
Ranking.create(axis:, winner:, loser:)
|
|
Rating.update_or_create({axis:, item: winner}, result.fetch(0).to_h)
|
|
Rating.update_or_create({axis:, item: loser}, result.fetch(1).to_h)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def self.os_rating(**filter)
|
|
if result = Rating.where(**filter).first
|
|
OS.rating(mu: result.mu, sigma: result.sigma)
|
|
else
|
|
OS.rating
|
|
end
|
|
end
|
|
end
|