Skip to content

Instantly share code, notes, and snippets.

@light-bringer
Created January 7, 2026 21:24
Show Gist options
  • Select an option

  • Save light-bringer/7dd93a57548bd5ba80291b28334efaa8 to your computer and use it in GitHub Desktop.

Select an option

Save light-bringer/7dd93a57548bd5ba80291b28334efaa8 to your computer and use it in GitHub Desktop.
from collections import defaultdict
from decimal import Decimal, ROUND_HALF_UP
# -----------------------------
# Configuration
# -----------------------------
PEOPLE = ["Buro", "Tablu", "Shreshtha", "Meghna", "Sayani"]
# All expenses: (amount, paid_by)
EXPENSES = [
# 26th
(2962, "Buro"),
(3300, "Buro"),
(913, "Tablu"),
(4500, "Tablu"),
# 27th
(750, "Buro"),
(6600, "Buro"),
(1420, "Buro"),
# 28th
(730, "Buro"),
(1180, "Buro"),
(4050, "Tablu"),
(10000, "Buro"),
(1420, "Tablu"),
# 29th
(1250, "Tablu"),
(3870, "Buro"),
(2870, "Buro"),
(550, "Buro"),
(4050, "Tablu"),
(4065, "Tablu"),
# 30th
(1065, "Buro"),
(550, "Tablu"),
(2000, "Buro"),
(250, "Shreshtha"),
(250, "Tablu"),
# 31st
(4000, "Buro"),
(850, "Buro"),
(250, "Buro"),
(640, "Tablu"),
(3817, "Buro"),
(3200, "Tablu"),
# 1st
(5000, "Buro"),
(2599, "Tablu"),
(565, "Tablu"),
(1310, "Tablu"),
(1695, "Buro"),
]
COLLECTOR = "Tablu"
REPRESENTED_BY_COLLECTOR = ["Tablu", "Meghna", "Sayani"]
# -----------------------------
# Helpers
# -----------------------------
TWOPLACES = Decimal("0.01")
def D(value):
return Decimal(str(value)).quantize(TWOPLACES, ROUND_HALF_UP)
# -----------------------------
# Splitwise Engine
# -----------------------------
class SplitwiseEngine:
def __init__(self, people):
self.people = people
self.balance = defaultdict(Decimal)
def add_expense(self, amount, paid_by):
amount = D(amount)
split = (amount / len(self.people)).quantize(TWOPLACES)
for p in self.people:
self.balance[p] -= split
self.balance[paid_by] += amount
def get_balances(self):
return {p: self.balance[p].quantize(TWOPLACES) for p in self.people}
def settle_with_collector(self, collector, represented):
settlements = []
# Step 1: represented people pay collector
for p in represented:
if self.balance[p] < 0:
amt = -self.balance[p]
settlements.append(f"{p} pays {collector}: {amt:.2f}")
self.balance[collector] += amt
self.balance[p] = D(0)
# Step 2: remaining debtors and creditors
creditors = {
p: amt for p, amt in self.balance.items()
if amt > 0 and p != collector
}
debtors = {
p: -amt for p, amt in self.balance.items()
if amt < 0
}
# Direct settlements (non-represented debtors)
for d, d_amt in debtors.items():
for c in list(creditors):
if d_amt <= 0:
break
pay = min(d_amt, creditors[c])
settlements.append(f"{d} pays {c}: {pay:.2f}")
d_amt -= pay
creditors[c] -= pay
self.balance[c] -= pay
# Step 3: collector pays remaining creditors
for c, amt in creditors.items():
if amt > 0:
settlements.append(f"{collector} pays {c}: {amt:.2f}")
self.balance[collector] -= amt
self.balance[c] = D(0)
self.balance[collector] = D(0)
return settlements
# -----------------------------
# Main Execution
# -----------------------------
def main():
engine = SplitwiseEngine(PEOPLE)
for amount, payer in EXPENSES:
engine.add_expense(amount, payer)
print("================================")
print("TOTAL BALANCES")
print("================================")
balances = engine.get_balances()
for p in PEOPLE:
print(f"{p:<10}: {balances[p]:>10.2f}")
print("\n================================")
print("FINAL SETTLEMENT")
print("================================")
settlements = engine.settle_with_collector(
collector=COLLECTOR,
represented=REPRESENTED_BY_COLLECTOR
)
for s in settlements:
print(s)
print("\n================================")
print("ALL SETTLED ✔")
print("================================")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment