swap-candidates #26
@ -2,39 +2,66 @@ require_relative '../../extensions/tree_node_extension'
|
|||||||
|
|
||||||
module Tables
|
module Tables
|
||||||
class Distribution
|
class Distribution
|
||||||
attr_accessor :tables
|
|
||||||
|
|
||||||
def initialize(min_per_table:, max_per_table:)
|
def initialize(min_per_table:, max_per_table:)
|
||||||
@min_per_table = min_per_table
|
@min_per_table = min_per_table
|
||||||
@max_per_table = max_per_table
|
@max_per_table = max_per_table
|
||||||
@tables = []
|
@tables = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def tables
|
||||||
|
@tables.values.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def deep_freeze
|
||||||
|
@tables.each_value(&:freeze)
|
||||||
|
@tables.freeze
|
||||||
|
freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace(table)
|
||||||
|
@tables[table.id] = table
|
||||||
|
end
|
||||||
|
|
||||||
|
def dup
|
||||||
|
super.tap do |new_distribution|
|
||||||
|
new_distribution.instance_variable_set(:@tables, @tables.dup)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def <<(array)
|
||||||
|
Table.new(array).tap do |table|
|
||||||
|
@tables[table.id] = table
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def random_distribution(people)
|
def random_distribution(people)
|
||||||
@tables = []
|
@tables = {}
|
||||||
|
|
||||||
@tables << Table.new(people.slice!(0..rand(@min_per_table..@max_per_table))) while people.any?
|
self << people.slice!(0..rand(@min_per_table..@max_per_table)) while people.any?
|
||||||
|
|
||||||
|
@tables.freeze
|
||||||
|
freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def discomfort
|
def discomfort
|
||||||
@tables.map do |table|
|
tables.map(&:discomfort).sum
|
||||||
local_discomfort(table)
|
|
||||||
end.sum
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
"#{@tables.count} tables, discomfort: #{discomfort}"
|
"#{tables.count} tables, discomfort: #{discomfort}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def pretty_print
|
def pretty_print
|
||||||
@tables.map.with_index do |table, i|
|
tables.map.with_index do |table, i|
|
||||||
"Table #{i + 1} (#{table.count} ppl): (#{local_discomfort(table)}) #{table.map(&:full_name).join(', ')}"
|
"Table #{i + 1} (#{table.count} ppl): (#{table.discomfort}) #{table.map(&:full_name).join(', ')}"
|
||||||
end.join("\n")
|
end.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
def deep_dup
|
def deep_dup
|
||||||
self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table).tap do |new_distribution|
|
self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table).tap do |new_distribution|
|
||||||
new_distribution.tables = @tables.map(&:dup)
|
tables.each do |table|
|
||||||
|
new_distribution << table.dup
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -55,11 +82,5 @@ module Tables
|
|||||||
arrangement.update!(discomfort:)
|
arrangement.update!(discomfort:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def local_discomfort(table)
|
|
||||||
table.discomfort ||= DiscomfortCalculator.new(table).calculate
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,26 +7,26 @@ module Tables
|
|||||||
|
|
||||||
def each
|
def each
|
||||||
@initial_solution.tables.combination(2) do |table_a, table_b|
|
@initial_solution.tables.combination(2) do |table_a, table_b|
|
||||||
table_a.product(table_b).each do |(person_a, person_b)|
|
table_a.swap_candidates.product(table_b.swap_candidates).each do |(person_a, person_b)|
|
||||||
original_discomfort_a = table_a.reset
|
next if person_a.affinity_group_list.first == person_b.affinity_group_list.first
|
||||||
original_discomfort_b = table_b.reset
|
|
||||||
|
|
||||||
table_a.delete(person_a)
|
new_solution = @initial_solution.dup
|
||||||
table_b.delete(person_b)
|
|
||||||
|
|
||||||
table_a << person_b
|
new_table_a = table_a.dup
|
||||||
table_b << person_a
|
new_table_b = table_b.dup
|
||||||
|
|
||||||
yield(@initial_solution)
|
new_solution.replace(new_table_a)
|
||||||
ensure
|
new_solution.replace(new_table_b)
|
||||||
table_a.delete(person_b)
|
|
||||||
table_b.delete(person_a)
|
|
||||||
|
|
||||||
table_a << person_a
|
new_table_a.delete(person_a)
|
||||||
table_b << person_b
|
new_table_b.delete(person_b)
|
||||||
|
|
||||||
table_a.discomfort = original_discomfort_a
|
new_table_a << person_b
|
||||||
table_b.discomfort = original_discomfort_b
|
new_table_b << person_a
|
||||||
|
|
||||||
|
new_solution.freeze
|
||||||
|
|
||||||
|
yield(new_solution)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,15 +1,25 @@
|
|||||||
module Tables
|
module Tables
|
||||||
class Table < Array
|
class Table < Array
|
||||||
attr_accessor :discomfort
|
attr_writer :discomfort
|
||||||
|
attr_reader :id
|
||||||
|
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
reset
|
@id = SecureRandom.uuid
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset
|
def discomfort
|
||||||
original_discomfort = discomfort
|
@discomfort ||= DiscomfortCalculator.new(self).calculate
|
||||||
@discomfort = nil
|
end
|
||||||
original_discomfort
|
|
||||||
|
def swap_candidates
|
||||||
|
@swap_candidates ||= uniq { |person| person.affinity_group_list.first }
|
||||||
|
end
|
||||||
|
|
||||||
|
def dup
|
||||||
|
super.tap do |new_table|
|
||||||
|
new_table.discomfort = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,4 +1,4 @@
|
|||||||
NUMBER_OF_GUESTS = 50
|
NUMBER_OF_GUESTS = (ENV['SEED_GUEST_COUNT'] || 50).to_i
|
||||||
|
|
||||||
TablesArrangement.delete_all
|
TablesArrangement.delete_all
|
||||||
Expense.delete_all
|
Expense.delete_all
|
||||||
@ -21,7 +21,6 @@ Expense.create!(name: 'Transportation', amount: 3000, pricing_type: 'fixed')
|
|||||||
Expense.create!(name: 'Invitations', amount: 200, pricing_type: 'fixed')
|
Expense.create!(name: 'Invitations', amount: 200, pricing_type: 'fixed')
|
||||||
Expense.create!(name: 'Cake', amount: 500, pricing_type: 'fixed')
|
Expense.create!(name: 'Cake', amount: 500, pricing_type: 'fixed')
|
||||||
|
|
||||||
|
|
||||||
samples = {
|
samples = {
|
||||||
close_family_a: 10,
|
close_family_a: 10,
|
||||||
close_family_b: 10,
|
close_family_b: 10,
|
||||||
|
@ -14,8 +14,8 @@ module Tables
|
|||||||
context 'when there are two tables with two people each' do
|
context 'when there are two tables with two people each' do
|
||||||
let(:initial_solution) do
|
let(:initial_solution) do
|
||||||
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
|
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
|
||||||
distribution.tables << %i[a b].to_table
|
distribution << %i[a b]
|
||||||
distribution.tables << %i[c d].to_table
|
distribution << %i[c d]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -32,8 +32,8 @@ module Tables
|
|||||||
context 'when there are two tables with three people each' do
|
context 'when there are two tables with three people each' do
|
||||||
let(:initial_solution) do
|
let(:initial_solution) do
|
||||||
Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution|
|
Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution|
|
||||||
distribution.tables << %i[a b c].to_table
|
distribution << %i[a b c]
|
||||||
distribution.tables << %i[d e f].to_table
|
distribution << %i[d e f]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -55,9 +55,9 @@ module Tables
|
|||||||
context 'when there are three tables with two people each' do
|
context 'when there are three tables with two people each' do
|
||||||
let(:initial_solution) do
|
let(:initial_solution) do
|
||||||
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
|
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
|
||||||
distribution.tables << %i[a b].to_table
|
distribution << %i[a b]
|
||||||
distribution.tables << %i[c d].to_table
|
distribution << %i[c d]
|
||||||
distribution.tables << %i[e f].to_table
|
distribution << %i[e f]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user