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等高阶函数,使代码更加简洁易读。同时,通过将不同功能封装到独立函数中,提高了代码的可维护性和可扩展性。

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

相关推荐
我有与与症8 小时前
从页面加载过程看 Kuikly 的多线程架构
kotlin
JMchen12312 小时前
Android UDP编程:实现高效实时通信的全面指南
android·经验分享·网络协议·udp·kotlin
JMchen12313 小时前
Android网络安全实战:从HTTPS到双向认证
android·经验分享·网络协议·安全·web安全·https·kotlin
JMchen1231 天前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
儿歌八万首1 天前
硬核春节:用 Compose 打造“赛博鞭炮”
android·kotlin·compose·春节
消失的旧时光-19431 天前
从 Kotlin 到 Dart:为什么 sealed 是处理「多种返回结果」的最佳方式?
android·开发语言·flutter·架构·kotlin·sealed
有位神秘人1 天前
kotlin与Java中的单例模式总结
java·单例模式·kotlin
Jinkxs1 天前
Gradle - 与Groovy/Kotlin DSL对比 构建脚本语言选择指南
android·开发语言·kotlin
&有梦想的咸鱼&1 天前
Kotlin委托机制的底层实现深度解析(74)
android·开发语言·kotlin
golang学习记1 天前
IntelliJ IDEA 2025.3 重磅发布:K2 模式全面接管 Kotlin —— 告别 K1,性能飙升 40%!
java·kotlin·intellij-idea