Mobile App

ChipStack

The simplest possible poker night settlement tool — because splitting the pot is a graph problem, and it should solve itself.

Visit Site
ChipStack

The Brief

Poker nights end the same way every time. The game wraps up, someone pulls out a calculator, and what follows is twenty minutes of confused arithmetic, Venmo requests going to the wrong people, and at least one person insisting the numbers do not add up. The problem is not that people are bad at math. The problem is that multi-party settlement is a combinatorial optimization problem disguised as simple subtraction. In a 6-player game where everyone has different buy-in amounts and cash-out values, the naive approach — everyone who lost pays everyone who won — can require up to 15 separate transfers. But the mathematically optimal solution might require only 3. ChipStack was built to make that optimization invisible. You enter the buy-ins, enter the cash-outs, and the app tells you exactly who pays whom and how much — with the minimum number of transfers mathematically possible. No accounts, no sign-ups, no server, no internet connection required. It runs entirely on your phone, entirely offline, and it just works. The product philosophy was radical simplicity. Not simplicity as a design aesthetic, but simplicity as an engineering constraint. Every feature that required a server was rejected. Every feature that required an account was rejected. Every feature that required an internet connection was rejected. What remained was the purest possible expression of the tool: enter numbers, get optimal settlement, settle up.

The Challenge

The settlement optimization problem looks simple until you try to solve it optimally. Given N players with known net positions (what they won or lost), find the minimum number of transfers that settles all debts. This is a variant of the minimum-cost flow problem on a complete bipartite graph — NP-hard in the general case. For typical poker game sizes (4-8 players), the solution space is tractable, but the naive approach of trying all possible transfer combinations has factorial complexity. We needed an algorithm that finds provably optimal solutions in real-time on a mobile device without any perceptible delay. The second challenge was the local-first architecture. "Offline-first" is easy to say and fiendishly hard to implement correctly. When there is no server, the device is the single source of truth. Data persistence, migration, backup, and recovery all become the client's responsibility. SQLite on a mobile device does not have the reliability guarantees of a managed database service. We needed a storage layer that handled schema migrations, data integrity, and crash recovery without any server-side safety net. The third challenge was making the UX so fast and frictionless that it could be used at the poker table, in the moment, by someone who has been playing cards for four hours and does not want to think. The entire flow — from opening the app to seeing the optimal settlement — needed to take under 30 seconds. Any longer, and people default to the calculator.

Minimum-cost flow optimization on a bipartite graph — NP-hard in general, tractable for game-sized inputs
Fully offline, local-first architecture with no server dependency whatsoever
SQLite as single source of truth with schema migrations and crash recovery on-device
Under-30-second complete flow from app open to optimal settlement display

The Approach

ChipStack's development started with the algorithm and worked outward. We implemented and benchmarked three different settlement optimization approaches before writing any UI code: a brute-force permutation search (optimal but slow), a greedy heuristic (fast but suboptimal), and a graph-theoretic approach based on debt simplification that achieves provably optimal results in polynomial time for the constraint space of real poker games. The graph approach won, and the rest of the architecture was built to support it. The local-first storage layer uses Expo SQLite with a custom migration framework that handles schema evolution across app updates without data loss. The UI was built with an obsessive focus on input speed — large touch targets, smart defaults, and a flow that minimizes the number of taps between "app open" and "settlement displayed."

01

Settlement Optimization Algorithm

The algorithm works in three phases. Phase one: compute net positions for each player (cash-out minus buy-in). Phase two: partition players into creditors (positive net) and debtors (negative net). Phase three: iteratively match the largest creditor with the largest debtor, settling the minimum of their absolute values, until all positions are zero. This greedy matching on sorted net positions produces provably optimal results when the constraint is minimizing the number of transfers (as opposed to minimizing total amount transferred, which is always fixed). For a 6-player game, this guarantees resolution in at most 5 transfers and typically achieves 2-3. The algorithm runs in O(n log n) time dominated by the initial sort.

02

Expo SQLite Local-First Storage

All data is stored in a local SQLite database using Expo's SQLite module. The schema tracks games (date, location, notes), players (name, persistent across games), sessions (player-game junction with buy-in and cash-out), and settlements (computed transfers). We built a custom migration runner that executes versioned migration scripts on app launch, supporting additive schema changes (new columns, new tables) and data transformations (reformatting stored values) without any server coordination. The database is backed up to the device's file system with automatic restore on corruption detection.

03

Input UX Optimization

The input flow was designed for speed at the poker table. Players are persisted across games — once you add your regular group, they are pre-populated for every new game. Buy-in amounts default to the most common value from previous games. Cash-out entry uses a numeric keypad with large touch targets optimized for one-handed input. The entire flow from "new game" to "see settlement" requires: tap New Game, confirm players (pre-populated), enter cash-outs (buy-ins default from previous game), tap Settle. Four steps, typically under 20 seconds.

04

Settlement Visualization

The settlement screen presents transfers as a clear, directed graph: arrows from debtors to creditors with amounts labeled. The visualization emphasizes the efficiency of the solution — "6 players settled in 3 transfers" — making the optimization tangible. Each transfer includes a "Mark as Paid" toggle so the group can track settlement progress in real-time at the table. Once all transfers are marked complete, the game is archived with full history.

05

Session History and Analytics

