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