<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: tapadyuti chatterjee</title>
    <description>The latest articles on DEV Community by tapadyuti chatterjee (@tapadyutichatterjee).</description>
    <link>https://dev.to/tapadyutichatterjee</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4079519%2F8c945cf0-ed17-434f-8721-cd600b5308e4.png</url>
      <title>DEV Community: tapadyuti chatterjee</title>
      <link>https://dev.to/tapadyutichatterjee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tapadyutichatterjee"/>
    <language>en</language>
    <item>
      <title>Building Mathastic Twice: One Math Puzzle Game, Two Native Architectures</title>
      <dc:creator>tapadyuti chatterjee</dc:creator>
      <pubDate>Sat, 15 Aug 2026 23:29:23 +0000</pubDate>
      <link>https://dev.to/tapadyutichatterjee/building-mathastic-twice-one-math-puzzle-game-two-native-architectures-1og6</link>
      <guid>https://dev.to/tapadyutichatterjee/building-mathastic-twice-one-math-puzzle-game-two-native-architectures-1og6</guid>
      <description>&lt;p&gt;I recently released &lt;strong&gt;Mathastic&lt;/strong&gt;, a fast-paced math puzzle game for iOS and Android.&lt;/p&gt;

&lt;p&gt;I’m Tapadyuti Chatterjee, a software engineer interested in distributed systems, mobile development, and practical applications of AI. You can learn more about my work on &lt;a href="https://tapadyuti.com/" rel="noopener noreferrer"&gt;my personal website&lt;/a&gt; or connect with me on &lt;a href="https://www.linkedin.com/in/tapadyutichatterjee/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apps.apple.com/us/app/mathastic/id6740511685" rel="noopener noreferrer"&gt;Download Mathastic on the App Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.tapadyuti.mathastic" rel="noopener noreferrer"&gt;Download Mathastic on Google Play&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is also my first post on DEV, so I wanted to go beyond a simple launch announcement. Instead, I want to share how the app works, how I structured the two native codebases, and what I learned while translating the same product into SwiftUI and Jetpack Compose.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Mathastic is a native iOS and Android game that turns arithmetic practice into short, replayable runs. Players choose a game mode, difficulty, and operation mix, then build streaks, complete missions, earn XP, unlock themes, and track their performance over time.&lt;/p&gt;

&lt;p&gt;The iOS version uses SwiftUI, observable state, and &lt;code&gt;UserDefaults&lt;/code&gt;. The Android version uses Jetpack Compose, a &lt;code&gt;ViewModel&lt;/code&gt; with &lt;code&gt;StateFlow&lt;/code&gt;, Hilt for dependency injection, and &lt;code&gt;SharedPreferences&lt;/code&gt; with Gson.&lt;/p&gt;

&lt;p&gt;Both apps share the same product rules and domain concepts, but each follows the conventions of its platform instead of forcing an identical implementation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Transparency note: I used AI to help format and polish the wording of this article. The app, architecture, implementation decisions, and experiences described here are my own.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea behind Mathastic
&lt;/h2&gt;

&lt;p&gt;The original idea was simple: arithmetic practice should feel less like a worksheet and more like a game you want to replay.&lt;/p&gt;

&lt;p&gt;A basic math quiz can ask a question, accept an answer, and display a score. That works, but it does not create much momentum. For Mathastic, I wanted each session to have a small emotional arc:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with approachable questions.&lt;/li&gt;
&lt;li&gt;Build a streak.&lt;/li&gt;
&lt;li&gt;Feel the pressure increase.&lt;/li&gt;
&lt;li&gt;Decide when to use a hint, skip, or time bonus.&lt;/li&gt;
&lt;li&gt;Finish with a useful summary of the run.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That led to several game modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timed Sprint&lt;/strong&gt; is the classic race against the clock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice&lt;/strong&gt; removes the timer and penalties so the player can focus on repetition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endless&lt;/strong&gt; increases the pressure as the run progresses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily Challenge&lt;/strong&gt; generates a consistent challenge from the current day.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Players can focus on addition, subtraction, multiplication, division, or a mixed set. Difficulty changes more than operand size: it also affects the timer, scoring, penalties, streak bonuses, and XP.&lt;/p&gt;

&lt;p&gt;The surrounding progression system—missions, achievements, levels, unlockable themes, score history, and operation-level accuracy—exists to give players a reason to return without getting in the way of the central activity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting with a shared domain model
&lt;/h2&gt;

&lt;p&gt;Although the iOS and Android projects are separate native applications, I kept their domain language deliberately similar.&lt;/p&gt;

&lt;p&gt;Both versions have equivalents of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GameConfiguration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MathQuestion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Score&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GameResult&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GameMission&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MissionProgress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PlayerProfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OperationStat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DailyChallenge&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enumerations represent the major rule choices: difficulty, operation, game mode, theme, and mission type.&lt;/p&gt;

&lt;p&gt;This was one of the most useful architectural decisions in the project. When the product has a stable vocabulary, platform-specific code becomes easier to reason about. “Timed Sprint” should mean the same thing whether its state is stored in a Swift property wrapper or a Kotlin &lt;code&gt;StateFlow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The UI implementations can differ. The game rules should not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The high-level architecture
&lt;/h2&gt;

&lt;p&gt;Conceptually, Mathastic is divided into four layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UI and navigation
        ↓
Game session state
        ↓
Question, mission, and challenge generation
        ↓
Local scores, progress, and preferences
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI renders the current state and sends player actions such as answering, requesting a hint, skipping a question, or ending a run.&lt;/p&gt;

&lt;p&gt;The game-state layer applies the rules: scoring, streaks, timing, progression, and mission updates.&lt;/p&gt;

&lt;p&gt;Small factory components generate questions, daily challenges, and missions.&lt;/p&gt;

&lt;p&gt;Finally, a local score store persists completed runs and derives higher-level information such as XP, levels, achievements, best scores, and operation accuracy.&lt;/p&gt;

&lt;p&gt;I chose a local-first design. Mathastic does not require an account or server round trip to begin a game. For this kind of app, immediate startup and offline play are more valuable than introducing a backend before it is necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question generation is more than choosing two numbers
&lt;/h2&gt;

&lt;p&gt;The question factory is one of the most important pieces of the app.&lt;/p&gt;

&lt;p&gt;It selects an operation, chooses operands based on difficulty, calculates the correct result, and creates three plausible wrong answers. Mixed mode resolves to a specific operation for every question.&lt;/p&gt;

&lt;p&gt;A few details improve the experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Division questions are built from a divisor and quotient, so answers remain whole numbers.&lt;/li&gt;
&lt;li&gt;Some addition questions hide an operand instead of always hiding the result.&lt;/li&gt;
&lt;li&gt;Wrong options are generated near the correct answer rather than being completely random.&lt;/li&gt;
&lt;li&gt;Endless mode can promote the effective difficulty as the run develops.&lt;/li&gt;
&lt;li&gt;Each question records its operation so the app can calculate per-operation accuracy later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This logic is isolated from the visual layer. A screen should not need to know how to construct a valid division problem or produce convincing distractors. It only needs a &lt;code&gt;MathQuestion&lt;/code&gt; containing a prompt, a correct answer, and a set of options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deterministic daily challenges
&lt;/h2&gt;

&lt;p&gt;The Daily Challenge created an interesting requirement: randomness needed to be predictable.&lt;/p&gt;

&lt;p&gt;A normal run can generate a fresh sequence. A daily challenge should be tied to the day so that different sessions receive the same underlying challenge configuration.&lt;/p&gt;

&lt;p&gt;Both apps derive a numeric seed from the current date. That seed determines the day’s difficulty, operation mix, theme, and question sequence.&lt;/p&gt;