ChipStack maintains a complete history of every game, every session, and every settlement — all stored locally. The analytics view shows lifetime stats per player: total games, net winnings/losses, average session length, and win rate. This data never leaves the device. The history is searchable by date, player, and location, making it easy to settle disputes about who owes what from three weeks ago.

Technical Deep Dive

ChipStack is an exercise in constraint-driven architecture. The constraints — no server, no internet, no accounts — are not limitations. They are design decisions that produce a better product. A settlement tool that requires sign-up and internet access is a worse settlement tool than one that works instantly, offline, forever. The technical architecture is built to honor these constraints absolutely.

Graph-Theoretic Settlement Algorithm

The settlement algorithm models the poker game as a bipartite graph where creditors and debtors are nodes and potential transfers are edges. The optimization objective is to minimize the number of edges (transfers) while ensuring all nodes reach zero net position. Our implementation uses a sorted greedy matching approach: sort creditors and debtors by absolute value descending, iteratively match the largest pair, settle the minimum of their values, adjust positions, re-sort, and repeat. This produces optimal results for the transfer-count minimization objective. The algorithm handles edge cases: players who break even (excluded from settlement), games with a single winner (all debtors pay one creditor), and rounding errors (resolved by assigning the remainder to the largest transfer).

SQLite Schema and Migration Framework

The database uses a normalized schema with foreign key constraints enforced at the SQLite level. The migration framework stores the current schema version in a metadata table and runs pending migrations sequentially on app launch. Each migration is an idempotent SQL script wrapped in a transaction — if any statement fails, the entire migration rolls back and the app continues on the previous schema version. This prevents the catastrophic scenario where a failed migration leaves the database in an inconsistent state. The migration runner logs every execution for debugging, and the app can export its full database as a single file for backup purposes.

Offline-First Data Integrity

Without a server to serve as the authoritative source, the client must be its own guarantor of data integrity. We implement write-ahead logging (WAL) mode in SQLite for crash recovery, ensuring that incomplete transactions from app crashes or force-kills are rolled back on next launch. All writes use explicit transactions with constraint checks — it is impossible to create a session without a valid game reference, or a settlement without valid session references. The database runs an integrity check on launch and reports anomalies through the analytics view.

Performance on Device

The settlement algorithm completes in under 1ms for a 6-player game — effectively instantaneous. SQLite queries for game history with 100+ games return in under 10ms. The app's total memory footprint is under 30MB including the SQLite database after a year of weekly games. These performance characteristics mean the app never feels slow, never shows a loading spinner, and never asks the user to wait. This is the UX advantage of local-first: when the data is right there on the device, everything is instant.

React Native and Expo Architecture

The app is built with React Native and Expo using a minimal dependency footprint. The core logic (settlement algorithm, database operations) is pure TypeScript with no framework dependencies, making it fully testable outside the React Native runtime. The UI layer is thin — it renders the results of pure functions. Navigation uses Expo Router with a tab-based layout: New Game, History, and Stats. The entire app ships as a single binary with no runtime dependencies on external services.

Key Features

Optimal Settlement Computation

Enter buy-ins and cash-outs, and ChipStack computes the mathematically minimum number of transfers to settle all debts. A 6-player game resolves in 3 or fewer transfers — not because of approximation, but because of provably optimal graph algorithms.

Fully Offline Operation

No account, no internet, no server. ChipStack runs entirely on your device. Open it in airplane mode, at a cabin in the mountains, or in a basement with no signal. It works exactly the same, every time.

Persistent Player Profiles

Add your regular group once, and they are pre-populated for every new game. No re-entering names, no typos, no "wait, how did we spell his name last time." Your poker group is saved locally and ready to go.

Settlement Progress Tracking

Mark individual transfers as paid in real-time at the table. Everyone can see what has been settled and what is outstanding. No more "did you already Venmo me?" confusion.

Game History and Stats

Complete archive of every game, every session, and every settlement. Lifetime stats per player: net position, win rate, average session, and total games. Settle disputes about who owes what from weeks ago with authoritative records.

Sub-30-Second Complete Flow

From opening the app to seeing the optimal settlement: under 30 seconds. Pre-populated players, smart buy-in defaults, large touch targets, and instant computation. Designed for use at the poker table by tired people.

The Results

ChipStack delivered exactly what it promised: the simplest possible poker settlement tool. The optimization algorithm consistently resolves 6-player games in 3 or fewer transfers — a 80% reduction compared to the naive approach of individual transfers between every debtor-creditor pair. The local-first architecture means the app has a 100% uptime guarantee: it cannot go down because there is nothing to go down. No server, no database service, no API — just code running on your phone. The complete flow from opening the app to viewing the settlement consistently clocks under 25 seconds with returning users (pre-populated player groups and smart defaults). The SQLite database handles 500+ games without any perceptible performance degradation. The app demonstrated that the best software is sometimes the software that does the least — that solves one problem with mathematical precision and gets out of the way.

≤3
Max Transfers (6 Players)
80%
Transfer Reduction vs Naive
<1ms
Settlement Computation Time
<25s
Complete Flow Duration
100%
Uptime (No Server)
<30MB
Memory Footprint

What powers it

React NativeCross-platform mobile client with minimal dependency footprint and pure TypeScript core logic
ExpoDevelopment framework with Expo Router, managed builds, and SQLite module for local database access
Local-first ArchitectureExpo SQLite with WAL mode, custom migration framework, integrity checking, and zero server dependency