commonMain.dev.teogor.sudoklify.tokenizer.Tokenizer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sudoklify-tokenizer Show documentation
Show all versions of sudoklify-tokenizer Show documentation
Sudoklify stands as a versatile and user-friendly Sudoku puzzle generation library crafted in Kotlin. Effortlessly generate, manipulate, and solve Sudoku puzzles with ease.
The newest version!
/*
* Copyright 2023 Teogor (Teodor Grigor)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.teogor.sudoklify.tokenizer
// import dev.teogor.sudoklify.InternalSudoklifyApi
/**
* 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
/**
* 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,
tokenMap: TokenMap,
): Array>
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 when (digits) {
in 1..9 -> SingleDigitTokenizer
else -> MultiDigitTokenizer(digits)
}
}
}
/**
* A tokenizer for sequences with single-digit tokens.
*/
data object SingleDigitTokenizer : Tokenizer() {
// @OptIn(InternalSudoklifyApi::class)
override fun replaceTokens(
sequence: String,
tokenMap: TokenMap,
): String {
val result = StringBuilder()
sequence.forEach { char ->
result.append(tokenMap[JEncodedCell(char.toString())] ?: char)
}
return result.toString()
}
override fun populateLayout(
layout: Layout,
sequence: String,
tokenMap: TokenMap,
): Array> {
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() {
// @OptIn(InternalSudoklifyApi::class)
override fun replaceTokens(
sequence: String,
tokenMap: TokenMap,
): String {
// TODO regex to be used in JEncodedCell
val regex = Regex("([A-I][a-z]+)|-|[A-I][A-I]+")
return regex.replace(sequence) { matchResult ->
val token = matchResult.value
tokenMap[JEncodedCell(token)] ?: token
}
}
override fun populateLayout(
layout: Layout,
sequence: String,
tokenMap: TokenMap,
): Array> {
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()
}
// @OptIn(InternalSudoklifyApi::class)
internal fun extractTokens(
sequence: String,
tokenMap: TokenMap,
): List {
val regex = Regex("([A-I][a-j]+)|-|[A-I]")
return regex.findAll(sequence).map { match ->
tokenMap[JEncodedCell(match.value)] ?: match.value
}.toList()
}
}
}