commonMain.mahjongutils.shanten.helpers.HandPatternUtils.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mahjong-utils-jvm Show documentation
Show all versions of mahjong-utils-jvm Show documentation
Mahjong Utils (for Japanese Riichi Mahjong)
package mahjongutils.shanten.helpers
import mahjongutils.models.Tatsu
import mahjongutils.models.Tile
import mahjongutils.models.TileType
import mahjongutils.models.hand.ChitoiHandPattern
import mahjongutils.models.hand.KokushiHandPattern
import mahjongutils.models.hand.RegularHandPattern
internal fun RegularHandPattern.calcShanten(): Int {
var shanten = 2 * (k - menzenMentsu.size - furo.size) - tatsu.size
if (jyantou != null) {
shanten -= 1
}
return shanten
}
internal fun ChitoiHandPattern.calcShanten(): Int {
val tileSet = buildSet {
addAll(pairs)
addAll(remaining)
}
if (tileSet.size >= 7) {
return 6 - pairs.size
} else {
return 6 - pairs.size + (7 - tileSet.size)
}
}
internal fun KokushiHandPattern.calcShanten(): Int {
return if (repeated != null) {
// 非十三面
12 - yaochu.size
} else {
// 十三面
13 - yaochu.size
}
}
internal val TILE_CLING = buildMap> {
repeat(3) {
val type = TileType.valueOf(it)
for (j in 1..9) {
val t = Tile.get(type, j)
this[t] = listOf(-2, -1, 0, 1, 2)
.filter { k -> j + k in 1..9 }
.map { k -> Tile.get(type, j + k) }
.toSet()
}
}
for (j in 1..7) {
val t = Tile.get(TileType.Z, j)
this[t] = setOf(t)
}
}
internal fun RegularHandPattern.calcAdvance(): Set {
return buildSet {
// 搭子的进张
for (tt in tatsu) {
addAll(tt.waiting)
}
// 浮张的靠张
if (furo.size + menzenMentsu.size + tatsu.size < k) {
for (t in remaining) {
addAll(TILE_CLING[t]!!)
}
}
// 无雀头
if (jyantou == null) {
for (t in remaining) {
add(t)
}
}
}
}
/**
* 计算已摸牌的和牌手牌舍张后的所有可能的听牌形
* @param discard 舍张
* @return 所有可能手牌形
*/
internal fun RegularHandPattern.afterDiscardForHoraHand(discard: Tile): List {
return buildList {
// 扣掉雀头
if (jyantou == discard) {
val newPattern = copy(jyantou = null, remaining = remaining + discard)
add(newPattern)
}
// 扣掉面子
menzenMentsu.forEachIndexed { i, mt ->
if (discard in mt.tiles) {
val tt = mt.afterDiscard(discard)
val newPattern = copy(
menzenMentsu = menzenMentsu.slice(0 until i) + menzenMentsu.slice(i + 1 until menzenMentsu.size),
tatsu = tatsu + tt
)
add(newPattern)
}
}
// 扣掉搭子
tatsu.forEachIndexed { i, tt ->
if (discard == tt.first) {
val newPattern = copy(
tatsu = tatsu.slice(0 until i) + tatsu.slice(i + 1 until tatsu.size),
remaining = remaining + tt.second
)
add(newPattern)
} else if (discard == tt.second) {
val newPattern = copy(
tatsu = tatsu.slice(0 until i) + tatsu.slice(i + 1 until tatsu.size),
remaining = remaining + tt.first
)
add(newPattern)
}
}
// 扣掉浮张
val idx = remaining.indexOf(discard)
if (idx != -1) {
val newPattern = copy(
remaining = remaining.slice(0 until idx) + remaining.slice(idx + 1 until remaining.size),
)
add(newPattern)
}
}
}
/**
* 计算未摸牌的一向听手牌形进张后的所有可能手牌形
* @param advance 进张
* @return 所有可能手牌形
*/
internal fun RegularHandPattern.afterAdvanceForOneShantenHand(advance: Tile): List {
return buildList {
// 搭子的进张
tatsu.forEachIndexed { i, tt ->
if (advance in tt.waiting) {
val newPattern = copy(
menzenMentsu = menzenMentsu + tt.withWaiting(advance),
tatsu = tatsu.slice(0 until i) + tatsu.slice(i + 1 until tatsu.size)
)
add(newPattern)
}
}
// 浮张的靠张
if (furo.size + menzenMentsu.size + tatsu.size < k) {
remaining.forEachIndexed { i, t ->
if (advance in TILE_CLING[t]!!) {
val newPattern = copy(
tatsu = tatsu + Tatsu(advance, t),
remaining = remaining.slice(0 until i) + remaining.slice(i + 1 until remaining.size)
)
add(newPattern)
}
}
}
// 无雀头
if (jyantou == null) {
val idx = remaining.indexOf(advance)
if (idx != -1) {
val newPattern = copy(
jyantou = advance,
remaining = remaining.slice(0 until idx) + remaining.slice(idx + 1 until remaining.size)
)
add(newPattern)
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy