1. Overview & Specifications

2048-Infinity is an original, production-grade native Android puzzle game developed by StrangeInfinity. Built from the ground up with Kotlin 2.0.21 and Jetpack Compose Material 3, it delivers high-performance sliding-tile mechanics elevated with an infinite 64-bit numerical engine, hardware-accelerated animations running at 60/120Hz display refresh rates, persistent local state, rich player statistics, deterministic challenge seeds, and complete offline privacy.

The game declares zero internet permissions (android.permission.INTERNET is completely omitted), ensuring that zero bytes of player gameplay or analytics ever leave the device.

Technical Specifications: • Package Name: com.strangeinfinity.infinitytiles • Language: Kotlin 2.0.21 • UI Framework: Jetpack Compose (BOM 2024.10.00) + Material 3 • Minimum SDK: Android 8.0 Oreo (API 26) • Target & Compile SDK: Android 14 (API 34) • JVM Target: Java 21 • Build System: Gradle 8.10 + AGP 8.6.0 • Persistence: Jetpack DataStore Preferences 1.1.1 • Concurrency: Kotlinx Coroutines 1.9.0 + StateFlow • Packaging Size: 11 MB (.apk)

2. Clean Architecture & MVVM Pattern

The codebase strictly follows Android recommended architecture patterns: Clean Architecture, Model-View-ViewModel (MVVM), and Unidirectional Data Flow (UDF). The core deterministic puzzle engine is decoupled from Android platform dependencies, enabling instant headless unit testing without emulators.

app/src/main/java/com/strangeinfinity/infinitytiles/ ├── MainActivity.kt # Single Activity, edge-to-edge window, hardware key listener ├── domain/ │ ├── model/ │ │ ├── Tile.kt # Unique entity (id, value: Long, row, col, isMerged, isNew) │ │ ├── BoardSize.kt # Board dimensions enum (THREE=3x3, FOUR=4x4, FIVE=5x5) │ │ ├── GameMode.kt # Game modes (CLASSIC, DAILY_CHALLENGE, TIME_RUSH) │ │ ├── MoveDirection.kt # UP, DOWN, LEFT, RIGHT │ │ ├── GameState.kt # Immutable board snapshot, undo state, score, status │ │ └── GameStats.kt # Aggregated career metrics (games won, win rate, best tile) │ └── engine/ │ └── GameEngine.kt # Pure Kotlin deterministic rules, single-merge guarantee ├── data/ │ └── GamePreferencesRepository.kt # DataStore persistence for games, settings, and stats ├── sound/ │ └── SoundManager.kt # Ultra-low-latency tone synthesis and haptics └── ui/ ├── GameViewModel.kt # State holder managing UI StateFlow and user intents ├── theme/ │ ├── Color.kt # Infinite color progression and dark/light palettes │ ├── Theme.kt # Material 3 dynamic and custom theming │ └── Type.kt # Typography system ├── components/ │ ├── GameBoard.kt # Gesture handling and animated tile coordinates │ ├── TileView.kt # Dynamic font sizing and scale pop animations │ ├── ScoreCard.kt # Metric cards with animated transitions │ ├── ControlBar.kt # Action bar (Undo, Restart, Stats, Settings) │ ├── GameOverDialog.kt # End-of-game overlay with Try Again and Share │ └── VictoryDialog.kt # 2048 milestone overlay with Keep Going option └── screens/ ├── GameScreen.kt # Root composable screen ├── SettingsDialog.kt # Theme, audio, board size, and game mode preferences ├── AboutDialog.kt # Brand attribution and technical specifications └── StatisticsDialog.kt # Player lifetime metrics modal

3. Mathematical Game Engine Rules

The GameEngine enforces classic mathematical 2048 rules with deterministic invariants:

Single-Merge Guarantee

During any single directional swipe, a newly merged tile cannot merge again in the same move.

Example 1: Row [2, 2, 2, 2] moved LEFT -> [4, 4, 0, 0] (Score +8) Example 2: Row [4, 4, 8, 0] moved LEFT -> [8, 8, 0, 0] (Score +8; the resulting 8s do not chain) Example 3: Row [2, 0, 2, 4] moved LEFT -> [4, 4, 0, 0] (Score +4)

Tile Spawn Probability

A new tile is spawned only if the move altered the board configuration. The new tile is placed randomly in an unoccupied cell with exact probability distribution:

  • Tile Value 2: 90% probability (0.90)
  • Tile Value 4: 10% probability (0.10)

64-Bit Infinite Integer Engine

Unlike legacy 2048 implementations that store tile values in 32-bit signed integers (capping or overflowing around 2 billion), 2048-Infinity stores values as Kotlin 64-bit Long integers. This allows unbounded cosmic growth:

