Arguments have the documented types. Money is integer cents; IDs and member names are case-sensitive strings. No floating-point conversion is required. Inputs must be copied where retained. Returned dictionaries/lists must be fresh, and instances must be independent. There is no member deletion, expense editing, currency conversion, or external payment processing.

Prototype: implement split_equal(total, participants) -> dict[str, int]. Require total >= 0 and a nonempty list of distinct, nonempty participant names; otherwise raise ValueError. Return shares in lexicographic member order. Give each participant total // count, and give the first total % count sorted members one extra cent. Zero shares are valid. Do not mutate the input list.

Final: implement ExpenseSharing(members), where members is a nonempty list of distinct, nonempty names; invalid constructor input raises ValueError. Start every member at zero. The class manages one shared operation-ID namespace across expenses and settlements.

  • add_expense(operation_id, payer, total, participants) -> bool: require a nonempty operation ID, total > 0, a payer in the group, and a nonempty list of distinct group members. Invalid data raises ValueError unchanged. Split cents using the prototype's rule. Credit the payer with total, debit each participant with their share, and return True for a newly accepted expense. The payer may be absent from participants.
  • settle(operation_id, debtor, creditor, amount) -> bool: require a nonempty ID, two distinct group members, and amount > 0; invalid structure raises ValueError. For a new ID, require balance[debtor] <= -amount and balance[creditor] >= amount, otherwise raise ValueError unchanged. Increase the debtor balance by amount and decrease the creditor balance by amount. Return True on acceptance.
  • Both mutation methods recognize exact retries after structural validation and before applying any balance-dependent checks. A repeated accepted operation returns False without mutation. For expense identity, participant order is ignored; payer, total, and participant membership must match. For settlements, debtor, creditor, and amount must match. Reusing any accepted ID with different data or a different method raises ValueError. Failed requests do not consume IDs.
  • balances() -> dict[str, int]: return every member, including zero balances, in lexicographic key order. Positive means owed money; negative means owes money. The sum must always be zero.
  • suggest_settlements() -> list[tuple[str, str, int]]: use copies of balances. Sort debtors and creditors independently by name. Match the first remaining debtor to the first remaining creditor for the smaller remaining amount; advance each exhausted side and repeat. Return (debtor, creditor, cents) tuples in that generated order. Omit zero amounts. Reading suggestions never applies them. Return [] when all balances are zero; no minimum-transfer claim is required.

Every invalid request preserves balances and the operation registry. Run python main.py --stage prototype, then python main.py --stage final (the default). Edit only exercise.py.

Drag or use the arrow keys to resize. Home collapses the question; End collapses the editor. Enter or double-click resets the split.
Loading editor…
No results yet.

Complete the starter code, then run the checks.
Results and errors will appear here.