Files
DawnsorrowandCursor 1ae7c24706 Initial Hex Mines fork with hex tiles and mine-count slider.
Based on StefanOltmann/mines (AGPL-3.0): flat-top hex grid, configurable
board size, and a mine-count slider replacing fixed difficulty presets.

Co-authored-by: Cursor <[email protected]>
2026-07-29 07:32:33 -05:00

6.3 KiB

Mines Project Development Guidelines

This document provides essential information for developers working on the Mines project.

Build/Configuration Instructions

Project Overview

Mines is a KMP Minesweeper clone with Compose Multiplatform for UI targeting Android, JVM (Desktop), and WebAssembly JS (Browser).

Prerequisites

  • JDK 11 (for Android compatibility)
  • Android SDK (for Android builds)
  • Latest Gradle version

Building the Project

For all platforms: ./gradlew build

Platform-specific builds:

  • Android: ./gradlew assembleDebug or ./gradlew assembleRelease
  • Desktop: ./gradlew packageDistributionForCurrentOS
  • Web: ./gradlew wasmJsBrowserDistribution

Running the Application

  • Android: Use IntelliJ IDEA with Android plugin or ./gradlew installDebug
  • Desktop: ./gradlew run
  • Web: ./gradlew wasmJsBrowserRun

Testing Information

Test Structure

The project follows Kotlin Multiplatform conventions:

  • commonTest: Platform-independent tests
  • jvmTest: JVM-specific tests
  • androidTest: Android-specific tests
  • wasmJsTest: WebAssembly JS-specific tests

Note: Desktop (JVM) is the primary development platform.

Running Tests

All tests: ./gradlew allTests

Platform-specific tests:

  • JVM: ./gradlew jvmTest
  • Android: ./gradlew androidTest
  • WebAssembly JS: ./gradlew wasmJsTest

Specific test: ./gradlew test --tests "de.stefan_oltmann.mines.model.GameDifficultyTest"

Important: Place all logic/non-UI tests in commonTest and test with ./gradlew jvmTest. No need to run androidTest or wasmJsTest if jvmTest passes.

Adding New Tests

  1. Create a test file in the appropriate directory:

    • Common: app/src/commonTest/kotlin/de/stefan_oltmann/mines/...
    • JVM: app/src/jvmTest/kotlin/de/stefan_oltmann/mines/...
    • Android: app/src/androidTest/kotlin/de/stefan_oltmann/mines/...
    • WebAssembly JS: app/src/wasmJsTest/kotlin/de/stefan_oltmann/mines/...
  2. Use the Kotlin Test framework:

    class MyTest {
        @Test
        fun testSomething() {
            assertEquals(expected, actual)
        }
    }
    
  3. Configure dependencies in app/build.gradle.kts:

    commonTest.dependencies {
        implementation(libs.kotlin.test)
    }
    jvmTest.dependencies {
        implementation(libs.kotlin.test.junit)
    }
    

Compose UI Testing

Use Compose Desktop UI testing framework (not Android UI testing).

Setup:

  1. Add dependencies:

    jvmTest.dependencies {
        implementation(compose.desktop.uiTestJUnit4)
        implementation(compose.desktop.currentOs)
    }
    
  2. Create UI tests in jvmTest:

    class MyComposeUiTest {
        @get:Rule
        val composeTestRule = createComposeRule()
    
        @Test
        fun testMyComposable() {
            composeTestRule.setContent {
                MyComposable()
            }
            /* Verify UI elements */
            composeTestRule.onNodeWithText("Expected Text").assertIsDisplayed()
            /* Perform actions */
            composeTestRule.onNodeWithContentDescription("Button").performClick()
            /* Verify state changes */
            composeTestRule.onNodeWithText("Updated Text").assertIsDisplayed()
        }
    }
    

For details: Compose Desktop UI Testing documentation

Example Test

class GameDifficultyTest {
    @Test
    fun testCalcMineCount() {

        /* Test EASY difficulty (10%) */
        assertEquals(1, GameDifficulty.EASY.calcMineCount(3, 3))
        assertEquals(4, GameDifficulty.EASY.calcMineCount(10, 4))

        /* Test MEDIUM difficulty (15%) */
        assertEquals(1, GameDifficulty.MEDIUM.calcMineCount(3, 3))
        assertEquals(6, GameDifficulty.MEDIUM.calcMineCount(10, 4))

        /* Test HARD difficulty (20%) */
        assertEquals(1, GameDifficulty.HARD.calcMineCount(3, 3))
        assertEquals(8, GameDifficulty.HARD.calcMineCount(10, 4))
    }
}

Additional Development Information

Project Structure

  • app/src/commonMain: Shared code for all platforms
  • app/src/androidMain: Android-specific code
  • app/src/jvmMain: Desktop-specific code
  • app/src/wasmJsMain: WebAssembly JS-specific code

Key Components

  • GameConfig: Configuration (cell size, map dimensions, difficulty)
  • GameDifficulty: Difficulty levels (EASY, MEDIUM, HARD)
  • GameState: Game state management

Versioning

Uses androidGitVersion plugin with version numbers derived from Git tags.

Code Style

Follow Clean Code practices and official Kotlin conventions plus these rules:

  1. Indentation and Spacing

    • 4 spaces indentation, 120 character line limit
    • No braces for single-line if statements
    • Use blank lines to separate logical blocks
    • No consecutive blank lines
    • Add blank line before if/for/while statements
    • Don't separate consecutive assert statements
    • Add blank line between function signature and body for multi-line functions
    • Example:
      fun calculateValue(param1: Int, param2: Int): Int {
      
          val result = param1 + param2
      
          return result
      }
      
  2. Naming Conventions

    • Constants: UPPER_SNAKE_CASE with const val
    • Classes: PascalCase
    • Functions/variables: camelCase
    • Packages: lowercase.with.dots
  3. Imports: Alphabetical order, no wildcards

  4. Function Formatting: Align parameters in multi-line declarations, use trailing commas

  5. Type Declarations: Explicit types for public APIs

  6. Braces: Opening at line end, closing on own line, use braces for multi-line bodies only

  7. String Templates: Prefer "Value: $value" over concatenation

  8. Documentation: KDoc format for all public APIs

  9. Forbidden Practices

    • No print/println (use logger)
    • Don't remove TODO/FIXME/STOPSHIP comments unless resolved
    • No magic numbers
  10. Comment Style

    • Use only block comments (/* */), never line comments (//)
    • Align stars in multi-line comments
    • Each file needs license header as block comment

Dependencies Management

Managed in gradle/libs.versions.toml using Gradle's version catalog.

UI Framework

Compose Multiplatform for UI. No platform-specific UI libraries.

Final Checks

  • Ensure code compiles and tests pass
  • Remove unused code and imports