&lt;p&gt;This approach has several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does not require a backend to publish each challenge.&lt;/li&gt;
&lt;li&gt;The challenge remains stable during the day.&lt;/li&gt;
&lt;li&gt;Scores can be associated with the daily seed.&lt;/li&gt;
&lt;li&gt;The behavior is easy to reproduce while debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was a good reminder that “random” and “uncontrolled” are not the same thing. Seeded randomness preserves variety while still giving the system repeatable behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  The iOS implementation
&lt;/h2&gt;

&lt;p&gt;The iOS app is written with &lt;strong&gt;SwiftUI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;NavigationStack&lt;/code&gt; begins at the welcome screen and moves into the active game configuration. Shared progress is held by a &lt;code&gt;ScoreStore&lt;/code&gt; created as a &lt;code&gt;StateObject&lt;/code&gt; at the app level and passed through the SwiftUI environment.&lt;/p&gt;

&lt;p&gt;The game screen uses SwiftUI state for the active session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current question&lt;/li&gt;
&lt;li&gt;Score and streak&lt;/li&gt;
&lt;li&gt;Remaining time&lt;/li&gt;
&lt;li&gt;Hint and skip counts&lt;/li&gt;
&lt;li&gt;Mission progress&lt;/li&gt;
&lt;li&gt;Operation statistics&lt;/li&gt;
&lt;li&gt;Tutorial state&lt;/li&gt;
&lt;li&gt;Final result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Persistent player settings use &lt;code&gt;@AppStorage&lt;/code&gt;, while completed scores are encoded and stored through &lt;code&gt;UserDefaults&lt;/code&gt;. The score store publishes a derived snapshot containing the player profile, achievements, and operation insights.&lt;/p&gt;

&lt;p&gt;This creates a straightforward flow: changing game state causes SwiftUI to redraw the relevant parts of the interface, while saving a completed run rebuilds the player’s longer-term progress.&lt;/p&gt;

&lt;p&gt;For reminders, iOS uses &lt;code&gt;UNUserNotificationCenter&lt;/code&gt; with a repeating calendar trigger. The app asks for notification permission only when the player chooses to enable the reminder, which was important to me. A reminder should be an opt-in convenience, not an automatic interruption.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Android implementation
&lt;/h2&gt;

&lt;p&gt;The Android app uses &lt;strong&gt;Kotlin&lt;/strong&gt;, &lt;strong&gt;Jetpack Compose&lt;/strong&gt;, &lt;strong&gt;Material 3&lt;/strong&gt;, and &lt;strong&gt;Navigation Compose&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The main architectural difference is that the active game logic lives in a &lt;code&gt;GameViewModel&lt;/code&gt;. The view model exposes an immutable &lt;code&gt;StateFlow&amp;lt;GameUiState&amp;gt;&lt;/code&gt;, and Compose collects that state to render the game.&lt;/p&gt;

&lt;p&gt;Player actions call methods on the view model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Player action
    → ViewModel updates GameUiState
    → StateFlow emits a new value
    → Compose recomposes the UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The timer is implemented as a coroutine job inside the view model, which makes cancellation and lifecycle handling more explicit than keeping timer behavior inside a composable.&lt;/p&gt;

&lt;p&gt;Android also uses Hilt for dependency injection. The question factory, mission factory, daily challenge factory, and score store are provided to the components that need them. &lt;code&gt;SharedPreferences&lt;/code&gt; and Gson provide lightweight local persistence for scores and settings.&lt;/p&gt;

&lt;p&gt;Daily reminders require more platform plumbing on Android. The implementation uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AlarmManager&lt;/code&gt; to schedule the repeating event&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;BroadcastReceiver&lt;/code&gt; to receive it&lt;/li&gt;
&lt;li&gt;A notification channel on Android 8 and newer&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;PendingIntent&lt;/code&gt; to reopen the app&lt;/li&gt;
&lt;li&gt;Runtime notification permission handling on newer Android versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The end result looks similar to the user, but the route to that result is distinctly Android.&lt;/p&gt;

&lt;h2&gt;
  
  
  SwiftUI and Compose: similar ideas, different centers of gravity
&lt;/h2&gt;

&lt;p&gt;SwiftUI and Jetpack Compose feel philosophically related. Both encourage declarative interfaces where the UI is a function of state.&lt;/p&gt;

&lt;p&gt;The differences become clearer once the app grows beyond a few screens.&lt;/p&gt;

&lt;p&gt;On iOS, SwiftUI property wrappers make it natural to keep a moderate amount of session state close to the view. Shared progress fits neatly into an observable environment object.&lt;/p&gt;

&lt;p&gt;On Android, the &lt;code&gt;ViewModel&lt;/code&gt; and &lt;code&gt;StateFlow&lt;/code&gt; combination creates a stronger separation between rendering and game logic. Compose primarily observes state and forwards events.&lt;/p&gt;

&lt;p&gt;Neither structure is automatically better. The important question is whether state has a clear owner.&lt;/p&gt;

&lt;p&gt;If I continued expanding the iOS version, I would likely move more of the active game-session logic into a dedicated observable model. The Android version already has that boundary because its view model owns the session.&lt;/p&gt;

&lt;p&gt;This is one of the advantages of building the same idea twice: each platform reveals architectural improvements that can inform the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native parity does not mean identical code
&lt;/h2&gt;

&lt;p&gt;My goal was feature parity, not line-by-line parity.&lt;/p&gt;

&lt;p&gt;The two apps share concepts and behavior, but the implementations use native platform tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;iOS&lt;/th&gt;
&lt;th&gt;Android&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;SwiftUI&lt;/td&gt;
&lt;td&gt;Jetpack Compose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reactive state&lt;/td&gt;
&lt;td&gt;SwiftUI state and &lt;code&gt;ObservableObject&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ViewModel&lt;/code&gt; and &lt;code&gt;StateFlow&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Navigation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NavigationStack&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Navigation Compose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preferences&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@AppStorage&lt;/code&gt; and &lt;code&gt;UserDefaults&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SharedPreferences&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Score serialization&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Codable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gson&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency management&lt;/td&gt;
&lt;td&gt;App-level environment object and direct factories&lt;/td&gt;
&lt;td&gt;Hilt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timers&lt;/td&gt;
&lt;td&gt;Foundation &lt;code&gt;Timer&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Coroutines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reminders&lt;/td&gt;
&lt;td&gt;User Notifications framework&lt;/td&gt;
&lt;td&gt;AlarmManager, receiver, and notification channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visual language&lt;/td&gt;
&lt;td&gt;SF Symbols and SwiftUI styling&lt;/td&gt;
&lt;td&gt;Material icons and Material 3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Trying to hide all these differences behind a rigid cross-platform shape would have made both implementations less natural.&lt;/p&gt;

&lt;p&gt;Instead, I treated the domain model and game behavior as the contract. Everything around that contract was allowed to follow platform conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical decisions that paid off
&lt;/h2&gt;

&lt;p&gt;A few decisions had an outsized effect on maintainability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep generation logic outside the UI
&lt;/h3&gt;

&lt;p&gt;Question, mission, and daily challenge generation live in dedicated factories. This keeps the screens focused on presentation and interaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model difficulty as behavior
&lt;/h3&gt;

&lt;p&gt;Difficulty is not just a label. Each difficulty owns values such as time limit, operand range, correct-answer points, wrong-answer penalty, streak bonus, and XP multiplier.&lt;/p&gt;

&lt;p&gt;That makes balancing changes easier and avoids scattering conditionals throughout the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Save raw run data, derive progression
&lt;/h3&gt;

&lt;p&gt;Each completed score stores useful facts about the run: accuracy inputs, streak, XP, completed missions, game mode, difficulty, theme, daily seed, and operation statistics.&lt;/p&gt;

&lt;p&gt;The score store then derives the profile, achievements, unlocked themes, and analytics. This is more flexible than persisting every calculated label separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep persistence lightweight
&lt;/h3&gt;

