Inspiration

Every naval-strategy game on the App Store is grey ships on a grey grid. I kept thinking about how kids actually play "battleship" — in the bathtub, with rubber ducks and a submarine that's really a shampoo bottle. So I flipped the fantasy: what if the tub itself was the arena? Suds hide your fleet, a toy cannon fires your shots, and the villain is a scruffy pirate pug named Captain Pugbeard who talks trash between turns. Cozy on the surface, real turn-based strategy underneath.

What it does

Tub Pirates is a bath-toy naval strategy game for iOS:

  • A single-player ladder of four pirate captains — Captain Pugbeard, Soapy Sal, Barnacle Bess, and Admiral Bubbles — each with their own arsenal, difficulty, and table talk.
  • Five special cannons (Parrot Scout, Big Shot, Chain Shot, Flare, Fireworks) that trade doubloons for area shots, line rakes, and intel.
  • Three ways to play: the captain ladder, Pass & Play on one device with a privacy handoff, and online turn-based multiplayer with instant quick-chat through Game Center.
  • An economy to plunder: win battles, claim daily treasure, then spend doubloons in the Armory (specials), the Shipyard (Ducky Squadron and Sea Monster Crew fleets), and the avatar shop.
  • RevenueCat-powered doubloon packs for players who want to fast-track their fleet.

How we built it

I shipped it in under three weeks (first commit July 15) as a solo developer, pair-programming the whole way with Claude Code.

  • Engine first. The rules live in BathtubEngine, a pure Swift package with zero UI dependencies — board, placement, shot patterns, turn resolution, and the AI — covered by 43 unit tests that run on every push via GitHub Actions.
  • A deterministic, tunable AI. The AI is fully Codable with a seedable SplitMix64 RNG, so a half-finished battle serializes into a save file and replays identically in tests. It hunts with parity: if the smallest surviving toy has length $L$, only cells where $(x + y) \bmod L = 0$ need probing, cutting the search space on an $n \times n$ board from $n^2$ to about $\lceil n^2 / L \rceil$. On a hit it switches to line-following target mode. Difficulty is a single sloppiness dial — the probability per turn that the captain gets "distracted" and fires a plain hunting shot instead of exploiting intel — so each of the four captains is the same brain with a different value.
  • SwiftUI + SpriteKit. Menus, shops, and match flow are SwiftUI; the battle itself is a SpriteKit scene with a particle factory for splashes, explosions, and confetti.
  • Game Center turn-based matches handle online play, with a custom match-data codec for state sync.
  • RevenueCat powers the doubloon coin packs: consumable IAPs fetched from an Offering, joined to local bundle metadata, and purchased through Purchases.shared — my entire store screen is driven by whatever RevenueCat serves, so I can reprice and repackage without shipping an update.
  • AI as an art department. Every asset is generated: the cel-shaded bath-toy fleets and captain portraits (Gemini image generation, driven through iteration passes for style cohesion). Even my App Store screenshots are built by a reproducible HTML + headless Chrome pipeline instead of a design tool.
  • TelemetryDeck for anonymous, opt-out analytics — no ATT prompt needed.

Challenges we ran into

  • Game Center has no chat. Turn-based matches only exchange data when a turn ends, which makes multiplayer feel dead. I built instant quick-chat by piggybacking on GKTurnBasedExchange messages — canned pirate phrases arrive mid-turn without waiting for a move, and a seen-moves store deduplicates replayed events. Getting notifications to say something better than Apple's default "An action was completed" took its own debugging session.
  • A round board in a round tub. A square grid looks wrong floating in a circular bathtub. The fix was rotating the board 45° into a diamond and sizing it to the tub's inner water circle — for a grid of diagonal $d$ inside a tub of radius $r$, everything fits when $d \le 2r$ — plus nesting your own mini-board in a cloud of suds.
  • Making the AI lose gracefully. The first version of Pugbeard was ruthless — parity hunting plus intel exploitation beats a human almost every time. The sloppiness dial came out of playtesting: the AI stays smart in structure but humanly imperfect in execution, and each rung of the ladder just turns the dial down.
  • Trademark landmines. "Battleship" is Hasbro's. Every name, keyword, and store asset had to sell the genre ("sea battle," "naval strategy") without ever using the word.

Accomplishments that we're proud of

  • Shipped a complete game solo in under three weeks — 80 commits from empty Xcode template to App Store submission, with nothing stubbed out: single-player ladder, local and online multiplayer, economy, shops, achievements, and IAP all work.
  • A game engine I'd put in any codebase. BathtubEngine has zero UI dependencies, 43 passing tests, deterministic replay of any saved battle, and CI on every push. The whole game logic is provable without ever launching the app.
  • Multiplayer chat that Game Center doesn't officially support. Instant mid-turn quick-chat over GKTurnBasedExchange makes online matches feel alive — the thing turn-based games usually lack.
  • One AI, four personalities. The entire captain ladder is a single tunable brain, which meant balancing four difficulty levels was one playtesting loop instead of four.
  • It has a soul. A solo dev with AI tooling produced a cohesive hand-crafted-feeling world — cel-shaded bath toys, four trash-talking captains with wanted posters, sea-shanty soundtrack — not a programmer-art grid.

What we learned

  • Engine/UI separation pays for itself immediately. Every gnarly bug — shot patterns, turn resolution, AI behavior — was reproducible in a fast, deterministic unit test instead of a hand-played match.
  • Determinism is a feature, not a constraint. Making the RNG seedable and Codable made saves trivial and tests honest.
  • Monetization is a design problem. Consumable coin packs only feel fair because doubloons are earned in normal play; RevenueCat made the mechanical part — offerings, purchases, restore — the easy 10%.
  • AI-generated assets need an art director. Individual generations look great; a cohesive set takes deliberate style passes and a lot of rejections.

What's next for Tub Pirates: Sea Battle

  • Ship the iPad set and more localizations
  • New captains and seasonal fleets (the Shipyard was built to grow)
  • RevenueCat experiments on pack pricing, and a "remove nothing, add sparkle" cosmetic tier
  • Async tournaments between friends

Built With

Share this project:

Updates