2 -> 4 -> 8 -> 16 -> 32 -> 64 -> 128 -> 256 -> 512 -> 1024 -> 2048 -> 4096 -> 8192 -> 16384 -> 32768 -> 65536 -> 131072 -> 262144 -> 524288 -> ...

Victory & Defeat Criteria

  • Victory: Unlocked when any cell achieves a value of 2048. Players can select Keep Going to continue into infinite puzzle depth.
  • Game Over: Triggered if all grid cells are occupied and no two horizontally or vertically adjacent cells contain equal values.

4. Jetpack Compose UI & Animation System

Traditional Android Views suffer from layout hierarchy recalculations during rapid gesture movements. 2048-Infinity achieves native 60 FPS and 120 FPS high-refresh rate animations using Jetpack Compose's direct lambda-offset modifier:

// Direct lambda offset bypasses full layout recomposition Modifier.offset { IntOffset( x = (col * (cellSize + gapPx)).roundToInt(), y = (row * (cellSize + gapPx)).roundToInt() ) }

Dynamic Tile Typography

As numbers grow from 2 to 16384 and beyond, tile text automatically scales dynamically to ensure numbers fit crisply within tile boundaries without ellipsis or text truncation:

  • 1–2 digits (2, 64): 32.sp font size, Bold weight
  • 3 digits (128, 512): 26.sp font size
  • 4 digits (1024, 8192): 20.sp font size
  • 5+ digits (16384, 65536): 15.sp font size

5. Zero-Latency Audio Synthesis & Haptics

Standard Android sound playback via MediaPlayer incurs noticeable 50ms–150ms decoding latency. 2048-Infinity solves this using hardware synthesized tones:

  • Move Tone: High-frequency short chirp (ToneGenerator.TONE_PROP_BEEP)
  • Merge Chime: Pleasant dual-frequency resonance (ToneGenerator.TONE_PROP_ACK)
  • Victory Fanfare: Celebratory multi-note prompt tone
  • Defeat Tone: Low-frequency minor resolution tone

Tactile vibrations are powered by Android's modern VibratorManager (API 31+) with fallback to classic Vibrator. Merge events trigger VibrationEffect.createOneShot(25, 120) for crisp haptic feedback.

6. Jetpack DataStore Persistence

Game state is managed reactively via GamePreferencesRepository backed by Jetpack DataStore. Unlike legacy SharedPreferences, DataStore performs all disk I/O asynchronously off the main thread:

Stored Preferences Keys: • KEY_BOARD_TILES: JSON / CSV serialized list of active tiles • KEY_CURRENT_SCORE: Current game score (Long) • KEY_BEST_SCORE: All-time high score for current grid size (Long) • KEY_BOARD_SIZE: Active grid dimension (3x3, 4x4, 5x5) • KEY_GAME_MODE: Active mode (Classic, Daily, Time Rush) • KEY_THEME_MODE: Dark, Light, or Follow System • KEY_SOUND_ENABLED: Audio synthesis toggle flag • KEY_HAPTIC_ENABLED: Tactile vibration toggle flag • KEY_STATS_*: Games played, won, best tile, move counts

7. APK Installation & Verification

Download the signed release APK directly to your device:

URL: https://github.com/dev-hints/2048-Infinity/releases/download/First/2048-Infinity-v1.0.0-release.apk File: 2048-Infinity-v1.0.0-release.apk Size: 11,284,557 bytes (~11 MB)

Verify APK Signature

You can inspect and verify the APK signature using the official Android SDK apksigner tool:

apksigner verify --verbose 2048-Infinity-v1.0.0-release.apk

Output confirms valid v1, v2, v3, and v4 signing schemas matching the StrangeInfinity release certificate.

8. Building from Source

To build 2048-Infinity from source code:

# 1. Clone repository git clone https://github.com/dev-hints/2048-Infinity.git cd 2048-Infinity # 2. Run automated headless unit tests ./gradlew testDebugUnitTest # 3. Assemble Debug APK ./gradlew assembleDebug # 4. Assemble Signed Release APK ./gradlew assembleRelease

The output APK is generated at app/build/outputs/apk/release/app-release.apk.

9. Permissions & Privacy Statement

2048-Infinity is built on complete transparency and user respect:

  • android.permission.VIBRATE: Used solely to generate tactile haptic feedback during moves and merges. Can be disabled at any time in Settings.
  • Zero Network Declarations: The app does not declare android.permission.INTERNET or android.permission.ACCESS_NETWORK_STATE. The Android OS prevents the app from making network connections at the kernel sandbox level.
  • Zero Tracking SDKs: No Google Play Services, Firebase, ad frameworks, or telemetry collectors are linked into the binary.