Merge pull request 'Introduce an invitations penalty for solutions that split guests in the same invitation' (#302) from invitations-penalty into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 58s
Run unit tests / build-static-assets (push) Successful in 8m33s

Reviewed-on: #302
This commit is contained in:
bustikiller 2025-07-22 13:49:28 +00:00
commit c8b88ab3b1
3 changed files with 58 additions and 4 deletions

View File

@ -16,6 +16,7 @@ class AffinityGroupsHierarchy < Array
end
discomforts
invitation_counts
freeze
end
@ -54,8 +55,16 @@ class AffinityGroupsHierarchy < Array
Rational(dist, dist + 1)
end
def guest_count(invitation_id)
@invitation_counts[invitation_id] || 0
end
private
def invitation_counts
@invitation_counts = Guest.where.not(invitation_id: nil).group(:invitation_id).count
end
def discomforts
@discomforts ||= GroupAffinity.pluck(:group_a_id, :group_b_id,
:discomfort).each_with_object({}) do |(id_a, id_b, discomfort), acc|

View File

@ -15,7 +15,7 @@ module Tables
end
def breakdown
@breakdown ||= { table_size_penalty:, cohesion_penalty: }
@breakdown ||= { table_size_penalty:, cohesion_penalty:, invitations_penalty: }
end
private
@ -39,6 +39,12 @@ module Tables
10 * (cohesion_discomfort * 1.0 / table.size)
end
def invitations_penalty
2 * table.map(&:invitation_id)
.tally
.sum { |invitation_id, guests_in_table| hierarchy.guest_count(invitation_id) - guests_in_table }
end
#
# Calculates the discomfort of the table based on the cohesion of the guests. The total discomfort
# is calculated as the sum of the discomfort of each pair of guests. The discomfort of a pair of

View File

@ -14,14 +14,14 @@ module Tables
describe '#calculate' do
before do
allow(calculator).to receive_messages(table_size_penalty: 2, cohesion_discomfort: 3)
allow(calculator).to receive_messages(table_size_penalty: 2, cohesion_penalty: 5, invitations_penalty: 4)
end
let(:table) { Table.new(create_list(:guest, 6)) }
it 'returns the sum of the table size penalty and the average cohesion penalty', :aggregate_failures do
expect(calculator.calculate).to eq(7)
expect(calculator.breakdown).to eq(table_size_penalty: 2, cohesion_penalty: 5)
expect(calculator.calculate).to eq(11)
expect(calculator.breakdown).to eq(table_size_penalty: 2, cohesion_penalty: 5, invitations_penalty: 4)
end
end
@ -131,5 +131,44 @@ module Tables
end
end
end
describe '#invitations_penalty' do
let(:invitation_a) { create(:invitation) }
let(:invitation_b) { create(:invitation) }
let(:invitation_c) { create(:invitation) }
let(:table) do
create_list(:guest, 2, invitation: invitation_a) +
create_list(:guest, 3, invitation: invitation_b) +
create_list(:guest, 4, invitation: invitation_c)
end
context 'when the table contains all members of an invitation' do
it 'returns 0 as penalty' do
expect(calculator.send(:invitations_penalty)).to eq(0)
end
end
context 'when there is an additional guest of one of the invitations that is not included' do
before do
create(:guest, invitation: invitation_a)
end
it 'returns the penalty for the missing guest' do
expect(calculator.send(:invitations_penalty)).to eq(2)
end
end
context 'when there are multiple guests missing from different invitations' do
before do
create(:guest, invitation: invitation_b)
create(:guest, invitation: invitation_c)
end
it 'returns 2x # of guests left out as the total penalty for all missing guests' do
expect(calculator.send(:invitations_penalty)).to eq(4)
end
end
end
end
end