Skip to content
This repository was archived by the owner on Oct 12, 2025. It is now read-only.

gabrielrovesti/Simplis

Repository files navigation

Simplis - Modern Tetris for Android

A clean, polished Tetris implementation for Android built with Jetpack Compose and Kotlin. Features modern gameplay mechanics, smooth animations, and a minimalist design aesthetic.

License Platform Kotlin

✨ Features

Core Gameplay

  • Classic Tetris mechanics with all 7 standard tetrominoes
  • 7-bag randomizer prevents long piece droughts
  • Progressive difficulty - speed increases every 10 lines
  • Responsive controls - Touch, swipe, and button support

Advanced Mechanics

  • Ghost Piece - Semi-transparent preview showing landing position
  • Wall Kicks (SRS) - Smart rotation system tests multiple positions
  • Hold Piece - Store a piece for later use (once per drop)
  • Enhanced Scoring:
    • Single: 100 × level
    • Double: 300 × level
    • Triple: 500 × level
    • Tetris: 800 × level
    • Soft drop: +1 per cell
    • Hard drop: +2 per cell

Visual Polish

  • Line clear animation - Flash effect when clearing lines
  • Smooth transitions between screens
  • Animated title screen with falling tetromino background
  • Modern color scheme - Dark theme with vibrant piece colors

User Experience

  • Splash screen with creator credits
  • Title screen with instructions
  • Pause/Resume functionality
  • Game Over screen with final stats
  • Navigation flow - Easy return to main menu

🎮 Controls

Touch Gestures

  • Swipe Left/Right - Move piece horizontally
  • Swipe Down - Soft drop (move down faster)
  • Swipe Up - Hard drop (instant drop to bottom)

Buttons

  • ◄ ► - Move left/right
  • - Soft drop
  • ROTATE - Rotate piece clockwise
  • HOLD - Swap with held piece
  • DROP - Hard drop
  • PAUSE - Pause/Resume game

🏗️ Architecture

Built with clean architecture principles and functional programming patterns:

┌─────────────────┐
│   MainActivity  │  - Entry point, handles screen navigation
└────────┬────────┘
         │
    ┌────▼─────────────────────────────────┐
    │   Screens (Splash/Title/Game)        │  - UI Layer
    └────┬─────────────────────────────────┘
         │
    ┌────▼────────────┐
    │  GameViewModel  │  - State management, coroutines
    └────┬────────────┘
         │
    ┌────▼────────────┐
    │   GameEngine    │  - Pure functions, game logic
    └────┬────────────┘
         │
    ┌────▼────────────────────────────────┐
    │  GameState / Board / Tetromino      │  - Immutable data
    └─────────────────────────────────────┘

Key Design Principles

Immutability - All game state is immutable. Operations return new instances.

Pure Functions - GameEngine contains only pure functions with no side effects:

fun tick(state: GameState): GameState
fun movePiece(state: GameState, deltaCol: Int): GameState
fun rotatePiece(state: GameState): GameState

Separation of Concerns:

  • GameState - Data only, no logic
  • GameEngine - Logic only, no state
  • GameViewModel - Manages state flow and timing
  • UI Layer - Observes state, dispatches actions

Testability - Pure functions make unit testing straightforward without mocks.

📁 Project Structure

app/src/main/java/com/example/simplis/
├── MainActivity.kt
├── game/
│   ├── Board.kt              # Board state and validation
│   ├── GameConstants.kt      # Configuration constants
│   ├── GameEngine.kt         # Pure game logic functions
│   ├── GameState.kt          # Immutable game state
│   ├── GameViewModel.kt      # State management & coroutines
│   ├── Tetromino.kt          # Piece representation
│   └── TetrominoType.kt      # 7 piece definitions
└── ui/
    ├── GameScreen.kt         # Main game UI
    ├── SplashScreen.kt       # Opening splash
    ├── TitleScreen.kt        # Main menu
    ├── ScreenState.kt        # Navigation state
    └── theme/
        ├── Color.kt
        ├── Theme.kt
        └── Type.kt

🛠️ Technical Stack

  • Language: Kotlin 1.9+
  • UI: Jetpack Compose
  • Architecture: MVVM with StateFlow
  • Concurrency: Kotlin Coroutines
  • Build: Gradle with Kotlin DSL
  • Min SDK: 24 (Android 7.0)
  • Target SDK: 34 (Android 14)

Dependencies

// Compose BOM for version management
implementation(platform("androidx.compose:compose-bom:2024.xx.xx"))

// Core Android
implementation("androidx.core:core-ktx")
implementation("androidx.lifecycle:lifecycle-runtime-ktx")
implementation("androidx.activity:activity-compose")

// Compose UI
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")

// ViewModel for Compose
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")

🚀 Building & Running

Prerequisites

  • Android Studio Hedgehog (2023.1.1) or newer
  • JDK 17
  • Android SDK 34

Steps

  1. Clone the repository:
git clone https://github.com/yourusername/simplis.git
cd simplis
  1. Open in Android Studio

  2. Sync Gradle dependencies

  3. Run on emulator or physical device (Android 7.0+)

🎨 Customization

Change Your Name

Edit the creator credits in:

  • SplashScreen.kt (line 48)
  • TitleScreen.kt (line 91)

Adjust Difficulty

Modify GameConstants.kt:

const val INITIAL_DROP_DELAY = 1000L  // Starting speed
const val MIN_DROP_DELAY = 100L       // Maximum speed
const val LEVEL_SPEED_DECREASE = 50L  // Speed increase per level
const val LINES_PER_LEVEL = 10        // Lines needed to level up

Customize Colors

Edit piece colors in TetrominoType.kt:

I(color = Color(0xFF00F0F0)) // Cyan
O(color = Color(0xFFF0F000)) // Yellow
// ... etc

🧪 Testing Strategy

The architecture facilitates comprehensive testing:

Unit Tests - Test pure functions in GameEngine:

@Test
fun `tick moves piece down when space available`() {
    val state = GameState.initial()
    val newState = GameEngine.tick(state)
    assertEquals(state.currentPiece!!.row + 1, newState.currentPiece!!.row)
}

State Tests - Verify immutability:

@Test
fun `board lockPiece returns new instance`() {
    val board = Board.empty()
    val piece = Tetromino.spawn(TetrominoType.I)
    val newBoard = board.lockPiece(piece)
    assertNotSame(board, newBoard)
}

UI Tests - Compose testing tools:

@Test
fun `game over screen shows final score`() {
    composeTestRule.setContent {
        GameOverOverlay(score = 1000, level = 5, {}, {})
    }
    composeTestRule.onNodeWithText("1000").assertIsDisplayed()
}

📈 Performance Considerations

  • Immutable Collections - Structural sharing minimizes copying overhead
  • Canvas Rendering - Direct drawing for 60 FPS gameplay
  • Coroutine-based Game Loop - Non-blocking timing with proper lifecycle management
  • State Flow - Efficient state updates only when changed
  • No Memory Leaks - ViewModel properly cancels coroutines on clear

🎯 Future Enhancements

Potential features for future versions:

  • T-Spin Detection - Bonus points for advanced rotation techniques
  • Combo System - Multiplier for consecutive line clears
  • Lock Delay - Brief pause before piece locks (DAS/ARR)
  • High Score Persistence - Save top scores locally
  • Leaderboard - Online score comparison
  • Sound Effects - Audio feedback for actions
  • Music - Background soundtrack with volume control
  • Themes - Multiple color schemes and visual styles
  • Statistics - Track games played, pieces used, etc.
  • Marathon Mode - Fixed number of lines to clear
  • Sprint Mode - Race against the clock

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

👤 Author

Created by [Your Name]

🙏 Acknowledgments

  • Tetris gameplay mechanics based on the Tetris Guideline
  • SRS (Super Rotation System) for wall kick implementation
  • Jetpack Compose team for the excellent UI toolkit
  • The Android community for libraries and inspiration

Built with ❤️ using Jetpack Compose and Kotlin

About

A Tetris simple (for real) for current Android SDKs

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages