wedding-planner/app/services/affinity_groups_hierarchy.rb
Manuel Bustillo 1f0c6c2aac
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 50s
Add copyright notice / copyright_notice (pull_request) Successful in 1m11s
Run unit tests / unit_tests (pull_request) Successful in 1m58s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 19m18s
Use group affinities in discomfort calculator
2025-01-19 20:58:42 +01:00

80 lines
1.6 KiB
Ruby

# Copyright (C) 2024 Manuel Bustillo
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
class AffinityGroupsHierarchy < Array
DEFAULT_DISCOMFORT = 1
def initialize
super
@references = {}
Group.roots.each do |group|
self << group.id
hydrate(group)
end
load_discomforts
freeze
end
def find(id)
@references[id]
end
def <<(id)
new_node = Tree::TreeNode.new(id)
super(new_node).tap { @references[id] = new_node }
end
def register_child(parent_id, child_id)
@references[parent_id] << Tree::TreeNode.new(child_id).tap { |child_node| @references[child_id] = child_node }
end
def distance(id_a, id_b)
return nil if @references[id_a].nil? || @references[id_b].nil?
@references[id_a].distance_to_common_ancestor(@references[id_b])
end
def discomfort(id_a, id_b)
return 0 if id_a == id_b
@discomforts[uuid_to_int(id_a) + uuid_to_int(id_b)] || DEFAULT_DISCOMFORT
end
def default_discomfort(id_a, id_b)
return 0 if id_a == id_b
dist = distance(id_a, id_b)
return DEFAULT_DISCOMFORT if dist.nil?
Rational(dist, dist + 1)
end
private
def load_discomforts
@load_discomforts ||= GroupAffinity.pluck(:group_a_id, :group_b_id,
:discomfort).each_with_object({}) do |(id_a, id_b, discomfort), acc|
acc[uuid_to_int(id_a) + uuid_to_int(id_b)] = discomfort
end
end
def uuid_to_int(uuid)
uuid.gsub('-', '').hex
end
def hydrate(group)
group.children.each do |child|
register_child(group.id, child.id)
hydrate(child)
end
end
end