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 raisesValueErrorunchanged. Split cents using the prototype's rule. Credit the payer with total, debit each participant with their share, and returnTruefor 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, andamount > 0; invalid structure raisesValueError. For a new ID, requirebalance[debtor] <= -amountandbalance[creditor] >= amount, otherwise raiseValueErrorunchanged. Increase the debtor balance by amount and decrease the creditor balance by amount. ReturnTrueon acceptance.- Both mutation methods recognize exact retries after structural validation and before applying any balance-dependent checks. A repeated accepted operation returns
Falsewithout 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 raisesValueError. 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.
Complete the starter code, then run the checks.
Results and errors will appear here.