From 3bca0447008523e638e0c4744062a1811c01bf8e Mon Sep 17 00:00:00 2001 From: Teodor Grigor Date: Wed, 4 Sep 2024 18:09:10 +0300 Subject: [PATCH] Refactor Codebase with explicitApi() and applyDefaultHierarchyTemplate, Add Compiler Options for Opt-In --- build.gradle.kts | 8 + demo/composeApp/api/android/composeApp.api | 161 ++++++++++++++++++ demo/composeApp/api/desktop/composeApp.api | 159 +++++++++++++++++ .../dev/teogor/sudoklify/multiplatform/App.kt | 7 +- .../multiplatform/SudokuGameViewModel.kt | 13 +- sudoklify-common/build.gradle.kts | 6 + .../sudoklify/ExperimentalSudoklifyApi.kt | 6 +- .../teogor/sudoklify/InternalSudoklifyApi.kt | 8 +- .../dev/teogor/sudoklify/SudoklifyDsl.kt | 2 +- .../sudoklify/components/BoxCoordinates.kt | 27 ++- .../sudoklify/components/CellCoordinates.kt | 16 +- .../teogor/sudoklify/components/Difficulty.kt | 12 +- .../teogor/sudoklify/components/Dimension.kt | 114 +++++-------- .../dev/teogor/sudoklify/components/Seed.kt | 20 +-- .../sudoklify/components/DimensionTest.kt | 2 - sudoklify-core/api/sudoklify-core.api | 1 - sudoklify-core/build.gradle.kts | 8 +- .../teogor/sudoklify/SudoklifyArchitect.kt | 23 ++- .../teogor/sudoklify/SudoklifyAssembler.kt | 41 ++--- .../dev/teogor/sudoklify/SudokuConversions.kt | 12 +- .../sudoklify/SudokuLayoutManipulator.kt | 12 +- .../dev/teogor/sudoklify/SudokuTokenMapper.kt | 10 +- .../teogor/sudoklify/puzzle/SudokuPuzzle.kt | 13 +- .../dev/teogor/sudoklify/puzzle/SudokuSpec.kt | 47 +++-- .../teogor/sudoklify/random/SeededRandom.kt | 16 +- .../teogor/sudoklify/schema/SudokuSchema.kt | 43 ++--- .../teogor/sudoklify/schema/SudokuSchemas.kt | 68 ++++---- .../teogor/sudoklify/util/BoardConversions.kt | 4 +- .../sudoklify/SudoklifyArchitectTest.kt | 1 - .../sudoklify/SudoklifyAssemblerTest.kt | 1 - .../teogor/sudoklify/SudokuConversionsTest.kt | 2 +- .../sudoklify/puzzle/SudokuPuzzleTest.kt | 2 - .../teogor/sudoklify/puzzle/SudokuSpecTest.kt | 2 - .../sudoklify/schema/SudokuSchemaTest.kt | 2 - .../sudoklify/schema/SudokuSchemasTest.kt | 2 - sudoklify-io/api/sudoklify-io.api | 4 - sudoklify-io/build.gradle.kts | 6 + .../teogor/sudoklify/io/BoardSerialization.kt | 2 +- .../dev/teogor/sudoklify/io/SudokuParser.kt | 13 +- sudoklify-presets/build.gradle.kts | 6 + .../sudoklify/presets/FourDigitsSchemas.kt | 5 +- .../sudoklify/presets/NineDigitsSchemas.kt | 5 +- .../teogor/sudoklify/presets/PresetSchemas.kt | 2 +- .../sudoklify/presets/SixteenDigitsSchemas.kt | 5 +- .../presets/TwentyFiveDigitsSchemas.kt | 5 +- .../sudoklify/presets/PresetSchemasTest.kt | 6 +- sudoklify-solver/build.gradle.kts | 6 + .../sudoklify/solver/GridMistakeChecker.kt | 9 +- .../sudoklify/solver/MistakeCheckingMode.kt | 2 +- .../sudoklify/solver/SudoklifyMoveAdvisor.kt | 7 +- .../sudoklify/solver/SudoklifySolverEngine.kt | 21 +-- .../sudoklify/solver/SudokuCellState.kt | 6 +- .../sudoklify/solver/SudokuGridProcessor.kt | 19 +-- .../dev/teogor/sudoklify/solver/SudokuMove.kt | 2 +- .../sudoklify/solver/SudokuCellStateTest.kt | 2 - sudoklify-tokenizer/build.gradle.kts | 6 + .../sudoklify/tokenizer/JEncodedCell.kt | 18 +- .../dev/teogor/sudoklify/tokenizer/Layout.kt | 2 +- .../sudoklify/tokenizer/SudokuString.kt | 8 +- .../teogor/sudoklify/tokenizer/TokenMap.kt | 2 +- .../teogor/sudoklify/tokenizer/Tokenizer.kt | 17 +- .../sudoklify/tokenizer/JEncodedCellTest.kt | 1 - 62 files changed, 647 insertions(+), 411 deletions(-) create mode 100644 demo/composeApp/api/android/composeApp.api create mode 100644 demo/composeApp/api/desktop/composeApp.api diff --git a/build.gradle.kts b/build.gradle.kts index c8670c5..1b37a06 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -179,6 +179,14 @@ apiValidation { * Subprojects that are excluded from API validation */ ignoredProjects.addAll(excludedProjects.map { it.name }) + + /** + * Non-public markers that are excluded from API validation + */ + nonPublicMarkers.addAll(listOf( + "dev.teogor.sudoklify.ExperimentalSudoklifyApi", + "dev.teogor.sudoklify.InternalSudoklifyApi" + )) } subprojects { diff --git a/demo/composeApp/api/android/composeApp.api b/demo/composeApp/api/android/composeApp.api new file mode 100644 index 0000000..a545eb3 --- /dev/null +++ b/demo/composeApp/api/android/composeApp.api @@ -0,0 +1,161 @@ +public final class dev/teogor/sudoklify/multiplatform/AppKt { + public static final fun App (Ldev/teogor/sudoklify/multiplatform/SudokuGameViewModel;Landroidx/compose/runtime/Composer;II)V +} + +public final class dev/teogor/sudoklify/multiplatform/Cell { + public static final field $stable I + public fun (IZZIII)V + public final fun component1 ()I + public final fun component2 ()Z + public final fun component3 ()Z + public final fun component4 ()I + public final fun component5 ()I + public final fun component6 ()I + public final fun copy (IZZIII)Ldev/teogor/sudoklify/multiplatform/Cell; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/Cell;IZZIIIILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/Cell; + public fun equals (Ljava/lang/Object;)Z + public final fun getCol ()I + public final fun getRow ()I + public final fun getSolution ()I + public final fun getValue ()I + public fun hashCode ()I + public final fun isError ()Z + public final fun isGiven ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/Cell$Position { + public static final field $stable I + public fun (II)V + public final fun component1 ()I + public final fun component2 ()I + public final fun copy (II)Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/Cell$Position;IIILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public fun equals (Ljava/lang/Object;)Z + public final fun getCol ()I + public final fun getRow ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/ComposableSingletons$AppKt { + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/ComposableSingletons$AppKt; + public static field lambda-1 Lkotlin/jvm/functions/Function3; + public fun ()V + public final fun getLambda-1$composeApp_release ()Lkotlin/jvm/functions/Function3; +} + +public final class dev/teogor/sudoklify/multiplatform/ComposableSingletons$MainActivityKt { + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/ComposableSingletons$MainActivityKt; + public static field lambda-1 Lkotlin/jvm/functions/Function2; + public fun ()V + public final fun getLambda-1$composeApp_release ()Lkotlin/jvm/functions/Function2; +} + +public final class dev/teogor/sudoklify/multiplatform/ComposableSingletons$SudokuBoardKt { + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/ComposableSingletons$SudokuBoardKt; + public static field lambda-1 Lkotlin/jvm/functions/Function2; + public fun ()V + public final fun getLambda-1$composeApp_release ()Lkotlin/jvm/functions/Function2; +} + +public abstract class dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Active : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$Active; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Completed : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public fun (Z)V + public final fun component1 ()Z + public final fun copy (Z)Ldev/teogor/sudoklify/multiplatform/GameState$Completed; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/GameState$Completed;ZILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/GameState$Completed; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public final fun isWon ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Loading : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$Loading; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$NotStarted : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$NotStarted; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Paused : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$Paused; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/MainActivity : androidx/activity/ComponentActivity { + public static final field $stable I + public fun ()V +} + +public final class dev/teogor/sudoklify/multiplatform/MainActivityKt { + public static final fun AppAndroidPreview (Landroidx/compose/runtime/Composer;I)V +} + +public final class dev/teogor/sudoklify/multiplatform/SudokuBoardKt { + public static final fun SudokuBoard (Ldev/teogor/sudoklify/components/Dimension;Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V + public static final fun SudokuCell (Ldev/teogor/sudoklify/multiplatform/Cell;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;II)V +} + +public final class dev/teogor/sudoklify/multiplatform/SudokuGameState { + public static final field $stable I + public fun (Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Ljava/util/List;Z)V + public final fun component1 ()Ljava/util/List; + public final fun component2 ()Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public final fun component3 ()Ljava/util/List; + public final fun component4 ()Z + public final fun copy (Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Ljava/util/List;Z)Ldev/teogor/sudoklify/multiplatform/SudokuGameState; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/SudokuGameState;Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Ljava/util/List;ZILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/SudokuGameState; + public fun equals (Ljava/lang/Object;)Z + public final fun getGrid ()Ljava/util/List; + public final fun getMistakes ()Ljava/util/List; + public final fun getSelectedCell ()Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public fun hashCode ()I + public final fun isSolved ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/SudokuGameViewModel : androidx/lifecycle/ViewModel { + public static final field $stable I + public field sudokuPuzzle Ldev/teogor/sudoklify/puzzle/SudokuPuzzle; + public field sudokuSolver Ldev/teogor/sudoklify/solver/SudoklifySolverEngine; + public field sudokuSpec Ldev/teogor/sudoklify/puzzle/SudokuSpec; + public fun ()V + public final fun generateSudoku (Ldev/teogor/sudoklify/components/Dimension;Ldev/teogor/sudoklify/components/Difficulty;Ldev/teogor/sudoklify/components/Seed;)V + public final fun getGameState ()Lkotlinx/coroutines/flow/StateFlow; + public final fun getSudokuGameState ()Lkotlinx/coroutines/flow/StateFlow; + public final fun getSudokuPuzzle ()Ldev/teogor/sudoklify/puzzle/SudokuPuzzle; + public final fun getSudokuSolver ()Ldev/teogor/sudoklify/solver/SudoklifySolverEngine; + public final fun getSudokuSpec ()Ldev/teogor/sudoklify/puzzle/SudokuSpec; + public final fun makeMove (III)V + public final fun resetGame ()V + public final fun selectCell (II)V + public final fun setSudokuPuzzle (Ldev/teogor/sudoklify/puzzle/SudokuPuzzle;)V + public final fun setSudokuSolver (Ldev/teogor/sudoklify/solver/SudoklifySolverEngine;)V + public final fun setSudokuSpec (Ldev/teogor/sudoklify/puzzle/SudokuSpec;)V +} + diff --git a/demo/composeApp/api/desktop/composeApp.api b/demo/composeApp/api/desktop/composeApp.api new file mode 100644 index 0000000..4aec11a --- /dev/null +++ b/demo/composeApp/api/desktop/composeApp.api @@ -0,0 +1,159 @@ +public final class dev/teogor/sudoklify/multiplatform/AppKt { + public static final fun App (Ldev/teogor/sudoklify/multiplatform/SudokuGameViewModel;Landroidx/compose/runtime/Composer;II)V +} + +public final class dev/teogor/sudoklify/multiplatform/Cell { + public static final field $stable I + public fun (IZZIII)V + public final fun component1 ()I + public final fun component2 ()Z + public final fun component3 ()Z + public final fun component4 ()I + public final fun component5 ()I + public final fun component6 ()I + public final fun copy (IZZIII)Ldev/teogor/sudoklify/multiplatform/Cell; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/Cell;IZZIIIILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/Cell; + public fun equals (Ljava/lang/Object;)Z + public final fun getCol ()I + public final fun getRow ()I + public final fun getSolution ()I + public final fun getValue ()I + public fun hashCode ()I + public final fun isError ()Z + public final fun isGiven ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/Cell$Position { + public static final field $stable I + public fun (II)V + public final fun component1 ()I + public final fun component2 ()I + public final fun copy (II)Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/Cell$Position;IIILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public fun equals (Ljava/lang/Object;)Z + public final fun getCol ()I + public final fun getRow ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/ComposableSingletons$AppKt { + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/ComposableSingletons$AppKt; + public static field lambda-1 Lkotlin/jvm/functions/Function3; + public fun ()V + public final fun getLambda-1$composeApp ()Lkotlin/jvm/functions/Function3; +} + +public final class dev/teogor/sudoklify/multiplatform/ComposableSingletons$MainKt { + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/ComposableSingletons$MainKt; + public static field lambda-1 Lkotlin/jvm/functions/Function3; + public static field lambda-2 Lkotlin/jvm/functions/Function3; + public fun ()V + public final fun getLambda-1$composeApp ()Lkotlin/jvm/functions/Function3; + public final fun getLambda-2$composeApp ()Lkotlin/jvm/functions/Function3; +} + +public final class dev/teogor/sudoklify/multiplatform/ComposableSingletons$SudokuBoardKt { + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/ComposableSingletons$SudokuBoardKt; + public static field lambda-1 Lkotlin/jvm/functions/Function2; + public fun ()V + public final fun getLambda-1$composeApp ()Lkotlin/jvm/functions/Function2; +} + +public abstract class dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Active : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$Active; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Completed : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public fun (Z)V + public final fun component1 ()Z + public final fun copy (Z)Ldev/teogor/sudoklify/multiplatform/GameState$Completed; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/GameState$Completed;ZILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/GameState$Completed; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public final fun isWon ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Loading : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$Loading; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$NotStarted : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$NotStarted; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/GameState$Paused : dev/teogor/sudoklify/multiplatform/GameState { + public static final field $stable I + public static final field INSTANCE Ldev/teogor/sudoklify/multiplatform/GameState$Paused; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/MainKt { + public static final fun main ()V + public static synthetic fun main ([Ljava/lang/String;)V +} + +public final class dev/teogor/sudoklify/multiplatform/SudokuBoardKt { + public static final fun SudokuBoard (Ldev/teogor/sudoklify/components/Dimension;Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V + public static final fun SudokuCell (Ldev/teogor/sudoklify/multiplatform/Cell;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;II)V +} + +public final class dev/teogor/sudoklify/multiplatform/SudokuGameState { + public static final field $stable I + public fun (Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Ljava/util/List;Z)V + public final fun component1 ()Ljava/util/List; + public final fun component2 ()Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public final fun component3 ()Ljava/util/List; + public final fun component4 ()Z + public final fun copy (Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Ljava/util/List;Z)Ldev/teogor/sudoklify/multiplatform/SudokuGameState; + public static synthetic fun copy$default (Ldev/teogor/sudoklify/multiplatform/SudokuGameState;Ljava/util/List;Ldev/teogor/sudoklify/multiplatform/Cell$Position;Ljava/util/List;ZILjava/lang/Object;)Ldev/teogor/sudoklify/multiplatform/SudokuGameState; + public fun equals (Ljava/lang/Object;)Z + public final fun getGrid ()Ljava/util/List; + public final fun getMistakes ()Ljava/util/List; + public final fun getSelectedCell ()Ldev/teogor/sudoklify/multiplatform/Cell$Position; + public fun hashCode ()I + public final fun isSolved ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/teogor/sudoklify/multiplatform/SudokuGameViewModel : androidx/lifecycle/ViewModel { + public static final field $stable I + public field sudokuPuzzle Ldev/teogor/sudoklify/puzzle/SudokuPuzzle; + public field sudokuSolver Ldev/teogor/sudoklify/solver/SudoklifySolverEngine; + public field sudokuSpec Ldev/teogor/sudoklify/puzzle/SudokuSpec; + public fun ()V + public final fun generateSudoku (Ldev/teogor/sudoklify/components/Dimension;Ldev/teogor/sudoklify/components/Difficulty;Ldev/teogor/sudoklify/components/Seed;)V + public final fun getGameState ()Lkotlinx/coroutines/flow/StateFlow; + public final fun getSudokuGameState ()Lkotlinx/coroutines/flow/StateFlow; + public final fun getSudokuPuzzle ()Ldev/teogor/sudoklify/puzzle/SudokuPuzzle; + public final fun getSudokuSolver ()Ldev/teogor/sudoklify/solver/SudoklifySolverEngine; + public final fun getSudokuSpec ()Ldev/teogor/sudoklify/puzzle/SudokuSpec; + public final fun makeMove (III)V + public final fun resetGame ()V + public final fun selectCell (II)V + public final fun setSudokuPuzzle (Ldev/teogor/sudoklify/puzzle/SudokuPuzzle;)V + public final fun setSudokuSolver (Ldev/teogor/sudoklify/solver/SudoklifySolverEngine;)V + public final fun setSudokuSpec (Ldev/teogor/sudoklify/puzzle/SudokuSpec;)V +} + diff --git a/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/App.kt b/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/App.kt index 4518068..ec04fad 100644 --- a/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/App.kt +++ b/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/App.kt @@ -34,11 +34,9 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewmodel.compose.viewModel import dev.teogor.paletteon.PaletteonDynamicTheme import dev.teogor.paletteon.ui.components.PaletteonThemedSurface -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.components.Seed @@ -49,13 +47,10 @@ import org.jetbrains.compose.ui.tooling.preview.Preview * * @param sudokuGameViewModel The ViewModel managing the game state and logic. Defaults to a new instance. */ -@OptIn(ExperimentalSudoklifyApi::class) @Composable @Preview fun App( - sudokuGameViewModel: SudokuGameViewModel = viewModel { - SudokuGameViewModel(SavedStateHandle()) - }, + sudokuGameViewModel: SudokuGameViewModel = viewModel { SudokuGameViewModel() }, ) { PaletteonDynamicTheme( seedColor = Color.Magenta, diff --git a/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/SudokuGameViewModel.kt b/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/SudokuGameViewModel.kt index 360e696..8e5f9b2 100644 --- a/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/SudokuGameViewModel.kt +++ b/demo/composeApp/src/commonMain/kotlin/dev/teogor/sudoklify/multiplatform/SudokuGameViewModel.kt @@ -16,9 +16,7 @@ package dev.teogor.sudoklify.multiplatform -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.SudoklifyArchitect import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension @@ -37,13 +35,8 @@ import kotlinx.coroutines.flow.update /** * ViewModel responsible for managing the state of the Sudoku game. - * - * @param savedStateHandle The handle for saving and restoring the state. */ -@OptIn(ExperimentalSudoklifyApi::class) -class SudokuGameViewModel( - savedStateHandle: SavedStateHandle, -) : ViewModel() { +class SudokuGameViewModel : ViewModel() { private val architect = SudoklifyArchitect(loadPresetSchemas()) private val _gameState = MutableStateFlow(GameState.NotStarted) @@ -63,10 +56,6 @@ class SudokuGameViewModel( lateinit var sudokuPuzzle: SudokuPuzzle lateinit var sudokuSolver: SudoklifySolverEngine - init { - _gameState.value = GameState.Loading - } - /** * Generates a new Sudoku puzzle based on the provided dimension, difficulty, and seed. * diff --git a/sudoklify-common/build.gradle.kts b/sudoklify-common/build.gradle.kts index 1847f05..d8266a7 100644 --- a/sudoklify-common/build.gradle.kts +++ b/sudoklify-common/build.gradle.kts @@ -31,6 +31,10 @@ winds { } kotlin { + explicitApi() + + applyDefaultHierarchyTemplate() + jvm { kotlin { jvmToolchain(11) @@ -80,5 +84,7 @@ kotlin { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { freeCompilerArgs.add("-Xexpect-actual-classes") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.InternalSudoklifyApi") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.ExperimentalSudoklifyApi") } } diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/ExperimentalSudoklifyApi.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/ExperimentalSudoklifyApi.kt index 665f0a2..98a5724 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/ExperimentalSudoklifyApi.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/ExperimentalSudoklifyApi.kt @@ -19,7 +19,7 @@ package dev.teogor.sudoklify @Retention(AnnotationRetention.BINARY) @RequiresOptIn( message = - "This API is experimental and subject to change in future Sudoklify versions. " + - "Use with caution and be prepared to adapt your code if the API changes.", + "This API is experimental and subject to change in future Sudoklify versions. " + + "Use with caution and be prepared to adapt your code if the API changes.", ) -annotation class ExperimentalSudoklifyApi +public annotation class ExperimentalSudoklifyApi diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/InternalSudoklifyApi.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/InternalSudoklifyApi.kt index 13e5d1c..ea1d073 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/InternalSudoklifyApi.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/InternalSudoklifyApi.kt @@ -18,9 +18,9 @@ package dev.teogor.sudoklify @RequiresOptIn( message = - "This API is for internal use only within the Sudoklify library. " + - "Using it in external code can lead to unexpected behavior or breakage in future Sudoklify " + - "versions.", + "This API is for internal use only within the Sudoklify library. " + + "Using it in external code can lead to unexpected behavior or breakage in future Sudoklify " + + "versions.", ) @Retention(AnnotationRetention.BINARY) -annotation class InternalSudoklifyApi +public annotation class InternalSudoklifyApi diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyDsl.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyDsl.kt index c9f7b2c..2b50b40 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyDsl.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyDsl.kt @@ -17,4 +17,4 @@ package dev.teogor.sudoklify @DslMarker -annotation class SudoklifyDsl +public annotation class SudoklifyDsl diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/BoxCoordinates.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/BoxCoordinates.kt index 0449129..e0c79e8 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/BoxCoordinates.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/BoxCoordinates.kt @@ -14,12 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.components -import dev.teogor.sudoklify.ExperimentalSudoklifyApi - /** * Data class representing the coordinates of a box in a Sudoku grid. * @@ -37,7 +33,7 @@ import dev.teogor.sudoklify.ExperimentalSudoklifyApi * @property topLeft A tuple representing the top-left cell coordinates (row, column). * @property bottomRight A tuple representing the bottom-right cell coordinates (row, column). This takes into account the height and width of the box. */ -data class BoxCoordinates( +public data class BoxCoordinates( val topLeftRow: Int, val topLeftCol: Int, val bottomRightRow: Int, @@ -81,7 +77,7 @@ data class BoxCoordinates( * @param col The column index of the cell to check. * @return `true` if the cell is within the box; otherwise, `false`. */ -fun BoxCoordinates.contains( +public fun BoxCoordinates.contains( row: Int, col: Int, ): Boolean { @@ -95,7 +91,7 @@ fun BoxCoordinates.contains( * @param colExpansion The number of additional columns to add to the box. * @return A new [BoxCoordinates] instance with the expanded dimensions. */ -fun BoxCoordinates.expand( +public fun BoxCoordinates.expand( rowExpansion: Int, colExpansion: Int, ): BoxCoordinates { @@ -112,7 +108,7 @@ fun BoxCoordinates.expand( * * @return A string representing the box coordinates. */ -fun BoxCoordinates.toFormattedString(): String { +public fun BoxCoordinates.toFormattedString(): String { return buildString { append("Box Coordinates:\n") append(" Top-Left: ($topLeftRow, $topLeftCol)\n") @@ -128,7 +124,7 @@ fun BoxCoordinates.toFormattedString(): String { * @param other The other box to intersect with. * @return A new [BoxCoordinates] instance representing the intersection of the two boxes, or `null` if they do not intersect. */ -fun BoxCoordinates.intersect(other: BoxCoordinates): BoxCoordinates? { +public fun BoxCoordinates.intersect(other: BoxCoordinates): BoxCoordinates? { val intersectTopLeftRow = maxOf(this.topLeftRow, other.topLeftRow) val intersectTopLeftCol = maxOf(this.topLeftCol, other.topLeftCol) val intersectBottomRightRow = minOf(this.bottomRightRow, other.bottomRightRow) @@ -154,7 +150,7 @@ fun BoxCoordinates.intersect(other: BoxCoordinates): BoxCoordinates? { * @param dimension The dimension of the Sudoku grid. * @return `true` if the box is in the top-left corner; otherwise, `false`. */ -fun BoxCoordinates.isTopStart(dimension: Dimension): Boolean { +public fun BoxCoordinates.isTopStart(dimension: Dimension): Boolean { return topLeftRow == 0 && topLeftCol == 0 } @@ -164,7 +160,7 @@ fun BoxCoordinates.isTopStart(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the box is in the top-right corner; otherwise, `false`. */ -fun BoxCoordinates.isTopEnd(dimension: Dimension): Boolean { +public fun BoxCoordinates.isTopEnd(dimension: Dimension): Boolean { return topLeftRow == 0 && bottomRightCol == dimension.width - 1 } @@ -174,7 +170,7 @@ fun BoxCoordinates.isTopEnd(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the box is in the bottom-left corner; otherwise, `false`. */ -fun BoxCoordinates.isBottomStart(dimension: Dimension): Boolean { +public fun BoxCoordinates.isBottomStart(dimension: Dimension): Boolean { return bottomRightRow == dimension.height - 1 && topLeftCol == 0 } @@ -184,7 +180,7 @@ fun BoxCoordinates.isBottomStart(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the box is in the bottom-right corner; otherwise, `false`. */ -fun BoxCoordinates.isBottomEnd(dimension: Dimension): Boolean { +public fun BoxCoordinates.isBottomEnd(dimension: Dimension): Boolean { return bottomRightRow == dimension.height - 1 && bottomRightCol == dimension.width - 1 } @@ -194,9 +190,10 @@ fun BoxCoordinates.isBottomEnd(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the box should have a darker background; otherwise, `false`. */ -fun BoxCoordinates.isAlternateBox(dimension: Dimension): Boolean { +public fun BoxCoordinates.isAlternateBox(dimension: Dimension): Boolean { // Compute the box index based on its position - val boxIndex = (topLeftRow / dimension.boxHeight) * (dimension.width / dimension.boxWidth) + (topLeftCol / dimension.boxWidth) + val boxIndex = + (topLeftRow / dimension.boxHeight) * (dimension.width / dimension.boxWidth) + (topLeftCol / dimension.boxWidth) // Use modulo operation to alternate the style return boxIndex % 2 == 1 diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/CellCoordinates.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/CellCoordinates.kt index 97e0c14..e2fd8cd 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/CellCoordinates.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/CellCoordinates.kt @@ -14,12 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.components -import dev.teogor.sudoklify.ExperimentalSudoklifyApi - /** * Data class representing the coordinates of a cell in a Sudoku grid. * @@ -30,7 +26,7 @@ import dev.teogor.sudoklify.ExperimentalSudoklifyApi * * @property position A tuple representing the cell coordinates (row, column). */ -data class CellCoordinates( +public data class CellCoordinates( val row: Int, val col: Int, ) { @@ -48,7 +44,7 @@ data class CellCoordinates( * @param dimension The dimension of the Sudoku grid. * @return `true` if the cell is in the top-start corner; otherwise, `false`. */ -fun CellCoordinates.isTopStart(dimension: Dimension): Boolean { +public fun CellCoordinates.isTopStart(dimension: Dimension): Boolean { return row == 0 && col == 0 } @@ -58,7 +54,7 @@ fun CellCoordinates.isTopStart(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the cell is in the top-end corner; otherwise, `false`. */ -fun CellCoordinates.isTopEnd(dimension: Dimension): Boolean { +public fun CellCoordinates.isTopEnd(dimension: Dimension): Boolean { return row == 0 && col == dimension.width - 1 } @@ -68,7 +64,7 @@ fun CellCoordinates.isTopEnd(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the cell is in the bottom-start corner; otherwise, `false`. */ -fun CellCoordinates.isBottomStart(dimension: Dimension): Boolean { +public fun CellCoordinates.isBottomStart(dimension: Dimension): Boolean { return row == dimension.height - 1 && col == 0 } @@ -78,7 +74,7 @@ fun CellCoordinates.isBottomStart(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the cell is in the bottom-end corner; otherwise, `false`. */ -fun CellCoordinates.isBottomEnd(dimension: Dimension): Boolean { +public fun CellCoordinates.isBottomEnd(dimension: Dimension): Boolean { return row == dimension.height - 1 && col == dimension.width - 1 } @@ -88,7 +84,7 @@ fun CellCoordinates.isBottomEnd(dimension: Dimension): Boolean { * @param dimension The dimension of the Sudoku grid. * @return `true` if the cell should have an alternate style; otherwise, `false`. */ -fun CellCoordinates.isAlternateCell(dimension: Dimension): Boolean { +public fun CellCoordinates.isAlternateCell(dimension: Dimension): Boolean { // Compute the cell index based on its position val cellIndex = row * dimension.width + col diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Difficulty.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Difficulty.kt index f1397a1..06d194e 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Difficulty.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Difficulty.kt @@ -35,7 +35,7 @@ package dev.teogor.sudoklify.components * | HARD | 0-20 | 20-40 | No | These puzzles are designed to challenge even the most experienced solvers and require advanced Sudoku techniques. | * | VERY_HARD | 0-10 | 10-20 | No | These puzzles are the most difficult to solve and are intended only for Sudoku experts, requiring extreme patience and logical reasoning. | */ -enum class Difficulty { +public enum class Difficulty { /** * Indicates an easy Sudoku puzzle with a large number of clues. */ @@ -67,7 +67,7 @@ enum class Difficulty { * * @return A string representation of the difficulty level using stars. */ -fun Difficulty.toStars(): String { +public fun Difficulty.toStars(): String { return "★".repeat(ordinal + 1) } @@ -83,7 +83,7 @@ fun Difficulty.toStars(): String { * @throws DifficultyLabelOutOfBoundsException if the ordinal is out of bounds * for the provided labels array. */ -fun Difficulty.toLabel(labels: Array): String { +public fun Difficulty.toLabel(labels: Array): String { require(ordinal < labels.size) { throw DifficultyLabelOutOfBoundsException(ordinal, labels.size) } @@ -98,9 +98,9 @@ fun Difficulty.toLabel(labels: Array): String { * @param index The index that was out of bounds. * @param labelsSize The size of the labels array. */ -class DifficultyLabelOutOfBoundsException( +public class DifficultyLabelOutOfBoundsException( index: Int, labelsSize: Int, ) : IndexOutOfBoundsException( - "Difficulty index $index is out of bounds for labels array of size $labelsSize.", - ) + "Difficulty index $index is out of bounds for labels array of size $labelsSize.", +) diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Dimension.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Dimension.kt index 756eb1b..a0ada68 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Dimension.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Dimension.kt @@ -14,12 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.components -import dev.teogor.sudoklify.ExperimentalSudoklifyApi - /** * Sealed class representing different Sudoku dimensions with varying grid sizes. * @@ -34,16 +30,15 @@ import dev.teogor.sudoklify.ExperimentalSudoklifyApi * @property boxHeight The height of a single box in the grid. * @property name A human-readable name for the Sudoku dimension (e.g., "4x4"). */ -@ExperimentalSudoklifyApi -sealed class Dimension( - val gridSize: GridSize, +public sealed class Dimension( + public val gridSize: GridSize, ) { /** * The number of distinct digits used in the Sudoku grid. This represents the total * number of unique symbols that can be placed within a single cell of the Sudoku. * It is calculated as the product of the grid width and height. */ - val uniqueDigitsCount: Int = gridSize.width * gridSize.height + public val uniqueDigitsCount: Int = gridSize.width * gridSize.height @Deprecated( message = """Consider using 'uniqueDigitsCount' for better clarity. This variable provides @@ -51,14 +46,14 @@ sealed class Dimension( |grid.""", replaceWith = ReplaceWith("uniqueDigitsCount"), ) - val digits: Int = uniqueDigitsCount + public val digits: Int = uniqueDigitsCount /** * The total number of cells in the Sudoku grid. This is calculated by squaring the * [uniqueDigitsCount]. Each cell within the grid can hold one of the [uniqueDigitsCount] * distinct digits (or symbols). */ - val totalCells: Int = uniqueDigitsCount * uniqueDigitsCount + public val totalCells: Int = uniqueDigitsCount * uniqueDigitsCount @Deprecated( message = """Consider using 'totalCells' for better clarity. This variable represents the @@ -66,37 +61,37 @@ sealed class Dimension( |the Sudoku grid.""", replaceWith = ReplaceWith("totalCells"), ) - val cells = totalCells + public val cells: Int = totalCells /** * Whether the grid size is square (width == height). */ - val isSquare: Boolean = gridSize.isSquare + public val isSquare: Boolean = gridSize.isSquare /** * The width of the Sudoku grid. */ - val width: Int = uniqueDigitsCount + public val width: Int = uniqueDigitsCount /** * The height of the Sudoku grid. */ - val height: Int = uniqueDigitsCount + public val height: Int = uniqueDigitsCount /** * The width of a single box in the grid. */ - val boxWidth: Int = gridSize.width + public val boxWidth: Int = gridSize.width /** * The height of a single box in the grid. */ - val boxHeight: Int = gridSize.height + public val boxHeight: Int = gridSize.height /** * A human-readable name for the Sudoku dimension (e.g., "4x4"). */ - val name: String = "${width}x$height" + public val name: String = "${width}x$height" /** * Returns a string representation of the Sudoku dimension. @@ -111,7 +106,7 @@ sealed class Dimension( * * @property isSquare Whether the grid size is square (width == height). */ - data class GridSize( + public data class GridSize( val width: Int, val height: Int, ) { @@ -121,102 +116,102 @@ sealed class Dimension( /** * Companion object used to represent an unspecified Sudoku dimension. */ - data object Unspecified : Dimension( + public data object Unspecified : Dimension( gridSize = GridSize(0, 0), ) /** * Object representing a 4x4 Sudoku dimension. */ - data object FourByFour : Dimension( + public data object FourByFour : Dimension( gridSize = GridSize(2, 2), ) /** * Object representing a 6x6 Sudoku dimension. */ - data object SixBySix : Dimension( + public data object SixBySix : Dimension( gridSize = GridSize(2, 3), ) /** * Object representing a 8x8 Sudoku dimension. */ - data object EightByEight : Dimension( + public data object EightByEight : Dimension( gridSize = GridSize(2, 4), ) /** * Object representing a 9x9 Sudoku dimension. */ - data object NineByNine : Dimension( + public data object NineByNine : Dimension( gridSize = GridSize(3, 3), ) /** * Object representing a 10x10 Sudoku dimension. */ - data object TenByTen : Dimension( + public data object TenByTen : Dimension( gridSize = GridSize(2, 5), ) /** * Object representing a 12x12 Sudoku dimension. */ - data object TwelveByTwelve : Dimension( + public data object TwelveByTwelve : Dimension( gridSize = GridSize(3, 4), ) /** * Object representing a 15x15 Sudoku dimension. */ - data object FifteenByFifteen : Dimension( + public data object FifteenByFifteen : Dimension( gridSize = GridSize(3, 5), ) /** * Object representing a 16x16 Sudoku dimension. */ - data object SixteenBySixteen : Dimension( + public data object SixteenBySixteen : Dimension( gridSize = GridSize(4, 4), ) /** * Object representing a 25x25 Sudoku dimension. */ - data object TwentyFiveByTwentyFive : Dimension( + public data object TwentyFiveByTwentyFive : Dimension( gridSize = GridSize(5, 5), ) /** * Object representing a 36x36 Sudoku dimension. */ - data object ThirtySixByThirtySix : Dimension( + public data object ThirtySixByThirtySix : Dimension( gridSize = GridSize(6, 6), ) /** * Object representing a 49x49 Sudoku dimension. */ - data object FortyNineByFortyNine : Dimension( + public data object FortyNineByFortyNine : Dimension( gridSize = GridSize(7, 7), ) /** * Object representing a 64x64 Sudoku dimension. */ - data object SixtyFourBySixtyFour : Dimension( + public data object SixtyFourBySixtyFour : Dimension( gridSize = GridSize(8, 8), ) /** * Object representing a 81x81 Sudoku dimension. */ - data object EightyOneByEightyOne : Dimension( + public data object EightyOneByEightyOne : Dimension( gridSize = GridSize(9, 9), ) - companion object { + public companion object { /** * Returns the corresponding [Dimension] instance based on the provided digit count. * @@ -257,7 +252,7 @@ sealed class Dimension( * - [InvalidDimensionException]: If the provided `digitCount` does not correspond to any known Sudoku dimension. */ @Throws(InvalidDimensionException::class) - fun fromDigitCount(digitCount: Int): Dimension { + public fun fromDigitCount(digitCount: Int): Dimension { return when (digitCount) { 4 -> FourByFour 6 -> SixBySix @@ -318,8 +313,7 @@ sealed class Dimension( * ### Throws: * - [InvalidDimensionException]: If the provided `digitCount` does not correspond to any known Sudoku dimension. */ -@ExperimentalSudoklifyApi -fun Dimension(digitCount: Int): Dimension { +public fun Dimension(digitCount: Int): Dimension { return Dimension.fromDigitCount(digitCount) } @@ -327,15 +321,13 @@ fun Dimension(digitCount: Int): Dimension { * Returns a list containing all valid digits (1 to [Dimension.digits]) for the * Sudoku. */ -@ExperimentalSudoklifyApi -fun Dimension.getAllDigits(): List = (1..uniqueDigitsCount).toList() +public fun Dimension.getAllDigits(): List = (1..uniqueDigitsCount).toList() /** * Checks if a given digit is valid within the range of allowed digits for this Sudoku * (1 to [Dimension.digits]). */ -@ExperimentalSudoklifyApi -fun Dimension.isDigitValid(digit: Int): Boolean = digit in 1..uniqueDigitsCount +public fun Dimension.isDigitValid(digit: Int): Boolean = digit in 1..uniqueDigitsCount /** * Returns the box index (within the range 0 to [Dimension.boxes - 1]) for a given cell @@ -344,8 +336,7 @@ fun Dimension.isDigitValid(digit: Int): Boolean = digit in 1..uniqueDigitsCount * Throws an [IllegalArgumentException] with a specific message if the provided row or * column index is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.getBoxIndex( +public fun Dimension.getBoxIndex( row: Int, col: Int, ): Int { @@ -364,8 +355,7 @@ fun Dimension.getBoxIndex( return boxRowIndex + boxColumnIndex } -@ExperimentalSudoklifyApi -fun Dimension.getCellCoordinates( +public fun Dimension.getCellCoordinates( row: Int, col: Int, ): CellCoordinates { @@ -385,8 +375,7 @@ fun Dimension.getCellCoordinates( * Throws an [IllegalArgumentException] with a specific message if the provided row or * column index is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.getBoxCoordinates( +public fun Dimension.getBoxCoordinates( row: Int, col: Int, ): BoxCoordinates { @@ -417,8 +406,7 @@ fun Dimension.getBoxCoordinates( * Throws an [IllegalArgumentException] with a specific message if the provided cell index * is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.getCellRowIndex(cellIndex: Int): Int { +public fun Dimension.getCellRowIndex(cellIndex: Int): Int { requireValidCellIndex(cellIndex = cellIndex, message = "Invalid cell index for row calculation") return cellIndex / width } @@ -430,8 +418,7 @@ fun Dimension.getCellRowIndex(cellIndex: Int): Int { * Throws an [IllegalArgumentException] with a specific message if the provided cell index * is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.getCellColumnIndex(cellIndex: Int): Int { +public fun Dimension.getCellColumnIndex(cellIndex: Int): Int { requireValidCellIndex( cellIndex = cellIndex, message = "Invalid cell index for column calculation", @@ -446,8 +433,7 @@ fun Dimension.getCellColumnIndex(cellIndex: Int): Int { * Throws an [IllegalArgumentException] with a specific message if the provided cell index * is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.getCellBoxRowIndex(cellIndex: Int): Int { +public fun Dimension.getCellBoxRowIndex(cellIndex: Int): Int { requireValidCellIndex( cellIndex = cellIndex, message = "Invalid cell index for box row", @@ -462,8 +448,7 @@ fun Dimension.getCellBoxRowIndex(cellIndex: Int): Int { * Throws an [IllegalArgumentException] with a specific message if the provided cell * index is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.getCellBoxColumnIndex(cellIndex: Int): Int { +public fun Dimension.getCellBoxColumnIndex(cellIndex: Int): Int { requireValidCellIndex( cellIndex = cellIndex, message = "Invalid cell index for box column calculation", @@ -477,8 +462,7 @@ fun Dimension.getCellBoxColumnIndex(cellIndex: Int): Int { * Throws an [IllegalArgumentException] with a specific message if either cell index * is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.areCellsInSameRow( +public fun Dimension.areCellsInSameRow( cellIndex1: Int, cellIndex2: Int, ): Boolean { @@ -499,8 +483,7 @@ fun Dimension.areCellsInSameRow( * Throws an [IllegalArgumentException] with a specific message if either cell * index is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.areCellsInSameColumn( +public fun Dimension.areCellsInSameColumn( cellIndex1: Int, cellIndex2: Int, ): Boolean { @@ -521,8 +504,7 @@ fun Dimension.areCellsInSameColumn( * Throws an [IllegalArgumentException] with a specific message if either cell index * is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.areCellsInSameBox( +public fun Dimension.areCellsInSameBox( cellIndex1: Int, cellIndex2: Int, ): Boolean { @@ -545,8 +527,7 @@ fun Dimension.areCellsInSameBox( * Throws an [IllegalArgumentException] with a specific message if either row or column * index is invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.areCellsInSameBox( +public fun Dimension.areCellsInSameBox( row1: Int, col1: Int, row2: Int, @@ -560,8 +541,7 @@ fun Dimension.areCellsInSameBox( * Throws an [IllegalArgumentException] with a specific message if any of the row or * column indices are invalid. */ -@ExperimentalSudoklifyApi -fun Dimension.areCellsRelated( +public fun Dimension.areCellsRelated( row1: Int, col1: Int, row2: Int, @@ -601,10 +581,10 @@ internal fun Dimension.requireValidCellIndex( } } -class InvalidRowOrColumnIndexException(message: String) : IllegalArgumentException(message) +public class InvalidRowOrColumnIndexException(message: String) : IllegalArgumentException(message) -class InvalidCellIndexException(message: String) : IllegalArgumentException(message) +public class InvalidCellIndexException(message: String) : IllegalArgumentException(message) -class InvalidDimensionException(digitCount: Int) : IllegalArgumentException( +public class InvalidDimensionException(digitCount: Int) : IllegalArgumentException( "No dimension exists for digit count: $digitCount", ) diff --git a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Seed.kt b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Seed.kt index 5345ebe..af72bcb 100644 --- a/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Seed.kt +++ b/sudoklify-common/src/commonMain/kotlin/dev/teogor/sudoklify/components/Seed.kt @@ -27,8 +27,8 @@ package dev.teogor.sudoklify.components * * @throws InvalidSeedException if the initial value is negative. */ -sealed class Seed( - val value: Long, +public sealed class Seed( + public val value: Long, ) : Comparable { init { if (value < 0) { @@ -43,7 +43,7 @@ sealed class Seed( * * @return A new [Seed] object with an incremented value. */ - open fun nextSeed(): Seed = + public open fun nextSeed(): Seed = when (this) { is Random -> Random() is Explicit -> Explicit(value + 1) @@ -57,7 +57,7 @@ sealed class Seed( * * @return A [kotlin.random.Random] instance. */ - fun toRandom(): kotlin.random.Random = kotlin.random.Random(value) + public fun toRandom(): kotlin.random.Random = kotlin.random.Random(value) /** * Returns a string representation of the [Seed] object. @@ -79,7 +79,7 @@ sealed class Seed( * * @return A new [Seed] object with the specified value. */ - fun copy(seed: Long? = null): Seed { + public fun copy(seed: Long? = null): Seed { return when (this) { is Random -> Random() is Explicit -> Explicit(seed ?: this.value) @@ -130,7 +130,7 @@ sealed class Seed( * * @see kotlin.random.Random */ - class Random : Seed(kotlin.random.Random.nextLong(Long.MAX_VALUE)) + public class Random : Seed(kotlin.random.Random.nextLong(Long.MAX_VALUE)) /** * Represents an explicit seed with a specific long value. @@ -139,7 +139,7 @@ sealed class Seed( * * @throws InvalidSeedException if the value is negative. */ - class Explicit(value: Long) : Seed(value) + public class Explicit(value: Long) : Seed(value) } /** @@ -151,7 +151,7 @@ sealed class Seed( * @see Seed.Explicit * @see createSeed */ -fun Long.toSeed(): Seed = createSeed(this) +public fun Long.toSeed(): Seed = createSeed(this) /** * Creates a new [Seed] object with the specified [value], representing an explicit seed. @@ -165,7 +165,7 @@ fun Long.toSeed(): Seed = createSeed(this) * @see Seed * @see Seed.Explicit */ -fun createSeed(value: Long): Seed { +public fun createSeed(value: Long): Seed { require(value > 0) { throw InvalidSeedException("Seed value must be non-negative.") } @@ -177,4 +177,4 @@ fun createSeed(value: Long): Seed { * * @param message The detail message explaining the reason for the exception. */ -class InvalidSeedException(message: String) : IllegalArgumentException(message) +public class InvalidSeedException(message: String) : IllegalArgumentException(message) diff --git a/sudoklify-common/src/commonTest/kotlin/dev/teogor/sudoklify/components/DimensionTest.kt b/sudoklify-common/src/commonTest/kotlin/dev/teogor/sudoklify/components/DimensionTest.kt index adeb2df..cf5cc5b 100644 --- a/sudoklify-common/src/commonTest/kotlin/dev/teogor/sudoklify/components/DimensionTest.kt +++ b/sudoklify-common/src/commonTest/kotlin/dev/teogor/sudoklify/components/DimensionTest.kt @@ -16,13 +16,11 @@ package dev.teogor.sudoklify.components -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class DimensionTest { @Test fun constructor_shouldInitializePropertiesCorrectlyForSudoku4x4() { diff --git a/sudoklify-core/api/sudoklify-core.api b/sudoklify-core/api/sudoklify-core.api index b679539..c3108ce 100644 --- a/sudoklify-core/api/sudoklify-core.api +++ b/sudoklify-core/api/sudoklify-core.api @@ -198,7 +198,6 @@ public final class dev/teogor/sudoklify/random/SeededRandomKt { public static final fun randomItem (Ljava/lang/Iterable;Lkotlin/random/Random;)Ljava/lang/Object; public static final fun randomItem ([Ljava/lang/Object;Lkotlin/random/Random;)Ljava/lang/Object; public static final fun randomOrderFactor (Lkotlin/random/Random;)I - public static final fun sortRandom (Lkotlin/random/Random;)I } public final class dev/teogor/sudoklify/schema/NoSchemasForDifficultyException : java/lang/Exception { diff --git a/sudoklify-core/build.gradle.kts b/sudoklify-core/build.gradle.kts index 0556177..7dcac59 100644 --- a/sudoklify-core/build.gradle.kts +++ b/sudoklify-core/build.gradle.kts @@ -31,6 +31,10 @@ winds { } kotlin { + explicitApi() + + applyDefaultHierarchyTemplate() + jvm { kotlin { jvmToolchain(11) @@ -69,7 +73,7 @@ kotlin { dependencies { implementation(libs.jetbrains.kotlinx.datetime) - implementation(libs.teogor.crosslens.core) + // implementation(libs.teogor.crosslens.core) api(projects.sudoklifyCommon) api(projects.sudoklifyTokenizer) @@ -85,5 +89,7 @@ kotlin { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { freeCompilerArgs.add("-Xexpect-actual-classes") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.InternalSudoklifyApi") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.ExperimentalSudoklifyApi") } } diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyArchitect.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyArchitect.kt index 49cf45e..0492356 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyArchitect.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyArchitect.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify import dev.teogor.sudoklify.puzzle.SudokuPuzzle @@ -46,7 +44,7 @@ import dev.teogor.sudoklify.schema.requireSchemasForType * val puzzle = architect.constructSudoku(sudokuSpec) * ``` */ -class SudoklifyArchitect( +public class SudoklifyArchitect( private val schemas: SudokuSchemas, ) { private lateinit var spec: SudokuSpec @@ -63,13 +61,12 @@ class SudoklifyArchitect( * @param specConfig A configuration block that applies settings to the [SudokuSpec] builder. * @return The generated [SudokuPuzzle]. */ - fun constructSudoku(specConfig: SudokuSpec.Builder.() -> Unit): SudokuPuzzle { - val localSpecBuilder = - if (this::spec.isInitialized) { - this.spec.toBuilder() - } else { - SudokuSpec.Builder() - } + public fun constructSudoku(specConfig: SudokuSpec.Builder.() -> Unit): SudokuPuzzle { + val localSpecBuilder = if (this::spec.isInitialized) { + this.spec.toBuilder() + } else { + SudokuSpec.Builder() + } val localSpec = localSpecBuilder.apply(specConfig).build() return constructSudoku(localSpec) } @@ -80,7 +77,7 @@ class SudoklifyArchitect( * @param spec The specification to use for puzzle generation. * @return The generated [SudokuPuzzle]. */ - fun constructSudoku(spec: SudokuSpec): SudokuPuzzle { + public fun constructSudoku(spec: SudokuSpec): SudokuPuzzle { this.spec = spec return createSudokuFromSpec(spec) } @@ -128,7 +125,7 @@ class SudoklifyArchitect( * @see SudokuSchemas.Builder.addAll */ @SudoklifyDsl -inline fun SudoklifyArchitect(crossinline block: () -> SudokuSchemas): SudoklifyArchitect { +public inline fun SudoklifyArchitect(crossinline block: () -> SudokuSchemas): SudoklifyArchitect { return SudoklifyArchitect(block()) } @@ -146,7 +143,7 @@ inline fun SudoklifyArchitect(crossinline block: () -> SudokuSchemas): Sudoklify * For more detailed instructions and examples on providing Sudoku schemas, visit: * [Sudoklify Documentation - Sudoku Schemas](https://source.teogor.dev/sudoklify/sudoku-schemas) */ -class EmptySudokuSchemasException : Exception( +public class EmptySudokuSchemasException : Exception( """ |The Sudoku schemas list is empty. | diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyAssembler.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyAssembler.kt index cb1e5dd..c37b699 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyAssembler.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudoklifyAssembler.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify import dev.teogor.sudoklify.puzzle.SudokuPuzzle @@ -68,9 +66,9 @@ import kotlin.random.Random * @see SudokuTokenMapper * @see SudokuPuzzle */ -class SudoklifyAssembler( - val schemas: SudokuSchemas, - val spec: SudokuSpec, +public class SudoklifyAssembler( + public val schemas: SudokuSchemas, + public val spec: SudokuSpec, private val sudokuLayoutManipulator: SudokuLayoutManipulator, private val sudokuTokenMapper: SudokuTokenMapper, private val random: Random, @@ -93,17 +91,15 @@ class SudoklifyAssembler( * * @return A [SudokuPuzzle] object containing the generated puzzle, solution, and other metadata. */ - fun assembleSudoku(): SudokuPuzzle { - val randomItem = - schemas - .getSeedsBySize(spec.type) - .getSeedsByDifficulty(spec.difficulty) - .randomItem(random) + public fun assembleSudoku(): SudokuPuzzle { + val randomItem = schemas + .getSeedsBySize(spec.type) + .getSeedsByDifficulty(spec.difficulty) + .randomItem(random) - val layout = - sudokuLayoutManipulator.shuffle( - sudokuLayoutManipulator.rotate(sudokuLayoutManipulator.constructBase()), - ) + val layout = sudokuLayoutManipulator.shuffle( + sudokuLayoutManipulator.rotate(sudokuLayoutManipulator.constructBase()), + ) val tokenMap = sudokuTokenMapper.getTokenMap() val puzzle = sudokuTokenMapper.getSequence(layout, randomItem.puzzle, tokenMap) @@ -196,7 +192,7 @@ class SudoklifyAssembler( * * @property spec The specification used to configure the [SudoklifyAssembler]. */ - class Factory( + public class Factory( private val schemas: SudokuSchemas, private val spec: SudokuSpec, ) { @@ -220,10 +216,9 @@ class SudoklifyAssembler( * @return A [SudokuTokenMapper] instance for generating token sequences for the Sudoku puzzle. */ private fun createBoardElementsFactory(): SudokuTokenMapper { - val tokenizer = - Tokenizer.create( - digits = spec.type.uniqueDigitsCount, - ) + val tokenizer = Tokenizer.create( + digits = spec.type.uniqueDigitsCount, + ) return SudokuTokenMapper.default( tokenizer = tokenizer, random = random, @@ -244,7 +239,7 @@ class SudoklifyAssembler( * * @return A [SudoklifyAssembler] instance ready to generate Sudoku puzzles. */ - fun createAssembler(): SudoklifyAssembler { + public fun createAssembler(): SudoklifyAssembler { return SudoklifyAssembler( schemas = schemas, spec = spec, @@ -273,7 +268,7 @@ class SudoklifyAssembler( * @return A [SudoklifyAssembler] instance configured with the provided parameters. */ @SudoklifyDsl -fun SudoklifyAssembler( +public fun SudoklifyAssembler( schemas: SudokuSchemas, spec: SudokuSpec, ): SudoklifyAssembler { @@ -305,7 +300,7 @@ fun SudoklifyAssembler( */ @Suppress("FunctionName") @SudoklifyDsl -fun SudoklifyAssembler( +public fun SudoklifyAssembler( schemas: SudokuSchemas, spec: SudokuSpec, block: SudoklifyAssembler.() -> T, diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuConversions.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuConversions.kt index 2948cf8..29be0d0 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuConversions.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuConversions.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify import dev.teogor.sudoklify.components.Dimension @@ -46,7 +44,7 @@ import dev.teogor.sudoklify.tokenizer.toJEncodedCell * @see mapToSudokuString * @see toJEncodedCell */ -fun Iterable>.mapToSudokuString(): String { +public fun Iterable>.mapToSudokuString(): String { return flatMap { innerIterable -> innerIterable.map { element -> element.toJEncodedCell() @@ -82,7 +80,7 @@ fun Iterable>.mapToSudokuString(): String { * @see mapToSudokuString * @see toJEncodedCell */ -inline fun Iterable>.mapToSudokuString( +public inline fun Iterable>.mapToSudokuString( crossinline valueMapper: T.() -> Int, ): String { return flatMap { cells -> @@ -126,7 +124,7 @@ inline fun Iterable>.mapToSudokuString( * @see mapToSudokuBoard * @see mapIndexedToSudokuBoard */ -fun String.mapToSudokuBoard(dimension: Dimension): List> { +public fun String.mapToSudokuBoard(dimension: Dimension): List> { return JEncodedCell.extractCells(this) .chunked(dimension.uniqueDigitsCount) .map { row -> row.map { it.toInt() } } @@ -168,7 +166,7 @@ fun String.mapToSudokuBoard(dimension: Dimension): List> { * @see mapToSudokuBoard * @see mapIndexedToSudokuBoard */ -inline fun String.mapToSudokuBoard( +public inline fun String.mapToSudokuBoard( dimension: Dimension, crossinline valueMapper: Int.() -> T, ): List> { @@ -192,7 +190,7 @@ inline fun String.mapToSudokuBoard( * * @see mapToSudokuBoard */ -inline fun String.mapIndexedToSudokuBoard( +public inline fun String.mapIndexedToSudokuBoard( dimension: Dimension, crossinline valueMapper: (value: Int, row: Int, column: Int) -> T, ): List> { diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuLayoutManipulator.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuLayoutManipulator.kt index 076f5c4..4c25923 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuLayoutManipulator.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuLayoutManipulator.kt @@ -42,7 +42,7 @@ import kotlin.random.Random * val rotatedLayout = manipulator.rotate(shuffledLayout) * ``` */ -interface SudokuLayoutManipulator { +public interface SudokuLayoutManipulator { /** * Constructs the base Sudoku layout based on the specified size. * @@ -51,7 +51,7 @@ interface SudokuLayoutManipulator { * * @return A 2D array representing the base Sudoku layout. */ - fun constructBase(): Layout + public fun constructBase(): Layout /** * Shuffles the given Sudoku layout by applying a series of transformations. @@ -62,7 +62,7 @@ interface SudokuLayoutManipulator { * @param layout The Sudoku layout to be shuffled. * @return A new Sudoku layout with applied shuffling. */ - fun shuffle(layout: Layout): Layout + public fun shuffle(layout: Layout): Layout /** * Rotates the given Sudoku layout by a random multiple of 90 degrees. @@ -73,9 +73,9 @@ interface SudokuLayoutManipulator { * @param layout The Sudoku layout to be rotated. * @return The rotated Sudoku layout. */ - fun rotate(layout: Layout): Layout + public fun rotate(layout: Layout): Layout - companion object { + public companion object { /** * Provides a default implementation of [SudokuLayoutManipulator]. * @@ -87,7 +87,7 @@ interface SudokuLayoutManipulator { * @param random The random number generator used for shuffling and rotation. * @return A [SudokuLayoutManipulator] instance with the default implementation. */ - fun default( + public fun default( boxDigits: Int, random: Random, ): SudokuLayoutManipulator { diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuTokenMapper.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuTokenMapper.kt index a9bf786..162a0e5 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuTokenMapper.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/SudokuTokenMapper.kt @@ -42,7 +42,7 @@ import kotlin.random.Random * val sequence = tokenMapper.getSequence(layout, seedSequence, tokenMap) * ``` */ -interface SudokuTokenMapper { +public interface SudokuTokenMapper { /** * Generates a map of tokens to their corresponding values. * @@ -51,7 +51,7 @@ interface SudokuTokenMapper { * * @return A [TokenMap] where each token is mapped to its corresponding value. */ - fun getTokenMap(): TokenMap + public fun getTokenMap(): TokenMap /** * Produces a sequence of tokens for the given Sudoku layout and seed sequence. @@ -64,13 +64,13 @@ interface SudokuTokenMapper { * @param tokenMap The map of tokens to values used for tokenization. * @return A 2D array of tokens representing the tokenized Sudoku layout. */ - fun getSequence( + public fun getSequence( layout: Layout, seedSequence: SudokuString, tokenMap: TokenMap, ): Array> - companion object { + public companion object { /** * Provides a default implementation of [SudokuTokenMapper]. * @@ -82,7 +82,7 @@ interface SudokuTokenMapper { * @param tokenizer The [Tokenizer] used to populate the Sudoku layout with tokens. * @return A [SudokuTokenMapper] instance with the default implementation. */ - fun default( + public fun default( boxDigits: Int, random: Random, tokenizer: Tokenizer, diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzle.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzle.kt index 96e93f5..8c4e816 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzle.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzle.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.puzzle -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.components.Seed @@ -35,7 +32,7 @@ import dev.teogor.sudoklify.puzzle.SudokuPuzzle.Hint * @property solution The solution grid of the puzzle as a list of lists of integers. * @property hints Optional hints for solving the puzzle, represented as a list of [Hint]. */ -data class SudokuPuzzle( +public data class SudokuPuzzle( val difficulty: Difficulty, val type: Dimension, val seed: Seed, @@ -50,7 +47,7 @@ data class SudokuPuzzle( * @property col The column index of the given cell (0-based). * @property value The fixed value assigned to the cell. */ - data class Givens( + public data class Givens( val row: Int, val col: Int, val value: Int, @@ -65,7 +62,7 @@ data class SudokuPuzzle( * Defaults to -1 if the hint is not specific to a column. * @property type The type of hint, which determines the solving strategy to be used. */ - data class Hint( + public data class Hint( val message: String, val row: Int, val col: Int = -1, @@ -75,7 +72,7 @@ data class SudokuPuzzle( /** * Enumerates the types of hints that can be provided to help solve the Sudoku puzzle. */ - enum class HintType { + public enum class HintType { /** * Indicates that the hint involves eliminating possibilities in a row. */ @@ -119,7 +116,7 @@ data class SudokuPuzzle( * @return A list of lists representing the grid, where each inner list corresponds to a row, * and each element in the inner list corresponds to a cell value. */ -fun SudokuPuzzle.generateGridWithGivens(): List> { +public fun SudokuPuzzle.generateGridWithGivens(): List> { val gridSize = type.uniqueDigitsCount val grid = MutableList(gridSize) { MutableList(gridSize) { 0 } } diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpec.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpec.kt index 913e7d3..a995130 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpec.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpec.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.puzzle -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.SudoklifyDsl import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension @@ -31,7 +28,7 @@ import dev.teogor.sudoklify.components.Seed * @property seed The seed value used for generating the puzzle. * @property difficulty The difficulty level of the puzzle. */ -data class SudokuSpec( +public data class SudokuSpec( val type: Dimension, val seed: Seed, val difficulty: Difficulty, @@ -41,8 +38,7 @@ data class SudokuSpec( * * @return A new [Builder] instance. */ - @OptIn(ExperimentalSudoklifyApi::class) - fun toBuilder(): Builder { + public fun toBuilder(): Builder { return Builder() .difficulty(this.difficulty) .seed(this.seed) @@ -56,7 +52,7 @@ data class SudokuSpec( * @property seed The seed value used for generating the puzzle. * @property type The type of Sudoku puzzle. */ - data class Builder( + public data class Builder( var difficulty: Difficulty = Difficulty.EASY, var seed: Seed = Seed.Random(), var type: Dimension = Dimension.Unspecified, @@ -67,7 +63,9 @@ data class SudokuSpec( * @param difficulty The desired difficulty level. * @return This builder instance. */ - fun difficulty(difficulty: Difficulty) = apply { this.difficulty = difficulty } + public fun difficulty(difficulty: Difficulty): Builder = apply { + this.difficulty = difficulty + } /** * Sets the difficulty level for the Sudoku puzzle using a lambda function. @@ -75,10 +73,11 @@ data class SudokuSpec( * @param difficulty A lambda that returns the desired difficulty level. * @return This builder instance. */ - inline fun difficulty(crossinline difficulty: () -> Difficulty) = - apply { - this.difficulty = difficulty() - } + public inline fun difficulty( + crossinline difficulty: () -> Difficulty, + ): Builder = apply { + this.difficulty = difficulty() + } /** * Sets the seed value for the Sudoku puzzle. @@ -86,7 +85,7 @@ data class SudokuSpec( * @param seed The desired seed value. * @return This builder instance. */ - fun seed(seed: Seed) = apply { this.seed = seed } + public fun seed(seed: Seed): Builder = apply { this.seed = seed } /** * Sets the seed value for the Sudoku puzzle using a lambda function. @@ -94,10 +93,9 @@ data class SudokuSpec( * @param seed A lambda that returns the desired seed value. * @return This builder instance. */ - inline fun seed(crossinline seed: () -> Seed) = - apply { - this.seed = seed() - } + public inline fun seed(crossinline seed: () -> Seed): Builder = apply { + this.seed = seed() + } /** * Sets the type of Sudoku puzzle. @@ -105,7 +103,7 @@ data class SudokuSpec( * @param type The desired type of Sudoku puzzle. * @return This builder instance. */ - fun type(type: Dimension) = apply { this.type = type } + public fun type(type: Dimension): Builder = apply { this.type = type } /** * Sets the type of Sudoku puzzle using a lambda function. @@ -113,17 +111,16 @@ data class SudokuSpec( * @param type A lambda that returns the desired type of Sudoku puzzle. * @return This builder instance. */ - inline fun type(crossinline type: () -> Dimension) = - apply { - this.type = type() - } + public inline fun type(crossinline type: () -> Dimension): Builder = apply { + this.type = type() + } /** * Builds a [SudokuSpec] instance with the configured properties. * * @return A new [SudokuSpec] instance. */ - fun build(): SudokuSpec { + public fun build(): SudokuSpec { return SudokuSpec( type = type, difficulty = difficulty, @@ -150,7 +147,7 @@ data class SudokuSpec( * @return A new [SudokuSpec] instance configured by the builder. */ @SudoklifyDsl -fun SudokuSpec(block: SudokuSpec.Builder.() -> Unit): SudokuSpec { +public fun SudokuSpec(block: SudokuSpec.Builder.() -> Unit): SudokuSpec { val builder = SudokuSpec.Builder() builder.apply(block) return builder.build() @@ -173,7 +170,7 @@ fun SudokuSpec(block: SudokuSpec.Builder.() -> Unit): SudokuSpec { * @return A new [SudokuSpec] instance with the updated properties. */ @SudoklifyDsl -fun SudokuSpec( +public fun SudokuSpec( spec: SudokuSpec, block: SudokuSpec.Builder.() -> Unit, ): SudokuSpec { diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/random/SeededRandom.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/random/SeededRandom.kt index 27f2ddf..cf34c05 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/random/SeededRandom.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/random/SeededRandom.kt @@ -19,7 +19,7 @@ package dev.teogor.sudoklify.random import dev.teogor.sudoklify.components.Seed import kotlin.random.Random -class SeededRandom(seed: Seed) : Random() { +public class SeededRandom(seed: Seed) : Random() { private val internalRandom: Random = Random(seed.value) override fun nextBits(bitCount: Int): Int = internalRandom.nextBits(bitCount) @@ -75,16 +75,8 @@ class SeededRandom(seed: Seed) : Random() { ) } -fun Random.randomOrderFactor(): Int = if (nextDouble() < 0.5) 1 else -1 +public fun Random.randomOrderFactor(): Int = if (nextDouble() < 0.5) 1 else -1 -fun Iterable.randomItem(random: Random): T = shuffled(random).first() +public fun Iterable.randomItem(random: Random): T = shuffled(random).first() -fun Array.randomItem(random: Random): T = random(random) - -// region DEPRECATED -@Deprecated( - message = "Use randomOrderFactor() instead.", - replaceWith = ReplaceWith("randomOrderFactor()"), -) -fun Random.sortRandom(): Int = if (nextDouble() < 0.5) 1 else -1 -// endregion +public fun Array.randomItem(random: Random): T = random(random) diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt index 9872509..643177d 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt @@ -14,12 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.schema -import dev.teogor.crosslens.core.buildLazyHashCode -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.tokenizer.SudokuString @@ -36,13 +32,13 @@ import dev.teogor.sudoklify.tokenizer.toSudokuString * @property difficulty The difficulty level of the Sudoku puzzle. This is used to categorize the puzzle based on its complexity. * @property dimension The type of the Sudoku puzzle, defining the grid size and other characteristics (e.g., 9x9 classic Sudoku). */ -class SudokuSchema( - val puzzle: SudokuString, - val solution: SudokuString, - val difficulty: Difficulty, - val dimension: Dimension, +public class SudokuSchema( + public val puzzle: SudokuString, + public val solution: SudokuString, + public val difficulty: Difficulty, + public val dimension: Dimension, ) { - fun copy( + public fun copy( puzzle: SudokuString = this.puzzle, solution: SudokuString = this.solution, difficulty: Difficulty = this.difficulty, @@ -78,15 +74,6 @@ class SudokuSchema( } } - override fun hashCode(): Int = hash - - private val hash: Int by buildLazyHashCode { - append(puzzle) - append(solution) - append(difficulty) - append(dimension) - } - /** * Checks if this SudokuSchema is equal to another object. * @@ -104,6 +91,22 @@ class SudokuSchema( difficulty == other.difficulty && dimension == other.dimension } + + // TODO + // override fun hashCode(): Int = hash + // private val hash: Int by buildLazyHashCode { + // append(puzzle) + // append(solution) + // append(difficulty) + // append(dimension) + // } + override fun hashCode(): Int { + var result = puzzle.hashCode() + result = 31 * result + solution.hashCode() + result = 31 * result + difficulty.hashCode() + result = 31 * result + dimension.hashCode() + return result + } } /** @@ -130,7 +133,7 @@ class SudokuSchema( * @param dimension The type of the Sudoku puzzle, which defines the grid size and other characteristics (e.g., 9x9 classic Sudoku). * @return A new [SudokuSchema] instance with the specified properties. */ -fun SudokuSchema( +public fun SudokuSchema( puzzle: String, solution: String, difficulty: Difficulty, diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchemas.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchemas.kt index 6ac7df4..c54165f 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchemas.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchemas.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.schema -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.SudoklifyDsl import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension @@ -65,7 +62,7 @@ import dev.teogor.sudoklify.components.Dimension * @see SudokuSchema * @see Collection */ -class SudokuSchemas( +public class SudokuSchemas( private val schemas: List, ) : Collection { /** @@ -120,7 +117,7 @@ class SudokuSchemas( * @param schema The [SudokuSchema] to add. * @return A new [SudokuSchemas] collection containing the original schemas and the added schema. */ - operator fun plus(schema: SudokuSchema): SudokuSchemas { + public operator fun plus(schema: SudokuSchema): SudokuSchemas { return SudokuSchemas((schemas + schema).distinct()) } @@ -130,7 +127,7 @@ class SudokuSchemas( * @param other The collection of [SudokuSchema] objects to add. * @return A new [SudokuSchemas] collection containing the original schemas and the added schemas. */ - operator fun plus(other: Collection): SudokuSchemas { + public operator fun plus(other: Collection): SudokuSchemas { return SudokuSchemas((schemas + other).distinct()) } @@ -140,7 +137,7 @@ class SudokuSchemas( * @param other The [SudokuSchemas] collection to add. * @return A new [SudokuSchemas] collection containing the original schemas and the added schemas from the other collection. */ - operator fun plus(other: SudokuSchemas): SudokuSchemas { + public operator fun plus(other: SudokuSchemas): SudokuSchemas { return SudokuSchemas((schemas + other.schemas).distinct()) } @@ -150,7 +147,7 @@ class SudokuSchemas( * @param type The Sudoku dimension to filter by. * @return A new [SudokuSchemas] instance containing only the schemas with the specified dimension. */ - fun getSeedsBySize(type: Dimension): SudokuSchemas { + public fun getSeedsBySize(type: Dimension): SudokuSchemas { return schemas.filter { it.dimension.uniqueDigitsCount == type.uniqueDigitsCount }.let { schemas -> SudokuSchemas(schemas) } @@ -162,7 +159,7 @@ class SudokuSchemas( * @param difficulty The difficulty level to filter by. * @return A new [SudokuSchemas] instance containing only the schemas with the specified difficulty. */ - fun getSeedsByDifficulty(difficulty: Difficulty): SudokuSchemas { + public fun getSeedsByDifficulty(difficulty: Difficulty): SudokuSchemas { return schemas.filter { it.difficulty == difficulty }.let { schemas -> SudokuSchemas(schemas) } @@ -177,7 +174,7 @@ class SudokuSchemas( * @param difficulty The difficulty level to filter by. * @return A [SudokuSchemas] instance containing all [SudokuSchema] instances with the specified difficulty. */ - fun findByDifficulty(difficulty: Difficulty): SudokuSchemas { + public fun findByDifficulty(difficulty: Difficulty): SudokuSchemas { return schemas.filter { it.difficulty == difficulty }.let { schemas -> SudokuSchemas(schemas) } @@ -192,7 +189,7 @@ class SudokuSchemas( * @param dimension The Sudoku dimension to filter by. * @return A [SudokuSchemas] instance containing all [SudokuSchema] instances with the specified dimension. */ - fun findBySudokuType(dimension: Dimension): SudokuSchemas { + public fun findBySudokuType(dimension: Dimension): SudokuSchemas { return schemas.filter { it.dimension == dimension }.let { schemas -> SudokuSchemas(schemas) } @@ -203,7 +200,7 @@ class SudokuSchemas( * * @return A set of unique [Dimension] instances. */ - fun getUniqueSudokuTypes(): Set { + public fun getUniqueSudokuTypes(): Set { return schemas.map { it.dimension }.toSet() } @@ -212,7 +209,7 @@ class SudokuSchemas( * * @return A map where the keys are [Difficulty] levels and the values are counts of schemas with that difficulty. */ - fun countByDifficulty(): Map { + public fun countByDifficulty(): Map { return schemas.groupingBy { it.difficulty }.eachCount() } @@ -223,7 +220,7 @@ class SudokuSchemas( * the original list is used. * @return A new [SudokuSchemas] instance with the specified schemas. */ - fun copy(schemas: List = this.schemas): SudokuSchemas { + public fun copy(schemas: List = this.schemas): SudokuSchemas { return SudokuSchemas(schemas) } @@ -300,7 +297,7 @@ class SudokuSchemas( * * @return A [Builder] initialized with the schemas from this [SudokuSchemas]. */ - fun toBuilder(): Builder { + public fun toBuilder(): Builder { val builder = Builder() builder.addAll(schemas) return builder @@ -332,7 +329,7 @@ class SudokuSchemas( * }.build() * ``` */ - class Builder { + public class Builder { private val schemas = mutableListOf() /** @@ -341,10 +338,9 @@ class SudokuSchemas( * @param schema The schema to add. * @return This [Builder] instance for chaining. */ - fun add(schema: SudokuSchema) = - apply { - schemas.add(schema) - } + public fun add(schema: SudokuSchema): Builder = apply { + schemas.add(schema) + } /** * Adds multiple [SudokuSchema] instances to the set. @@ -352,10 +348,9 @@ class SudokuSchemas( * @param schemas The schemas to add. * @return This [Builder] instance for chaining. */ - fun add(vararg schemas: SudokuSchema) = - apply { - this.schemas.addAll(schemas) - } + public fun add(vararg schemas: SudokuSchema): Builder = apply { + this.schemas.addAll(schemas) + } /** * Adds multiple [SudokuSchema] instances to the set from an iterable. @@ -363,17 +358,16 @@ class SudokuSchemas( * @param schemas The iterable of schemas to add. * @return This [Builder] instance for chaining. */ - fun addAll(schemas: Iterable) = - apply { - this.schemas.addAll(schemas) - } + public fun addAll(schemas: Iterable): Builder = apply { + this.schemas.addAll(schemas) + } /** * Builds the [SudokuSchemas] instance using the schemas added to the builder. * * @return A new [SudokuSchemas] instance with the configured schemas. */ - fun build(): SudokuSchemas = SudokuSchemas(schemas) + public fun build(): SudokuSchemas = SudokuSchemas(schemas) } } @@ -442,7 +436,9 @@ class SudokuSchemas( * @see SudokuSchemas.Builder.addAll */ @SudoklifyDsl -inline fun SudokuSchemas(builder: SudokuSchemas.Builder.() -> Unit): SudokuSchemas { +public inline fun SudokuSchemas( + builder: SudokuSchemas.Builder.() -> Unit, +): SudokuSchemas { return SudokuSchemas.Builder().apply(builder).build() } @@ -488,7 +484,7 @@ inline fun SudokuSchemas(builder: SudokuSchemas.Builder.() -> Unit): SudokuSchem * @see SudokuSchemas.Builder.addAll */ @SudoklifyDsl -inline fun SudokuSchemas( +public inline fun SudokuSchemas( existingSet: SudokuSchemas, builder: SudokuSchemas.Builder.() -> Unit, ): SudokuSchemas { @@ -501,7 +497,7 @@ inline fun SudokuSchemas( * @param type The Sudoku type to check for. * @throws NoSchemasForTypeException if no schemas are found for the type. */ -fun SudokuSchemas.requireSchemasForType(type: Dimension) { +public fun SudokuSchemas.requireSchemasForType(type: Dimension) { if (findBySudokuType(type).isEmpty()) { throw NoSchemasForTypeException(type) } @@ -525,7 +521,7 @@ fun SudokuSchemas.requireSchemasForType(type: Dimension) { * @param schemas The array of [SudokuSchema] objects to add. * @return This [SudokuSchemas.Builder] instance for chaining. */ -fun SudokuSchemas.Builder.addAll(schemas: Array) { +public fun SudokuSchemas.Builder.addAll(schemas: Array) { addAll(schemas.toList()) } @@ -535,7 +531,7 @@ fun SudokuSchemas.Builder.addAll(schemas: Array) { * @param difficulty The difficulty level to check for. * @throws NoSchemasForDifficultyException if no schemas are found for the difficulty. */ -fun SudokuSchemas.requireSchemasForDifficulty(difficulty: Difficulty) { +public fun SudokuSchemas.requireSchemasForDifficulty(difficulty: Difficulty) { if (findByDifficulty(difficulty).isEmpty()) { throw NoSchemasForDifficultyException(difficulty) } @@ -544,13 +540,13 @@ fun SudokuSchemas.requireSchemasForDifficulty(difficulty: Difficulty) { /** * Exception thrown when no Sudoku schemas are found for a given Sudoku type. */ -class NoSchemasForTypeException( +public class NoSchemasForTypeException( type: Dimension, ) : Exception("No Sudoku schemas found for type: $type") /** * Exception thrown when no Sudoku schemas are found for a given difficulty. */ -class NoSchemasForDifficultyException( +public class NoSchemasForDifficultyException( difficulty: Difficulty, ) : Exception("No Sudoku schemas found for difficulty: $difficulty") diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/BoardConversions.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/BoardConversions.kt index 07036f9..34722c3 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/BoardConversions.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/BoardConversions.kt @@ -16,7 +16,6 @@ package dev.teogor.sudoklify.util -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.tokenizer.SudokuString @@ -29,8 +28,7 @@ import dev.teogor.sudoklify.tokenizer.SudokuString * * @return A list of lists of strings representing the Sudoku puzzle. */ -@ExperimentalSudoklifyApi -fun String.toBoard(dimension: Dimension): Array> { +public fun String.toBoard(dimension: Dimension): Array> { val regex = Regex("([A-I][a-z]+)|-|[A-I]") val matches = regex.findAll(this) val matchedTokens = ArrayList() diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyArchitectTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyArchitectTest.kt index 9735482..1473d3a 100644 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyArchitectTest.kt +++ b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyArchitectTest.kt @@ -29,7 +29,6 @@ import kotlin.test.assertFailsWith import kotlin.test.assertNotNull import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class SudoklifyArchitectTest { private val schema1 = SudokuSchema( diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyAssemblerTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyAssemblerTest.kt index efdea58..725e593 100644 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyAssemblerTest.kt +++ b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudoklifyAssemblerTest.kt @@ -29,7 +29,6 @@ import kotlin.test.assertNotEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class SudoklifyAssemblerTest { private val schema1 = SudokuSchema( diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudokuConversionsTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudokuConversionsTest.kt index 51ba516..47bc543 100644 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudokuConversionsTest.kt +++ b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/SudokuConversionsTest.kt @@ -21,7 +21,6 @@ import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals -@OptIn(ExperimentalSudoklifyApi::class) class SudokuConversionsTest { @Test fun mapIterableToSudokuString_shouldProduceExpectedResult() { @@ -43,6 +42,7 @@ class SudokuConversionsTest { @Test fun mapIterableWithMapperToSudokuString_shouldProduceExpectedResult() { data class Cell(val number: Int) + val board: Iterable> = listOf( listOf(Cell(1), Cell(2), Cell(3)), diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzleTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzleTest.kt index f500beb..aecd290 100644 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzleTest.kt +++ b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuPuzzleTest.kt @@ -16,7 +16,6 @@ package dev.teogor.sudoklify.puzzle -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.components.createSeed @@ -27,7 +26,6 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class SudokuPuzzleTest { @Test fun constructor_shouldSetPropertiesCorrectly() { diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpecTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpecTest.kt index c94fe86..237ec6b 100644 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpecTest.kt +++ b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/puzzle/SudokuSpecTest.kt @@ -16,7 +16,6 @@ package dev.teogor.sudoklify.puzzle -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.components.createSeed @@ -25,7 +24,6 @@ import kotlin.test.assertEquals import kotlin.test.assertSame import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class SudokuSpecTest { @Test fun constructor_shouldSetPropertiesCorrectly() { diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemaTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemaTest.kt index 65bc138..9f8a413 100644 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemaTest.kt +++ b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemaTest.kt @@ -16,7 +16,6 @@ package dev.teogor.sudoklify.schema -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.tokenizer.SudokuString @@ -25,7 +24,6 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals -@OptIn(ExperimentalSudoklifyApi::class) class SudokuSchemaTest { @Test fun constructor_shouldSetPropertiesCorrectly() { diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemasTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemasTest.kt index f5a4cf4..f34b53b 100644 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemasTest.kt +++ b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/schema/SudokuSchemasTest.kt @@ -16,7 +16,6 @@ package dev.teogor.sudoklify.schema -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import kotlin.test.Test @@ -25,7 +24,6 @@ import kotlin.test.assertNotEquals import kotlin.test.assertNotSame import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class SudokuSchemasTest { private val schema1 = SudokuSchema( diff --git a/sudoklify-io/api/sudoklify-io.api b/sudoklify-io/api/sudoklify-io.api index 7bc0a34..c501642 100644 --- a/sudoklify-io/api/sudoklify-io.api +++ b/sudoklify-io/api/sudoklify-io.api @@ -1,7 +1,3 @@ -public final class dev/teogor/sudoklify/io/BoardSerializationKt { - public static final fun generateTokenMap (I)Ljava/util/Map; -} - public final class dev/teogor/sudoklify/io/SudokuParser { public fun (Ljava/lang/String;Ldev/teogor/sudoklify/components/Dimension;)V public final fun toIntArray ()[[I diff --git a/sudoklify-io/build.gradle.kts b/sudoklify-io/build.gradle.kts index 79263ca..aa7c020 100644 --- a/sudoklify-io/build.gradle.kts +++ b/sudoklify-io/build.gradle.kts @@ -31,6 +31,10 @@ winds { } kotlin { + explicitApi() + + applyDefaultHierarchyTemplate() + jvm { kotlin { jvmToolchain(11) @@ -82,5 +86,7 @@ kotlin { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { freeCompilerArgs.add("-Xexpect-actual-classes") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.InternalSudoklifyApi") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.ExperimentalSudoklifyApi") } } diff --git a/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/BoardSerialization.kt b/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/BoardSerialization.kt index 33140f6..6a46b07 100644 --- a/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/BoardSerialization.kt +++ b/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/BoardSerialization.kt @@ -31,7 +31,7 @@ import dev.teogor.sudoklify.tokenizer.toJEncodedCell * and their string representations. */ @InternalSudoklifyApi -fun generateTokenMap(boxDigits: Int): TokenMap { +public fun generateTokenMap(boxDigits: Int): TokenMap { val gridList = (1..boxDigits) val tokenList = gridList.withIndex().map { (index, _) -> diff --git a/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/SudokuParser.kt b/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/SudokuParser.kt index 4ace4dc..940ba59 100644 --- a/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/SudokuParser.kt +++ b/sudoklify-io/src/commonMain/kotlin/dev/teogor/sudoklify/io/SudokuParser.kt @@ -14,12 +14,8 @@ * limitations under the License. */ -@file:OptIn(InternalSudoklifyApi::class) - package dev.teogor.sudoklify.io -import dev.teogor.sudoklify.ExperimentalSudoklifyApi -import dev.teogor.sudoklify.InternalSudoklifyApi import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.tokenizer.JEncodedCell import dev.teogor.sudoklify.util.toBoard @@ -30,8 +26,7 @@ import dev.teogor.sudoklify.util.toBoard * @param puzzle The Sudoku puzzle string to parse. * @param dimension The sudoku type of the Sudoku puzzle (e.g., 4x4, 9x9). */ -@ExperimentalSudoklifyApi -class SudokuParser( +public class SudokuParser( puzzle: String, dimension: Dimension, ) { @@ -43,8 +38,7 @@ class SudokuParser( * * @return A 2D array of integers representing the Sudoku puzzle. */ - @OptIn(InternalSudoklifyApi::class) - fun toIntArray(): Array { + public fun toIntArray(): Array { val tokenMap = generateTokenMap(boxDigits) val convertedPuzzle = Array(puzzleBoard.size) { IntArray(puzzleBoard[0].size) } @@ -77,8 +71,7 @@ class SudokuParser( * * @throws [IllegalArgumentException] if the provided Sudoku puzzle string is invalid. */ -@ExperimentalSudoklifyApi -fun String.toSudokuIntArray(dimension: Dimension): Array { +public fun String.toSudokuIntArray(dimension: Dimension): Array { val parser = SudokuParser(this, dimension) return parser.toIntArray() } diff --git a/sudoklify-presets/build.gradle.kts b/sudoklify-presets/build.gradle.kts index 3b59bd7..1a4cdc9 100644 --- a/sudoklify-presets/build.gradle.kts +++ b/sudoklify-presets/build.gradle.kts @@ -31,6 +31,10 @@ winds { } kotlin { + explicitApi() + + applyDefaultHierarchyTemplate() + jvm { kotlin { jvmToolchain(11) @@ -80,5 +84,7 @@ kotlin { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { freeCompilerArgs.add("-Xexpect-actual-classes") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.InternalSudoklifyApi") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.ExperimentalSudoklifyApi") } } diff --git a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/FourDigitsSchemas.kt b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/FourDigitsSchemas.kt index 6549327..fe8de71 100644 --- a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/FourDigitsSchemas.kt +++ b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/FourDigitsSchemas.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.presets -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.schema.SudokuSchema @@ -26,7 +23,7 @@ import dev.teogor.sudoklify.schema.SudokuSchema /** * An array of [SudokuSchema] objects representing easy 4x4 Sudoku puzzles. */ -val fourDigitsSchemas: Array = arrayOf( +public val fourDigitsSchemas: Array = arrayOf( // region Difficulty - Very Easy (*) // endregion diff --git a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/NineDigitsSchemas.kt b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/NineDigitsSchemas.kt index 685a7e2..d11a807 100644 --- a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/NineDigitsSchemas.kt +++ b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/NineDigitsSchemas.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.presets -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.schema.SudokuSchema @@ -26,7 +23,7 @@ import dev.teogor.sudoklify.schema.SudokuSchema /** * An array of [SudokuSchema] objects representing easy 9x9 Sudoku puzzles. */ -val nineDigitsSchemas: Array = arrayOf( +public val nineDigitsSchemas: Array = arrayOf( // region Difficulty - Very Easy (*) // Remaining Digits 36 SudokuSchema( diff --git a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/PresetSchemas.kt b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/PresetSchemas.kt index 8672964..267f7fd 100644 --- a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/PresetSchemas.kt +++ b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/PresetSchemas.kt @@ -40,7 +40,7 @@ import dev.teogor.sudoklify.schema.addAll * * @return A [SudokuSchemas] object containing all predefined seeds. */ -fun loadPresetSchemas(): SudokuSchemas { +public fun loadPresetSchemas(): SudokuSchemas { return SudokuSchemas { addAll(fourDigitsSchemas) addAll(nineDigitsSchemas) diff --git a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/SixteenDigitsSchemas.kt b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/SixteenDigitsSchemas.kt index e6a6b40..edef392 100644 --- a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/SixteenDigitsSchemas.kt +++ b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/SixteenDigitsSchemas.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.presets -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.schema.SudokuSchema @@ -26,7 +23,7 @@ import dev.teogor.sudoklify.schema.SudokuSchema /** * An array of `SudokuSchema` objects representing easy 16x16 Sudoku puzzles. */ -val sixteenDigitsSchemas: Array = arrayOf( +public val sixteenDigitsSchemas: Array = arrayOf( // Remaining Digits 130 SudokuSchema( puzzle = "AdA-----EHD----AeC-----A---B--Af-----Ab-G--H--C-AF-------Aj-AaF-EAe--H--AbCAa-AeEIDGAj-HBAf---AjDAd--G-AeFEICA-EIAe-C-AbBAcAa-HD-Aj-HG-FD-----Af--AeEAcAjAeA--C-----AbE-IB-Ad-IAe-AaAbEH-Aj-AcFA-AaECAjBA-Ae--IGAf---DFH-EIAcAAdB-AaAjAb--Aj--ED-AfI-H-------AcG-Ab--Af--Ad-E-----Ad--G---A-----AAf----CFB-----AaAj", diff --git a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/TwentyFiveDigitsSchemas.kt b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/TwentyFiveDigitsSchemas.kt index 7fbed86..d2e7b24 100644 --- a/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/TwentyFiveDigitsSchemas.kt +++ b/sudoklify-presets/src/commonMain/kotlin/dev/teogor/sudoklify/presets/TwentyFiveDigitsSchemas.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.presets -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.schema.SudokuSchema @@ -26,7 +23,7 @@ import dev.teogor.sudoklify.schema.SudokuSchema /** * An array of `SudokuSchema` objects representing easy 16x16 Sudoku puzzles. */ -val twentyFiveDigitsSchemas: Array = arrayOf( +public val twentyFiveDigitsSchemas: Array = arrayOf( // Remaining Digits 320 SudokuSchema( puzzle = "-----Ah---HAdAc--Ai-BeBb-Af-BaBj------AcC---BAgBj-BbA--HDBa-BcAfBeE-AhAiFAj-Ab-GD--Ba--AeC-AdAaBb-Ag-Ac-Be--H--BaA-BcD---IBG-Ac--Ad-AaG---Af-AgAdAiBb-AaAe-CBc-Ab--D----Af--AgG--H-E-BbB-BdAcAb----C-Ae-D---B-Ae-Ad--AbBc---Bd-Bb-AfAaHAj--A--Bd--Ai-BaAaFAc-----EDBj--B--AcFAdAbIBb-AfBc-Aj-Ag-AaA-CBe-D-BaAiAa-BeAjAe-C--FE------Ah-Ai--Ab--Ai---AaFBa-IAhDBc-B---A-E--Aj-AeF---BbB---AaAbI---Bj-----A--------AjEBdAgAiAf-A-BjBFBcHBb--------Af-----Ac---EBbAb---AeAa---BBe-Bc--Ab-Ae---G-AiAcBdAj-ICBa---Af--B--Ai-Ag------EAd--Ba-AeAbAa-BdAAe-Be-GAc-BjAj-Bd-Ab-AiAh-BcHAdBbBaE--Bb--BcAaH-----AiBaAfE-F--A--C--DCAhF-Be-Ba---AdH--Ag-Aa-I---Bj-Aa-E----BdAfA-CBj-Aj-D--BcB--Be----Ad--F-GH-ID-BeAfBdAh-C---AAb-Ah--Ad-EHI---BeB-AaAg--Bd--G-Bb-Bd-EBaB-AaAe--Ah--GBj-A-AiFBeAd-BjAiIA-AfBdBe--GE-AjAeC---FAg------AaG-Bc-AhC-Bd--AcFH---Aj-----", diff --git a/sudoklify-presets/src/commonTest/kotlin/dev/teogor/sudoklify/presets/PresetSchemasTest.kt b/sudoklify-presets/src/commonTest/kotlin/dev/teogor/sudoklify/presets/PresetSchemasTest.kt index 37023f5..d829e9f 100644 --- a/sudoklify-presets/src/commonTest/kotlin/dev/teogor/sudoklify/presets/PresetSchemasTest.kt +++ b/sudoklify-presets/src/commonTest/kotlin/dev/teogor/sudoklify/presets/PresetSchemasTest.kt @@ -16,7 +16,6 @@ package dev.teogor.sudoklify.presets -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.mapToSudokuBoard @@ -29,7 +28,6 @@ import kotlin.test.assertFailsWith import kotlin.test.assertNotNull import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class PresetSchemasTest { @Test @@ -146,11 +144,11 @@ class PresetSchemasTest { // Optionally, add more detailed checks to validate the board's correctness assertTrue( solutionBoard.isNotEmpty(), - "Solution board should be valid for SudokuType $type" + "Solution board should be valid for SudokuType $type", ) assertTrue( puzzleBoard.isNotEmpty(), - "Puzzle board should be valid for SudokuType $type" + "Puzzle board should be valid for SudokuType $type", ) } } diff --git a/sudoklify-solver/build.gradle.kts b/sudoklify-solver/build.gradle.kts index 7bbe30a..0589e1f 100644 --- a/sudoklify-solver/build.gradle.kts +++ b/sudoklify-solver/build.gradle.kts @@ -31,6 +31,10 @@ winds { } kotlin { + explicitApi() + + applyDefaultHierarchyTemplate() + jvm { kotlin { jvmToolchain(11) @@ -82,5 +86,7 @@ kotlin { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { freeCompilerArgs.add("-Xexpect-actual-classes") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.InternalSudoklifyApi") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.ExperimentalSudoklifyApi") } } diff --git a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/GridMistakeChecker.kt b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/GridMistakeChecker.kt index d340421..ab4d25e 100644 --- a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/GridMistakeChecker.kt +++ b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/GridMistakeChecker.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.solver -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.BoxCoordinates import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.components.getBoxCoordinates @@ -38,7 +35,7 @@ import dev.teogor.sudoklify.components.isDigitValid * * @return The updated grid with potential mistake annotations. */ -inline fun List>.processGridMistakes( +public inline fun List>.processGridMistakes( mistakesMethod: MistakeCheckingMode, dimension: Dimension, crossinline getValue: (T) -> Int, @@ -57,7 +54,7 @@ inline fun List>.processGridMistakes( return checkedBoard.toUserGrid(updateCell, this) } -fun List>.checkMistakesAll( +public fun List>.checkMistakesAll( mistakesMethod: MistakeCheckingMode, dimension: Dimension, ): List> { @@ -97,7 +94,7 @@ fun List>.checkMistakesAll( return newBoard } -fun Dimension.doesCellValueViolateRules( +public fun Dimension.doesCellValueViolateRules( row: Int, col: Int, value: Int, diff --git a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/MistakeCheckingMode.kt b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/MistakeCheckingMode.kt index cd601a2..e070b12 100644 --- a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/MistakeCheckingMode.kt +++ b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/MistakeCheckingMode.kt @@ -23,7 +23,7 @@ package dev.teogor.sudoklify.solver * Depending on the selected mode, the application will either disable mistake checking, * check for violations only, or check against the final solution. */ -enum class MistakeCheckingMode { +public enum class MistakeCheckingMode { /** * Disables mistake checking. * diff --git a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifyMoveAdvisor.kt b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifyMoveAdvisor.kt index 2224edd..ac4df12 100644 --- a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifyMoveAdvisor.kt +++ b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifyMoveAdvisor.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.solver -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Dimension import kotlin.random.Random @@ -27,7 +24,7 @@ import kotlin.random.Random * * @property dimension The dimension of the Sudoku grid, which provides size and box details. */ -class SudoklifyMoveAdvisor( +public class SudoklifyMoveAdvisor( private val dimension: Dimension, ) { private val size = dimension.uniqueDigitsCount @@ -39,7 +36,7 @@ class SudoklifyMoveAdvisor( * @param grid The current grid represented as a 2D array of integers. * @return A [SudokuMove] indicating the row, column, and value of the suggested move, or `null` if no move is suggested. */ - fun suggestNextMove(grid: Array): SudokuMove? { + public fun suggestNextMove(grid: Array): SudokuMove? { // List of empty cells with their coordinates val emptyCells = mutableListOf>() for (row in 0 until size) { diff --git a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifySolverEngine.kt b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifySolverEngine.kt index 36b400c..96d0eed 100644 --- a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifySolverEngine.kt +++ b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudoklifySolverEngine.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.solver -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.SudoklifyDsl import dev.teogor.sudoklify.puzzle.SudokuPuzzle @@ -29,8 +26,7 @@ import dev.teogor.sudoklify.puzzle.SudokuPuzzle * @property gridProcessor A [SudokuGridProcessor] instance responsible for grid processing and mistake checking. * @property puzzle The [SudokuPuzzle] configuration, including difficulty, type, seed, givens, solution, and hints. */ -@OptIn(ExperimentalSudoklifyApi::class) -class SudoklifySolverEngine( +public class SudoklifySolverEngine( private val gridProcessor: SudokuGridProcessor, private val puzzle: SudokuPuzzle, ) { @@ -38,7 +34,7 @@ class SudoklifySolverEngine( * The mode used for checking mistakes during puzzle solving. * Default is [MistakeCheckingMode.CheckViolations]. */ - var mistakeCheckingMode: MistakeCheckingMode = MistakeCheckingMode.CheckViolations + public var mistakeCheckingMode: MistakeCheckingMode = MistakeCheckingMode.CheckViolations // Extract dimension and grid from the SudokuPuzzle private val dimension = puzzle.type @@ -50,11 +46,10 @@ class SudoklifySolverEngine( * @param grid The current grid to analyze for suggesting the next move. * @return A [SudokuMove] representing the row, column, and the single possible value for the next move, or `null` if no move is suggested. */ - fun suggestNextMove(grid: List>): SudokuMove? { - val intGrid = - grid.map { row -> - row.map { cell -> gridProcessor.getValue(cell) }.toIntArray() - }.toTypedArray() + public fun suggestNextMove(grid: List>): SudokuMove? { + val intGrid = grid.map { row -> + row.map { cell -> gridProcessor.getValue(cell) }.toIntArray() + }.toTypedArray() return moveAdvisor.suggestNextMove(intGrid) } @@ -65,7 +60,7 @@ class SudoklifySolverEngine( * @param grid The grid to process. * @return The updated grid with potential mistake annotations. */ - fun processGridMistakes(grid: List>): List> { + public fun processGridMistakes(grid: List>): List> { return gridProcessor.processGridMistakes( grid, mistakeCheckingMode, @@ -84,7 +79,7 @@ class SudoklifySolverEngine( * @return A new [SudoklifySolverEngine] instance. */ @SudoklifyDsl -inline fun SudoklifySolverEngine( +public inline fun SudoklifySolverEngine( gridProcessor: SudokuGridProcessor, puzzle: SudokuPuzzle, mistakeCheckingMode: MistakeCheckingMode = MistakeCheckingMode.CheckViolations, diff --git a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuCellState.kt b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuCellState.kt index b93d81e..548a096 100644 --- a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuCellState.kt +++ b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuCellState.kt @@ -32,7 +32,7 @@ import dev.teogor.sudoklify.components.Dimension * @see [Dimension] for dimensions and rules applied to Sudoku grids. * @see [SudokuSolver] for methods that solve Sudoku puzzles. */ -data class SudokuCellState( +public data class SudokuCellState( /** * The current value of the cell in the Sudoku grid. */ @@ -64,7 +64,7 @@ data class SudokuCellState( * * @return A grid of `SudokuCellState`. */ -inline fun List>.toSudokuCellStates( +public inline fun List>.toSudokuCellStates( crossinline getValue: (T) -> Int, crossinline isLocked: (T) -> Boolean, crossinline getSolution: (T) -> Int, @@ -90,7 +90,7 @@ inline fun List>.toSudokuCellStates( * * @return The updated grid of the original type. */ -inline fun List>.toUserGrid( +public inline fun List>.toUserGrid( crossinline updateCell: (row: Int, col: Int, SudokuCellState, T) -> T, originalGrid: List>, ): List> { diff --git a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuGridProcessor.kt b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuGridProcessor.kt index 0e81ccd..efec2f5 100644 --- a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuGridProcessor.kt +++ b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuGridProcessor.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSudoklifyApi::class) - package dev.teogor.sudoklify.solver -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Dimension /** @@ -26,31 +23,31 @@ import dev.teogor.sudoklify.components.Dimension * * @param T The type of the user grid cells. */ -interface SudokuGridProcessor { +public interface SudokuGridProcessor { /** * Provides the lambda function to get the value of a cell. */ - val getValue: (T) -> Int + public val getValue: (T) -> Int /** * Provides the lambda function to determine if a cell is locked. */ - val isLocked: (T) -> Boolean + public val isLocked: (T) -> Boolean /** * Provides the lambda function to get the solution value of a cell. */ - val getSolution: (T) -> Int + public val getSolution: (T) -> Int /** * Provides the lambda function to determine if a cell has an error state. */ - val isError: (T) -> Boolean + public val isError: (T) -> Boolean /** * Provides the lambda function to update a cell in the original grid type. */ - val updateCell: (row: Int, col: Int, SudokuCellState, cell: T) -> T + public val updateCell: (row: Int, col: Int, SudokuCellState, cell: T) -> T /** * Processes the grid to check for mistakes and convert it back to the original grid type. @@ -60,7 +57,7 @@ interface SudokuGridProcessor { * @param dimension The dimension used for Sudoku rules. * @return The updated grid with potential mistake annotations. */ - fun processGridMistakes( + public fun processGridMistakes( grid: List>, mistakesMethod: MistakeCheckingMode, dimension: Dimension, @@ -93,7 +90,7 @@ interface SudokuGridProcessor { * @param updateCell Lambda function to update a cell in the original grid type. * @return A [SudokuGridProcessor] implementation with the provided functions. */ -fun createSudokuGridProcessor( +public fun createSudokuGridProcessor( getValue: (T) -> Int, isLocked: (T) -> Boolean, getSolution: (T) -> Int, diff --git a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuMove.kt b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuMove.kt index 7d99ec8..31aa055 100644 --- a/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuMove.kt +++ b/sudoklify-solver/src/commonMain/kotlin/dev/teogor/sudoklify/solver/SudokuMove.kt @@ -23,7 +23,7 @@ package dev.teogor.sudoklify.solver * @property col The column index where the move can be made. * @property value The single possible value that can be placed in the cell. */ -data class SudokuMove( +public data class SudokuMove( val row: Int, val col: Int, val value: Int, diff --git a/sudoklify-solver/src/commonTest/kotlin/dev/teogor/sudoklify/solver/SudokuCellStateTest.kt b/sudoklify-solver/src/commonTest/kotlin/dev/teogor/sudoklify/solver/SudokuCellStateTest.kt index 802da0d..600786e 100644 --- a/sudoklify-solver/src/commonTest/kotlin/dev/teogor/sudoklify/solver/SudokuCellStateTest.kt +++ b/sudoklify-solver/src/commonTest/kotlin/dev/teogor/sudoklify/solver/SudokuCellStateTest.kt @@ -16,7 +16,6 @@ package dev.teogor.sudoklify.solver -import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.SudoklifyArchitect import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension @@ -29,7 +28,6 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -@OptIn(ExperimentalSudoklifyApi::class) class SudokuCellStateTest { private val architect = SudoklifyArchitect(loadPresetSchemas()) diff --git a/sudoklify-tokenizer/build.gradle.kts b/sudoklify-tokenizer/build.gradle.kts index f7e47a3..02fa2d4 100644 --- a/sudoklify-tokenizer/build.gradle.kts +++ b/sudoklify-tokenizer/build.gradle.kts @@ -31,6 +31,10 @@ winds { } kotlin { + explicitApi() + + applyDefaultHierarchyTemplate() + jvm { kotlin { jvmToolchain(11) @@ -80,5 +84,7 @@ kotlin { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { freeCompilerArgs.add("-Xexpect-actual-classes") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.InternalSudoklifyApi") + freeCompilerArgs.add("-opt-in=dev.teogor.sudoklify.ExperimentalSudoklifyApi") } } diff --git a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCell.kt b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCell.kt index f4c342d..bce116f 100644 --- a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCell.kt +++ b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCell.kt @@ -29,13 +29,13 @@ import kotlin.jvm.JvmInline * ``` */ @JvmInline -value class JEncodedCell(val value: String) { +public value class JEncodedCell(public val value: String) { /** * Converts this [JEncodedCell] to its corresponding integer value. * * @return The integer value represented by the [JEncodedCell], using base-10 encoding. */ - fun toInt(): Int { + public fun toInt(): Int { return when { value == "-" -> 0 @@ -60,8 +60,8 @@ value class JEncodedCell(val value: String) { override fun toString(): String = value - companion object { - val regex = """([A-I][a-z]+)|-|[A-I]""".toRegex() + public companion object { + public val regex: Regex = """([A-I][a-z]+)|-|[A-I]""".toRegex() /** * Validates if a given string contains only valid JEncodedCells. @@ -69,7 +69,7 @@ value class JEncodedCell(val value: String) { * @param input The string to validate. * @return `true` if the string is valid, `false` otherwise. */ - fun isValid(input: String): Boolean { + public fun isValid(input: String): Boolean { val matches = regex.findAll(input) // Join all the matched parts and compare it with the original string // This ensures that the entire string is composed of valid components @@ -83,7 +83,7 @@ value class JEncodedCell(val value: String) { * @param input The string representing the Sudoku board. * @return A list of [JEncodedCell] extracted from the input string. */ - fun extractCells(input: String): List { + public fun extractCells(input: String): List { return regex.findAll(input).map { JEncodedCell(it.value) }.toList() } @@ -93,7 +93,7 @@ value class JEncodedCell(val value: String) { * @param input The string to check. * @return A list of invalid components found in the string. */ - fun findInvalidComponents(input: String): List { + public fun findInvalidComponents(input: String): List { val validMatches = regex.findAll(input).map { it.range }.toList() val invalidComponents = mutableListOf() @@ -131,7 +131,7 @@ value class JEncodedCell(val value: String) { * @return The [JEncodedCell] string representation of the cell, using letters 'a' to 'j' * (where 'j' is used for 0), and capitalizing the first letter. */ -fun Int.toJEncodedCell(): JEncodedCell { +public fun Int.toJEncodedCell(): JEncodedCell { val encodedString = when { this == 0 -> "-" @@ -180,6 +180,6 @@ fun Int.toJEncodedCell(): JEncodedCell { * @receiver The string representation of the Sudoku cell. * @return A [JEncodedCell] instance initialized with the string. */ -fun String.toJEncodedCell(): JEncodedCell { +public fun String.toJEncodedCell(): JEncodedCell { return JEncodedCell(this) } diff --git a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Layout.kt b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Layout.kt index 4b50518..70ee085 100644 --- a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Layout.kt +++ b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Layout.kt @@ -16,4 +16,4 @@ package dev.teogor.sudoklify.tokenizer -typealias Layout = Array +public typealias Layout = Array diff --git a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/SudokuString.kt b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/SudokuString.kt index 9e8d408..d686c92 100644 --- a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/SudokuString.kt +++ b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/SudokuString.kt @@ -19,7 +19,7 @@ package dev.teogor.sudoklify.tokenizer import kotlin.jvm.JvmInline @JvmInline -value class SudokuString(val value: String) { +public value class SudokuString(public val value: String) { init { if (value.isEmpty()) { throw EmptySudokuStringException("Value must not be empty.") @@ -34,10 +34,10 @@ value class SudokuString(val value: String) { override fun toString(): String = value } -fun String.toSudokuString(): SudokuString { +public fun String.toSudokuString(): SudokuString { return SudokuString(this) } -class EmptySudokuStringException(message: String) : IllegalArgumentException(message) +public class EmptySudokuStringException(message: String) : IllegalArgumentException(message) -class InvalidSudokuValueException(message: String) : IllegalArgumentException(message) +public class InvalidSudokuValueException(message: String) : IllegalArgumentException(message) diff --git a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/TokenMap.kt b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/TokenMap.kt index 6c016ed..916cdda 100644 --- a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/TokenMap.kt +++ b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/TokenMap.kt @@ -16,4 +16,4 @@ package dev.teogor.sudoklify.tokenizer -typealias TokenMap = Map +public typealias TokenMap = Map diff --git a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Tokenizer.kt b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Tokenizer.kt index 0e0ba03..e555816 100644 --- a/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Tokenizer.kt +++ b/sudoklify-tokenizer/src/commonMain/kotlin/dev/teogor/sudoklify/tokenizer/Tokenizer.kt @@ -24,7 +24,7 @@ package dev.teogor.sudoklify.tokenizer * * @constructor Creates a Tokenizer instance with the specified number of digits. */ -sealed class Tokenizer { +public sealed class Tokenizer { /** * Replaces tokens in a given sequence using a token map. * @@ -32,7 +32,7 @@ sealed class Tokenizer { * @param tokenMap A map of tokens to their replacement values. * @return The sequence with replaced tokens. */ - abstract fun replaceTokens( + public abstract fun replaceTokens( sequence: String, tokenMap: TokenMap, ): String @@ -45,20 +45,20 @@ sealed class Tokenizer { * @param tokenMap A map of tokens to their replacement values. * @return The populated board. */ - abstract fun populateLayout( + public abstract fun populateLayout( layout: Layout, sequence: String, tokenMap: TokenMap, ): Array> - companion object { + public companion object { /** * Creates a Tokenizer instance based on the number of digits. * * @param digits The number of digits used for tokenization. * @return A SingleDigitTokenizer for 1-9 digits, or a MultiDigitTokenizer otherwise. */ - fun create(digits: Int): Tokenizer { + public fun create(digits: Int): Tokenizer { return when (digits) { in 1..9 -> SingleDigitTokenizer else -> MultiDigitTokenizer(digits) @@ -69,8 +69,7 @@ sealed class Tokenizer { /** * A tokenizer for sequences with single-digit tokens. */ - data object SingleDigitTokenizer : Tokenizer() { - // @OptIn(InternalSudoklifyApi::class) + public data object SingleDigitTokenizer : Tokenizer() { override fun replaceTokens( sequence: String, tokenMap: TokenMap, @@ -100,10 +99,9 @@ sealed class Tokenizer { /** * A tokenizer for sequences with multi-digit tokens. */ - class MultiDigitTokenizer( + public class MultiDigitTokenizer( private val digits: Int, ) : Tokenizer() { - // @OptIn(InternalSudoklifyApi::class) override fun replaceTokens( sequence: String, tokenMap: TokenMap, @@ -130,7 +128,6 @@ sealed class Tokenizer { }.toTypedArray() } - // @OptIn(InternalSudoklifyApi::class) internal fun extractTokens( sequence: String, tokenMap: TokenMap, diff --git a/sudoklify-tokenizer/src/commonTest/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCellTest.kt b/sudoklify-tokenizer/src/commonTest/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCellTest.kt index 3131d79..9653df7 100644 --- a/sudoklify-tokenizer/src/commonTest/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCellTest.kt +++ b/sudoklify-tokenizer/src/commonTest/kotlin/dev/teogor/sudoklify/tokenizer/JEncodedCellTest.kt @@ -20,7 +20,6 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals -// @OptIn(InternalSudoklifyApi::class) class JEncodedCellTest { @Test fun testToInt_whenSingleDigit_thenCorrectInteger() {