All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.mahjongutils.models.Furo.kt Maven / Gradle / Ivy

The newest version!
@file:OptIn(ExperimentalSerializationApi::class)

package mahjongutils.models

import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * 副露
 */
@Serializable
sealed interface Furo {
    /**
     * 获取副露的面子
     */
    fun asMentsu(): Mentsu

    val tiles: List

    companion object {
        /**
         * 根据给定牌构造副露
         * @param tiles 牌
         * @param ankan 是否为暗杠
         * @return 副露
         */
        fun parse(tiles: List, ankan: Boolean = false): Furo {
            if (tiles.size == 3) {
                if (tiles[0] == tiles[1] && tiles[1] == tiles[2]) {
                    return Pon(tiles[0])
                } else {
                    if (tiles.any { it.type == TileType.Z }) {
                        throw IllegalArgumentException("invalid tiles: ${tiles.toTilesString()}")
                    }

                    val tiles = tiles.sorted()
                    if (tiles[1].distance(tiles[0]) == 1 && tiles[2].distance(tiles[1]) == 1) {
                        return Chi(tiles[0])
                    } else {
                        throw IllegalArgumentException("invalid tiles: ${tiles.toTilesString()}")
                    }
                }
            } else if (tiles.size == 4) {
                if (tiles[0] == tiles[1] && tiles[1] == tiles[2] && tiles[2] == tiles[3]) {
                    return Kan(tiles[0], ankan)
                }
            }

            throw IllegalArgumentException("invalid tiles: ${tiles.toTilesString()}")
        }

        /**
         * 根据给定牌构造副露
         * @param text 牌的文本
         * @param ankan 是否为暗杠
         * @return 副露
         */
        fun parse(text: String, ankan: Boolean = false): Furo {
            var ankan_ = ankan

            val tiles = if (text.length == 5 && text[0] == text[3] && text[0] == '0' && text[1] == text[2]) {
                ankan_ = true
                Tile.parseTiles("${text[1]}${text[1]}${text[1]}${text[1]}${text[4]}")
            } else {
                Tile.parseTiles(text)
            }

            return parse(tiles, ankan_)
        }
    }
}

fun Furo(vararg tiles: Tile, ankan: Boolean = false): Furo {
    return Furo.parse(tiles.toList(), ankan)
}

fun Furo(tiles: List, ankan: Boolean = false): Furo {
    return Furo.parse(tiles, ankan)
}

fun Furo(text: String, ankan: Boolean = false): Furo {
    return Furo.parse(text, ankan)
}

/**
 * 吃
 */
@Serializable
@SerialName("Chi")
data class Chi(
    /**
     * 吃成的顺子的第一张牌(如789m,tile应为7m)
     */
    val tile: Tile
) : Furo {
    override fun asMentsu(): Shuntsu {
        return Shuntsu(tile)
    }

    override val tiles: List
        get() = listOf(tile, tile.advance(1), tile.advance(2))
}

/**
 * 碰
 */
@Serializable
@SerialName("Pon")
data class Pon(
    /**
     * 碰成的刻子的牌(如777s,tile应为7s)
     */
    val tile: Tile
) : Furo {
    override fun asMentsu(): Kotsu {
        return Kotsu(tile)
    }

    override val tiles: List
        get() = listOf(tile, tile, tile)
}

/**
 * 杠
 */
@Serializable
@SerialName("Kan")
data class Kan(
    /**
     * 杠成的刻子的牌(如7777s,tile应为7s)
     */
    val tile: Tile,
    /**
     * 是否为暗杠
     */
    @EncodeDefault val ankan: Boolean = false
) : Furo {
    override fun asMentsu(): Kotsu {
        return Kotsu(tile)
    }

    override val tiles: List
        get() = listOf(tile, tile, tile, tile)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy