kotlin 斗牛小游戏

Kotlin实现斗牛游戏的完整代码与解析

斗牛作为一款经典的纸牌游戏,凭借简单易懂的规则和富有乐趣的竞技性深受大众喜爱。本文将为大家展示一个完整的Kotlin实现版本,并解析其核心逻辑。

一、代码实现解析

1. 生成扑克牌组

首先需要生成一副完整的扑克牌,包含4种花色(黑桃♠、红桃♥、方块♦、梅花♣)和13种点数(A、2-10、J、Q、K):

kotlin 复制代码
fun generateDeck(): List<String> {
    val suits = listOf("♠", "♥", "♦", "♣")
    val ranks = listOf("A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K")
    return suits.flatMap { suit -> ranks.map { rank -> "$suit$rank" } }
}

这段代码通过flatMap将花色和点数组合,生成如"♠A"、"♥10"、"♦K"等格式的牌面字符串。

2. 牌面点数转换

游戏中需要将牌面转换为对应的点数,规则如下:

  • A算1点
  • J、Q、K算10点
  • 其他牌按数字本身算点
kotlin 复制代码
fun cardToPoint(card: String): Int {
    return when (val rank = card.substring(1)) {
        "A" -> 1
        "J", "Q", "K" -> 10
        else -> rank.toInt()
    }
}

3. 核心判定逻辑

斗牛游戏的核心在于判断手牌的"牛"等级,从高到低依次为:

五小牛

五张牌的点数都小于5,且总和不超过10:

kotlin 复制代码
fun isFiveLittleCow(points: List<Int>): Boolean {
    return points.all { it < 5 } && points.sum() <= 10
}
五花牛

五张牌都是10点牌(10、J、Q、K):

kotlin 复制代码
fun isFiveFlowerCow(points: List<Int>): Boolean {
    return points.all { it == 10 }
}
牛牛

五张牌中任意三张之和为10的倍数,剩余两张之和也为10的倍数:

kotlin 复制代码
fun isNiuNiu(points: List<Int>): Boolean {
    for (i in points.indices) {
        for (j in i + 1 until points.size) {
            for (k in j + 1 until points.size) {
                val sum3 = points[i] + points[j] + points[k]
                if (sum3 % 10 == 0) {
                    val remainingPoints = points.filterIndexed { idx, _ -> idx != i && idx != j && idx != k }
                    val sum2 = remainingPoints.sum()
                    if (sum2 % 10 == 0) {
                        return true
                    }
                }
            }
        }
    }
    return false
}
普通牛(牛一到牛十)

五张牌中任意三张之和为10的倍数,剩余两张之和除以10的余数即为牛的等级:

kotlin 复制代码
fun checkNiuNiu(hand: List<String>): String {
    val points = hand.map { cardToPoint(it) }

    if (isFiveLittleCow(points)) {
        return "五小牛"
    }
    if (isFiveFlowerCow(points)) {
        return "五花牛"
    }
    if (isNiuNiu(points)) {
        return "牛牛"
    }

    // 检查普通牛
    for (i in hand.indices) {
        for (j in i + 1 until hand.size) {
            for (k in j + 1 until hand.size) {
                val sum3 = points[i] + points[j] + points[k]
                if (sum3 % 10 == 0) {
                    val remainingPoints = points.filterIndexed { idx, _ -> idx != i && idx != j && idx != k }
                    val sum2 = remainingPoints.sum()
                    val niuValue = sum2 % 10
                    return if (niuValue == 0) "牛十" else "牛$niuValue"
                }
            }
        }
    }
    return "无牛"
}

4. 胜负判定

将各种牛等级转换为数值,数值高的获胜:

kotlin 复制代码
fun getNiuValue(niuStr: String): Int {
    return when (niuStr) {
        "五小牛" -> 13
        "五花牛" -> 12
        "牛牛" -> 11
        "牛十", "牛10" -> 10
        "牛九", "牛9" -> 9
        // ... 其他牛等级
        else -> 0 // 无牛
    }
}

fun judgeWinner(bankerNiu: String, playersNiu: List<String>): List<String> {
    val results = mutableListOf<String>()
    val bankerValue = getNiuValue(bankerNiu)
    playersNiu.forEach { playerNiu ->
        val playerValue = getNiuValue(playerNiu)
        when {
            playerValue > bankerValue -> results.add("赢")
            playerValue < bankerValue -> results.add("输")
            else -> results.add("平局 庄家赢")
        }
    }
    return results
}

5. 游戏主流程

kotlin 复制代码
fun main() {
    // 生成并洗牌
    val deck = generateDeck().shuffled(Random)
    
    // 发牌:庄家5张,3个闲家各5张
    val bankerHand = deck.take(5)
    val player1Hand = deck.subList(5, 10)
    val player2Hand = deck.subList(10, 15)
    val player3Hand = deck.subList(15, 20)
    
    // 显示手牌
    println("庄家的手牌: ${bankerHand.joinToString(" ")}")
    println("闲家一手牌: ${player1Hand.joinToString(" ")}")
    // ... 显示其他玩家手牌
    
    // 计算牛等级
    val bankerNiu = checkNiuNiu(bankerHand)
    val player1Niu = checkNiuNiu(player1Hand)
    // ... 计算其他玩家牛等级
    
    // 判定胜负
    val results = judgeWinner(bankerNiu, listOf(player1Niu, player2Niu, player3Niu))
}

二、完整代码实现

以下是基于Kotlin实现的斗牛游戏完整代码,包含了从牌组生成、发牌到判定胜负的全流程:

kotlin 复制代码
package com.zzj.www

import kotlin.random.Random

fun main() {
    // 生成并洗牌
    val deck = generateDeck().shuffled(Random)

    // 发牌:庄家5张,3个闲家各5张
    val bankerHand = deck.take(5)
    val player1Hand = deck.subList(5, 10)
    val player2Hand = deck.subList(10, 15)
    val player3Hand = deck.subList(15, 20)

    // 显示各家手牌
    println("庄家的手牌: ${bankerHand.joinToString(" ")}")
    println("闲家一手牌: ${player1Hand.joinToString(" ")}")
    println("闲家二手牌: ${player2Hand.joinToString(" ")}")
    println("闲家三手牌: ${player3Hand.joinToString(" ")}\n")
    
    // 计算各家的牛型
    val bankerNiu = checkNiuNiu(bankerHand)
    val player1Niu = checkNiuNiu(player1Hand)
    val player2Niu = checkNiuNiu(player2Hand)
    val player3Niu = checkNiuNiu(player3Hand)

    // 显示牛型结果
    println("庄家: $bankerNiu")
    println("闲家1: $player1Niu")
    println("闲家2: $player2Niu")
    println("闲家3: $player3Niu")

    // 判定胜负
    val results = judgeWinner(bankerNiu, listOf(player1Niu, player2Niu, player3Niu))
    println("\n判定结果:")
    results.forEachIndexed { idx, result ->
        println("闲家${idx + 1} $result")
    }
}

/**
 * 生成一副完整的扑克牌
 * 包含4种花色(♠, ♥, ♦, ♣)和13种点数(A, 2-10, J, Q, K)
 */
fun generateDeck(): List<String> {
    val suits = listOf("♠", "♥", "♦", "♣")
    val ranks = listOf("A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K")
    return suits.flatMap { suit -> ranks.map { rank -> "$suit$rank" } }
}

/**
 * 将牌面转换为对应的点数
 * A=1,J/Q/K=10,其他按数字本身计算
 */
fun cardToPoint(card: String): Int {
    return when (val rank = card.substring(1)) {
        "A" -> 1
        "J", "Q", "K" -> 10
        else -> rank.toInt()
    }
}

/**
 * 判断是否为五小牛
 * 五张牌的点数都小于5,且总和不超过10
 */
fun isFiveLittleCow(points: List<Int>): Boolean {
    return points.all { it < 5 } && points.sum() <= 10
}

/**
 * 判断是否为五花牛
 * 五张牌都是10点牌(10、J、Q、K)
 */
fun isFiveFlowerCow(points: List<Int>): Boolean {
    return points.all { it == 10 }
}

/**
 * 判断是否为牛牛
 * 任意三张牌之和为10的倍数,剩余两张之和也为10的倍数
 */
fun isNiuNiu(points: List<Int>): Boolean {
    for (i in points.indices) {
        for (j in i + 1 until points.size) {
            for (k in j + 1 until points.size) {
                val sum3 = points[i] + points[j] + points[k]
                if (sum3 % 10 == 0) {
                    val remainingPoints = points.filterIndexed { idx, _ -> idx != i && idx != j && idx != k }
                    val sum2 = remainingPoints.sum()
                    if (sum2 % 10 == 0) {
                        return true
                    }
                }
            }
        }
    }
    return false
}

/**
 * 检查手牌的牛型
 * 按优先级从高到低判断:五小牛 > 五花牛 > 牛牛 > 普通牛 > 无牛
 */
fun checkNiuNiu(hand: List<String>): String {
    val points = hand.map { cardToPoint(it) }

    if (isFiveLittleCow(points)) {
        return "五小牛"
    }
    if (isFiveFlowerCow(points)) {
        return "五花牛"
    }
    if (isNiuNiu(points)) {
        return "牛牛"
    }

    // 检查普通牛
    for (i in hand.indices) {
        for (j in i + 1 until hand.size) {
            for (k in j + 1 until hand.size) {
                val sum3 = points[i] + points[j] + points[k]
                if (sum3 % 10 == 0) {
                    val remainingPoints = points.filterIndexed { idx, _ -> idx != i && idx != j && idx != k }
                    val sum2 = remainingPoints.sum()
                    val niuValue = sum2 % 10
                    return if (niuValue == 0) {
                        "牛十"
                    } else {
                        "牛$niuValue"
                    }
                }
            }
        }
    }
    return "无牛"
}

/*** 将牛型转换为对应分值,用于比较大小 */
fun getNiuValue(niuStr: String): Int {
    return when (niuStr) {
        "五小牛" -> 13
        "五花牛" -> 12
        "牛牛" -> 11
        "牛十", "牛10" -> 10
        "牛九", "牛9" -> 9
        "牛八", "牛8" -> 8
        "牛七", "牛7" -> 7
        "牛六", "牛6" -> 6
        "牛五", "牛5" -> 5
        "牛四", "牛4" -> 4
        "牛三", "牛3" -> 3
        "牛二", "牛2" -> 2
        "牛一", "牛1" -> 1
        else -> 0 // 无牛
    }
}

/*** 判定庄家与闲家的胜负 */
fun judgeWinner(bankerNiu: String, playersNiu: List<String>): List<String> {
    val results = mutableListOf<String>()
    val bankerValue = getNiuValue(bankerNiu)
    playersNiu.forEach { playerNiu ->
        val playerValue = getNiuValue(playerNiu)
        when {
            playerValue > bankerValue -> results.add("赢")
            playerValue < bankerValue -> results.add("输")
            else -> results.add("平局 庄家赢")
        }
    }
    return results
}

三、代码核心功能解析

该实现主要包含以下几个核心模块:

  1. 牌组生成 :通过generateDeck()函数创建包含52张牌的完整牌组,使用花色与点数组合的方式生成牌面字符串。

  2. 点数转换cardToPoint()函数将牌面转换为游戏中使用的点数,遵循斗牛游戏的点数计算规则。

  3. 牛型判定 :这是整个游戏最核心的部分,checkNiuNiu()函数按照五小牛、五花牛、牛牛、普通牛的优先级依次判断手牌类型。

  4. 胜负判定 :通过getNiuValue()将牛型转换为可比较的数值,再由judgeWinner()函数根据数值大小判定胜负。

  5. 游戏流程main()函数实现了完整的游戏流程,包括洗牌、发牌、计算牛型和判定胜负,并将结果输出到控制台。

四、运行示例

运行程序后,会得到类似以下的输出结果:

复制代码
庄家的手牌: ♠3 ♥5 ♦J ♣Q ♠10
闲家一手牌: ♥A ♦2 ♣3 ♠4 ♥5
闲家二手牌: ♦6 ♣7 ♠8 ♥9 ♦10
闲家三手牌: ♣J ♠Q ♥K ♦A ♣2

庄家: 五花牛
闲家1: 五小牛
闲家2: 牛十
闲家3: 牛3

判定结果:
闲家1 赢
闲家2 输
闲家3 输

五、总结

通过上述代码,我们实现了一个完整的斗牛游戏逻辑。这个实现包含了从牌组生成、发牌、牛等级计算到胜负判定的全流程。

该代码采用了Kotlin的函数式编程特性,如flatMapfilterIndexed等高阶函数,使代码更加简洁易读。同时,通过将不同功能封装到独立函数中,提高了代码的可维护性和可扩展性。

有空在搞一个图形化界面,嗨起来。

相关推荐
Fate_I_C2 小时前
Kotlin 中 `@JvmField` 注解的使用
android·开发语言·kotlin
大大祥2 小时前
一个kotlin实现的视频播放器
android·开发语言·kotlin·音视频
消失的旧时光-19434 小时前
从 Kotlin 到 Flutter:架构迁移指南
开发语言·flutter·kotlin
来来走走20 小时前
Android开发(kotlin) 开发一个简单天气应用
android·kotlin
zhangphil1 天前
Kotlin新式管道Channel融合flow流,协程实现Android废弃的AsyncTaskLoader(B)
kotlin
Yang-Never1 天前
Android 内存泄漏 -> ViewModel持有Activity/Fragment导致的内存泄漏
android·java·开发语言·kotlin·android studio
Yang-Never1 天前
Android 内存泄漏 -> LiveData如何解决ViewMode和Activity/Fragment之间的内存泄漏
android·java·开发语言·kotlin·android studio
HeDongDong-1 天前
Kotlin 协程(Coroutines)详解
android·开发语言·kotlin
Kapaseker1 天前
凌晨两点磨锋芒 调试采坑莫慌张
android·kotlin