Skip to content

Instantly share code, notes, and snippets.

@nickcherry
Created June 13, 2017 01:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nickcherry/994125c1bc2a840a485816b9f31de2ce to your computer and use it in GitHub Desktop.
Save nickcherry/994125c1bc2a840a485816b9f31de2ce to your computer and use it in GitHub Desktop.
class Balance
attr_accessor :person, :amount
def initialize(person, amount)
@person, @amount = person, amount
end
def to_s
"#{ person }: #{ amount }"
end
end
class Ledger
attr_accessor :people, :balances
def initialize(people)
@people = people
@balances = people.each_with_object({}) do |person, bal|
bal[person] = Balance.new(person, 0)
end
end
def expense(cost:, payer:, players:)
balances[payer].amount -= cost
cost_per_player = cost / players.count
players.each { |player| balances[player].amount += cost_per_player }
end
def compute_debts
result = {}
creditors, debtors = balances.values.partition { |balance| balance.amount < 0 }
credit_index, debt_index = creditors.count - 1, debtors.count - 1
loop do
return result if credit_index < 0 || debt_index < 0
credit, debt = creditors[credit_index], debtors[debt_index]
if -credit.amount == debt.amount
(result[debt.person] ||= []).push([credit.person, debt.amount])
credit.amount = debt.amount = 0
credit_index -= 1
debt_index -= 1
elsif -credit.amount < debt.amount
(result[debt.person] ||= []).push([credit.person, -credit.amount])
debt.amount += credit.amount
credit.amount = 0;
credit_index -= 1
else
(result[debt.person] ||= []).push([credit.person, debt.amount])
credit.amount += debt.amount
debt.amount = 0
debt_index -= 1
end
end
end
end
nick, maksim, alice, bob = 'Nick', 'Maksim', 'Alice', 'Bob'
ledger = Ledger.new([nick, maksim, alice, bob])
ledger.expense(cost: 200, payer: nick, players: [nick, maksim, alice, bob])
ledger.expense(cost: 100, payer: maksim, players: [alice, bob])
ledger.compute_debts.each do |(debtor, debts)|
puts "\n#{ debtor } owes:"
debts.each do |debt|
creditor, amount = debt
puts "...#{ amount } to #{ creditor }"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment