Skip to content

Commit

Permalink
Merge pull request #48 from teogor/feature/sealed-tokenizer
Browse files Browse the repository at this point in the history
Enhance Tokenizer with sealed class structure and improved token handling
  • Loading branch information
teogor authored Feb 20, 2024
2 parents 41b9cb0 + 48c6521 commit 515a882
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 157 deletions.
31 changes: 16 additions & 15 deletions sudoklify-core/api/sudoklify-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,29 @@ public final class dev/teogor/sudoklify/core/solver/SudokuSolver {
public final fun solve ()Ldev/teogor/sudoklify/common/model/SudokuSolution;
}

public final class dev/teogor/sudoklify/core/tokenizer/MultiDigitTokenizer : dev/teogor/sudoklify/core/tokenizer/Tokenizer {
public fun <init> (I)V
public fun populateLayout ([[ILjava/lang/String;)[[Ljava/lang/String;
public final fun populateLayout ([[ILjava/lang/String;Ljava/util/Map;)[[Ljava/lang/String;
public fun replaceTokens (Ljava/lang/String;Ljava/util/Map;)Ljava/lang/String;
public abstract class dev/teogor/sudoklify/core/tokenizer/Tokenizer {
public static final field Companion Ldev/teogor/sudoklify/core/tokenizer/Tokenizer$Companion;
public abstract fun populateLayout ([[ILjava/lang/String;Ljava/util/Map;)[[Ljava/lang/String;
public abstract fun replaceTokens (Ljava/lang/String;Ljava/util/Map;)Ljava/lang/String;
}

public final class dev/teogor/sudoklify/core/tokenizer/SingleDigitTokenizer : dev/teogor/sudoklify/core/tokenizer/Tokenizer {
public fun <init> ()V
public fun populateLayout ([[ILjava/lang/String;)[[Ljava/lang/String;
public fun replaceTokens (Ljava/lang/String;Ljava/util/Map;)Ljava/lang/String;
public final class dev/teogor/sudoklify/core/tokenizer/Tokenizer$Companion {
public final fun create (I)Ldev/teogor/sudoklify/core/tokenizer/Tokenizer;
}

public class dev/teogor/sudoklify/core/tokenizer/Tokenizer {
public static final field Companion Ldev/teogor/sudoklify/core/tokenizer/Tokenizer$Companion;
public fun <init> ()V
public fun populateLayout ([[ILjava/lang/String;)[[Ljava/lang/String;
public final class dev/teogor/sudoklify/core/tokenizer/Tokenizer$MultiDigitTokenizer : dev/teogor/sudoklify/core/tokenizer/Tokenizer {
public fun <init> (I)V
public fun populateLayout ([[ILjava/lang/String;Ljava/util/Map;)[[Ljava/lang/String;
public fun replaceTokens (Ljava/lang/String;Ljava/util/Map;)Ljava/lang/String;
}

public final class dev/teogor/sudoklify/core/tokenizer/Tokenizer$Companion {
public final fun create (I)Ldev/teogor/sudoklify/core/tokenizer/Tokenizer;
public final class dev/teogor/sudoklify/core/tokenizer/Tokenizer$SingleDigitTokenizer : dev/teogor/sudoklify/core/tokenizer/Tokenizer {
public static final field INSTANCE Ldev/teogor/sudoklify/core/tokenizer/Tokenizer$SingleDigitTokenizer;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun populateLayout ([[ILjava/lang/String;Ljava/util/Map;)[[Ljava/lang/String;
public fun replaceTokens (Ljava/lang/String;Ljava/util/Map;)Ljava/lang/String;
public fun toString ()Ljava/lang/String;
}

public final class dev/teogor/sudoklify/core/util/BoardConversionsKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import dev.teogor.sudoklify.common.types.Layout
import dev.teogor.sudoklify.common.types.SudokuString
import dev.teogor.sudoklify.common.types.TokenMap
import dev.teogor.sudoklify.core.io.toToken
import dev.teogor.sudoklify.core.tokenizer.MultiDigitTokenizer
import dev.teogor.sudoklify.core.tokenizer.Tokenizer
import dev.teogor.sudoklify.core.util.sortRandom
import dev.teogor.sudoklify.core.util.toBoard
Expand All @@ -41,7 +40,7 @@ internal class SudokuGenerator internal constructor(
private val gameType: GameType,
private val difficulty: Difficulty,
) {
private val random: Random
private val random: Random = Random(seed)
private val boxDigits = gameType.gridHeight * gameType.gridWidth
private val totalDigits = boxDigits * boxDigits
private val baseLayout: Layout = generateBaseLayout()
Expand All @@ -61,10 +60,6 @@ internal class SudokuGenerator internal constructor(
difficulty: Difficulty,
) : this(seeds, 0L, gameType, difficulty)

init {
random = Random(seed)
}

private fun generateBaseLayout(): Layout {
return Array(boxDigits) { i ->
IntArray(boxDigits) { j -> i * boxDigits + j }
Expand Down Expand Up @@ -130,15 +125,7 @@ internal class SudokuGenerator internal constructor(
layout: Layout,
seedSequence: String,
tokenMap: TokenMap,
): Board {
val grid =
if (tokenizer is MultiDigitTokenizer) {
tokenizer.populateLayout(layout, seedSequence, tokenMap)
} else {
tokenizer.populateLayout(layout, tokenizer.replaceTokens(seedSequence, tokenMap))
}
return grid
}
): Board = tokenizer.populateLayout(layout, seedSequence, tokenMap)

@Deprecated(message = "toSequenceString")
private fun boardToSequence(board: Board): SudokuString =
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,123 @@ import dev.teogor.sudoklify.common.types.Board
import dev.teogor.sudoklify.common.types.Layout
import dev.teogor.sudoklify.common.types.TokenMap

// TODO: convert to Sealed Class
open class Tokenizer {
open fun replaceTokens(
/**
* Represents a tokenizer responsible for replacing tokens in sequences and populating
* layouts.
*
* @constructor Creates a Tokenizer instance with the specified number of digits.
*/
sealed class Tokenizer {
/**
* Replaces tokens in a given sequence using a token map.
*
* @param sequence The input sequence containing tokens.
* @param tokenMap A map of tokens to their replacement values.
* @return The sequence with replaced tokens.
*/
abstract fun replaceTokens(
sequence: String,
tokenMap: TokenMap,
): String {
return ""
}
): String

open fun populateLayout(
/**
* Populates a layout with values from a sequence, replacing tokens as needed.
*
* @param layout The layout to be populated.
* @param sequence The input sequence containing tokens.
* @param tokenMap A map of tokens to their replacement values.
* @return The populated board.
*/
abstract fun populateLayout(
layout: Layout,
sequence: String,
): Board {
return emptyArray()
}
tokenMap: TokenMap,
): Board

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 {
return if (digits < 10) {
SingleDigitTokenizer()
} else {
MultiDigitTokenizer(digits)
return when (digits) {
in 1..9 -> SingleDigitTokenizer
else -> MultiDigitTokenizer(digits)
}
}
}

/**
* A tokenizer for sequences with single-digit tokens.
*/
data object SingleDigitTokenizer : Tokenizer() {
override fun replaceTokens(
sequence: String,
tokenMap: TokenMap,
): String {
val result = StringBuilder()
sequence.forEach { char ->
result.append(tokenMap[char.toString()] ?: char)
}
return result.toString()
}

override fun populateLayout(
layout: Layout,
sequence: String,
tokenMap: TokenMap,
): Board {
with(replaceTokens(sequence, tokenMap)) {
return layout.map { row ->
row.map { cell ->
this[cell].toString()
}.toTypedArray()
}.toTypedArray()
}
}
}

/**
* A tokenizer for sequences with multi-digit tokens.
*/
class MultiDigitTokenizer(
private val digits: Int,
) : Tokenizer() {
override fun replaceTokens(
sequence: String,
tokenMap: TokenMap,
): String {
val regex = Regex("([A-I][a-z]+)|-|[A-I][A-I]+")
return regex.replace(sequence) { matchResult ->
val token = matchResult.value
tokenMap[token] ?: token
}
}

override fun populateLayout(
layout: Layout,
sequence: String,
tokenMap: TokenMap,
): Board {
val tokens = extractTokens(sequence, tokenMap)
return layout.map { row ->
row.map { cell ->
val index = if (cell < digits) cell else cell - digits
tokens[index]
}.toTypedArray()
}.toTypedArray()
}

private fun extractTokens(
sequence: String,
tokenMap: TokenMap,
): List<String> {
val regex = Regex("([A-I][a-j]+)|-|[A-I]")
return regex.findAll(sequence).map { match ->
tokenMap[match.value] ?: match.value
}.toList()
}
}
}

0 comments on commit 515a882

Please sign in to comment.