&lt;p&gt;The data currently fits comfortably in local preferences as encoded JSON. Adding a database would create migration and query infrastructure without yet providing enough value.&lt;/p&gt;

&lt;p&gt;That choice may change if the app gains cloud sync, social leaderboards, or a much larger history. Architecture should reflect current needs while leaving room for the next likely step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build fairness into generated questions
&lt;/h3&gt;

&lt;p&gt;Clean division answers, plausible distractors, controlled operand ranges, and reproducible daily challenges are small implementation details with a large effect on player trust.&lt;/p&gt;

&lt;p&gt;A math game can be visually polished and still feel wrong if its question generator is careless.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;The hardest part of building the app twice was not translating Swift into Kotlin. It was preserving the same experience across two different ecosystems.&lt;/p&gt;

&lt;p&gt;A few lessons stood out.&lt;/p&gt;

&lt;p&gt;First, &lt;strong&gt;write down the game rules as data&lt;/strong&gt;. When scoring and difficulty values are centralized, the two versions are much easier to compare.&lt;/p&gt;

&lt;p&gt;Second, &lt;strong&gt;state ownership matters more than framework syntax&lt;/strong&gt;. Declarative UI is pleasant only when it is clear which component controls the timer, score, current question, and final result.&lt;/p&gt;

&lt;p&gt;Third, &lt;strong&gt;small platform features can require very different implementations&lt;/strong&gt;. A “daily reminder” is one checkbox in the interface, but underneath it involves different permissions, scheduling systems, lifecycle rules, and APIs.&lt;/p&gt;

&lt;p&gt;Fourth, &lt;strong&gt;offline-first was the right constraint for this version&lt;/strong&gt;. Avoiding accounts and network dependencies kept the core loop fast and let me spend more time on the actual game.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;parity needs a checklist&lt;/strong&gt;. It is easy to add a scoring adjustment, mission, or tutorial improvement on one platform and forget the other. Shared terminology helps, but explicit feature and rule comparisons are even better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would improve next
&lt;/h2&gt;

&lt;p&gt;There are several natural directions for Mathastic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expand automated tests around question generation, seeded challenges, scoring, and progression&lt;/li&gt;
&lt;li&gt;Move more iOS session logic into a dedicated game-state object&lt;/li&gt;
&lt;li&gt;Add stronger persistence migrations as the score model evolves&lt;/li&gt;
&lt;li&gt;Improve accessibility and adaptive layouts across more device sizes&lt;/li&gt;
&lt;li&gt;Explore optional cloud sync or shared leaderboards&lt;/li&gt;
&lt;li&gt;Add deeper analytics that turn weak operations into targeted practice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key word is &lt;em&gt;optional&lt;/em&gt;. I still want the app to open quickly and let someone solve a math problem without creating an account or waiting for a server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;Mathastic began as a small math puzzle idea, but building it natively for two platforms turned it into a useful architecture exercise.&lt;/p&gt;

&lt;p&gt;The project taught me that a shared product does not require a shared UI framework. With a clear domain model, deterministic rules, and well-defined state ownership, two native implementations can feel like the same app while still respecting their platforms.&lt;/p&gt;

&lt;p&gt;If you try Mathastic, I would love to hear which mode you play and where the experience could improve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apps.apple.com/us/app/mathastic/id6740511685" rel="noopener noreferrer"&gt;Mathastic for iPhone and iPad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.tapadyuti.mathastic" rel="noopener noreferrer"&gt;Mathastic for Android&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading my first DEV post! You can find more of my projects and writing at &lt;a href="https://tapadyuti.com/" rel="noopener noreferrer"&gt;tapadyuti.com&lt;/a&gt; or connect with me on &lt;a href="https://www.linkedin.com/in/tapadyutichatterjee/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>ios</category>
      <category>android</category>
      <category>gamedev</category>
    </item>
  </channel>
</rss>
