Merge pull request 'Redo TablesArrangements#show to display arrangement ID and discomfort breakdown' (#188) from table-discomfort-breakdown into main
Reviewed-on: #188
This commit is contained in:
commit
2c6a05ee06
@ -6,18 +6,33 @@ class TablesArrangementsController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
Seat.joins(guest: :group)
|
||||
.where(tables_arrangement_id: params[:id])
|
||||
.order('guests.group_id')
|
||||
.pluck(
|
||||
:table_number,
|
||||
'guests.name',
|
||||
'guests.id',
|
||||
'groups.color'
|
||||
)
|
||||
.group_by(&:first)
|
||||
.transform_values { |table| table.map { |(_, name, id, color)| { id:, name:, color: } } }
|
||||
.map { |number, guests| { number:, guests: } }
|
||||
.then { |result| render json: result }
|
||||
Guest.joins(:seats, :group)
|
||||
.where(seats: { tables_arrangement_id: params[:id] })
|
||||
.select('guests.*', 'groups.color', 'seats.table_number')
|
||||
.group_by(&:table_number)
|
||||
.map { |number, guests| format(number:, guests:) }
|
||||
.then { |result| render json: { id: params[:id], tables: result } }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format(number:, guests:)
|
||||
{
|
||||
number: number,
|
||||
discomfort: discomfort(guests: guests),
|
||||
guests: guests.as_json(only: %i[id name color])
|
||||
}
|
||||
end
|
||||
|
||||
def discomfort(guests:)
|
||||
table = Tables::Table.new(guests)
|
||||
|
||||
table.min_per_table = TableSimulatorJob::MIN_PER_TABLE
|
||||
table.max_per_table = TableSimulatorJob::MAX_PER_TABLE
|
||||
calculator = Tables::DiscomfortCalculator.new(table:)
|
||||
{
|
||||
discomfort: calculator.calculate,
|
||||
breakdown: calculator.breakdown
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -3,6 +3,9 @@
|
||||
class TableSimulatorJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
MIN_PER_TABLE = 8
|
||||
MAX_PER_TABLE = 10
|
||||
|
||||
def perform(wedding_id)
|
||||
ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do
|
||||
engine = VNS::Engine.new
|
||||
@ -10,7 +13,7 @@ class TableSimulatorJob < ApplicationJob
|
||||
engine.add_perturbation(Tables::Swap)
|
||||
engine.add_perturbation(Tables::Shift)
|
||||
|
||||
initial_solution = Tables::Distribution.new(min_per_table: 8, max_per_table: 10)
|
||||
initial_solution = Tables::Distribution.new(min_per_table: MIN_PER_TABLE, max_per_table: MAX_PER_TABLE)
|
||||
initial_solution.random_distribution(Guest.potential.shuffle)
|
||||
|
||||
engine.initial_solution = initial_solution
|
||||
|
@ -8,7 +8,11 @@ module Tables
|
||||
end
|
||||
|
||||
def calculate
|
||||
table_size_penalty + 10 * (cohesion_penalty * 1.0 / table.size)
|
||||
breakdown.values.sum
|
||||
end
|
||||
|
||||
def breakdown
|
||||
@breakdown ||= { table_size_penalty:, cohesion_penalty: }
|
||||
end
|
||||
|
||||
private
|
||||
@ -28,6 +32,10 @@ module Tables
|
||||
end
|
||||
end
|
||||
|
||||
def cohesion_penalty
|
||||
10 * (cohesion_discomfort * 1.0 / table.size)
|
||||
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
|
||||
@ -35,7 +43,7 @@ module Tables
|
||||
#
|
||||
# @return [Number] Total discomfort of the table.
|
||||
#
|
||||
def cohesion_penalty
|
||||
def cohesion_discomfort
|
||||
table.map(&:group_id).tally.to_a.combination(2).sum do |(a, count_a), (b, count_b)|
|
||||
distance = AffinityGroupsHierarchy.instance.distance(a, b)
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
require 'swagger_helper'
|
||||
|
||||
RSpec.describe 'tables_arrangements', type: :request do
|
||||
|
||||
path '/{slug}/tables_arrangements' do
|
||||
get('list tables arrangements') do
|
||||
tags 'Tables Arrangements'
|
||||
@ -33,21 +32,44 @@ RSpec.describe 'tables_arrangements', type: :request do
|
||||
parameter Swagger::Schema::SLUG
|
||||
parameter Swagger::Schema::ID
|
||||
response(200, 'successful') do
|
||||
schema type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
required: %i[number guests],
|
||||
properties: {
|
||||
number: { type: :integer },
|
||||
guests: {
|
||||
type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
required: %i[id name color],
|
||||
properties: {
|
||||
id: { type: :string, format: :uuid },
|
||||
name: { type: :string },
|
||||
color: { type: :string }
|
||||
schema type: :object,
|
||||
required: %i[id tables],
|
||||
properties: {
|
||||
id: { type: :string, format: :uuid },
|
||||
tables: {
|
||||
|
||||
type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
required: %i[number guests discomfort],
|
||||
properties: {
|
||||
number: { type: :integer },
|
||||
guests: {
|
||||
type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
required: %i[id name color],
|
||||
properties: {
|
||||
id: { type: :string, format: :uuid },
|
||||
name: { type: :string },
|
||||
color: { type: :string }
|
||||
}
|
||||
}
|
||||
},
|
||||
discomfort: {
|
||||
type: :object,
|
||||
required: %i[discomfort breakdown],
|
||||
properties: {
|
||||
discomfort: { type: :number },
|
||||
breakdown: {
|
||||
type: :object,
|
||||
required: %i[table_size_penalty cohesion_penalty],
|
||||
properties: {
|
||||
table_size_penalty: { type: :number },
|
||||
cohesion_penalty: { type: :number }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,14 @@ module Tables
|
||||
describe '#calculate' do
|
||||
before do
|
||||
allow(calculator).to receive(:table_size_penalty).and_return(2)
|
||||
allow(calculator).to receive(:cohesion_penalty).and_return(3)
|
||||
allow(calculator).to receive(:cohesion_discomfort).and_return(3)
|
||||
end
|
||||
|
||||
let(:table) { Table.new(create_list(:guest, 6)) }
|
||||
|
||||
it 'returns the sum of the table size penalty and the average cohesion penalty' do
|
||||
expect(calculator.calculate).to eq(2 + 10 * 3 / 6.0)
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
@ -71,7 +72,7 @@ module Tables
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cohesion_penalty' do
|
||||
describe '#cohesion_discomfort' do
|
||||
before do
|
||||
# Overridden in each test except trivial cases
|
||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).and_call_original
|
||||
@ -91,7 +92,7 @@ module Tables
|
||||
context 'when they belong to the same group' do
|
||||
let(:table) { create_list(:guest, 2, group: family) }
|
||||
|
||||
it { expect(calculator.send(:cohesion_penalty)).to eq(0) }
|
||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(0) }
|
||||
end
|
||||
|
||||
context 'when they belong to completely unrelated groups' do
|
||||
@ -101,7 +102,7 @@ module Tables
|
||||
create(:guest, group: friends)
|
||||
]
|
||||
end
|
||||
it { expect(calculator.send(:cohesion_penalty)).to eq(1) }
|
||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(1) }
|
||||
end
|
||||
|
||||
context 'when they belong to groups at a distance of 1' do
|
||||
@ -112,7 +113,7 @@ module Tables
|
||||
]
|
||||
end
|
||||
|
||||
it { expect(calculator.send(:cohesion_penalty)).to eq(0.5) }
|
||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(0.5) }
|
||||
end
|
||||
|
||||
context 'when they belong to groups at a distance of 2' do
|
||||
@ -123,7 +124,7 @@ module Tables
|
||||
]
|
||||
end
|
||||
|
||||
it { expect(calculator.send(:cohesion_penalty)).to eq(Rational(2, 3)) }
|
||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(Rational(2, 3)) }
|
||||
end
|
||||
|
||||
context 'when they belong to groups at a distance of 3' do
|
||||
@ -134,7 +135,7 @@ module Tables
|
||||
]
|
||||
end
|
||||
|
||||
it { expect(calculator.send(:cohesion_penalty)).to eq(Rational(3, 4)) }
|
||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(Rational(3, 4)) }
|
||||
end
|
||||
end
|
||||
|
||||
@ -148,7 +149,7 @@ module Tables
|
||||
end
|
||||
|
||||
it 'returns the sum of the penalties for each pair of guests' do
|
||||
expect(calculator.send(:cohesion_penalty)).to eq(1 + Rational(1, 2) + Rational(2, 3))
|
||||
expect(calculator.send(:cohesion_discomfort)).to eq(1 + Rational(1, 2) + Rational(2, 3))
|
||||
end
|
||||
end
|
||||
|
||||
@ -163,7 +164,7 @@ module Tables
|
||||
end
|
||||
|
||||
it 'returns the sum of the penalties for each pair of guests' do
|
||||
expect(calculator.send(:cohesion_penalty))
|
||||
expect(calculator.send(:cohesion_discomfort))
|
||||
.to eq(1 + Rational(1, 2) + Rational(2, 3) + Rational(3, 4) + Rational(4, 5) + Rational(5, 6))
|
||||
end
|
||||
end
|
||||
@ -177,7 +178,7 @@ module Tables
|
||||
end
|
||||
|
||||
it 'returns the sum of the penalties for each pair of guests' do
|
||||
expect(calculator.send(:cohesion_penalty)).to eq(4)
|
||||
expect(calculator.send(:cohesion_discomfort)).to eq(4)
|
||||
end
|
||||
end
|
||||
|
||||
@ -190,7 +191,7 @@ module Tables
|
||||
end
|
||||
|
||||
it 'returns the sum of the penalties for each pair of guests' do
|
||||
expect(calculator.send(:cohesion_penalty)).to eq(8)
|
||||
expect(calculator.send(:cohesion_discomfort)).to eq(8)
|
||||
end
|
||||
end
|
||||
|
||||
@ -204,7 +205,7 @@ module Tables
|
||||
end
|
||||
|
||||
it 'returns the sum of the penalties for each pair of guests' do
|
||||
expect(calculator.send(:cohesion_penalty)).to eq(4 * 1 + 4 * Rational(1, 2) + 4 * Rational(2, 3))
|
||||
expect(calculator.send(:cohesion_discomfort)).to eq(4 * 1 + 4 * Rational(1, 2) + 4 * Rational(2, 3))
|
||||
end
|
||||
end
|
||||
|
||||
@ -218,7 +219,7 @@ module Tables
|
||||
end
|
||||
|
||||
it 'returns the sum of the penalties for each pair of guests' do
|
||||
expect(calculator.send(:cohesion_penalty)).to eq(6 * 1 + 2 * Rational(1, 2) + 3 * Rational(2, 3))
|
||||
expect(calculator.send(:cohesion_discomfort)).to eq(6 * 1 + 2 * Rational(1, 2) + 3 * Rational(2, 3))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user