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

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

相关推荐
alexhilton3 小时前
Compose中的ContentScale:终极可视化指南
android·kotlin·android jetpack
jzlhll1234 小时前
kotlin Flow first() last()总结
开发语言·前端·kotlin
符哥20089 小时前
充电桩 WiFi 局域网配网(Android/Kotlin)流程、指令及实例说明文档
android·开发语言·kotlin
大傻^12 小时前
SpringAI2.0 Null Safety 实战:JSpecify 注解体系与 Kotlin 互操作
android·开发语言·人工智能·kotlin·springai
jzlhll12317 小时前
Kotlin Mutex vs Java ReentrantLock vs synchronized
java·开发语言·kotlin
Kapaseker17 小时前
一杯 Kotlin 美式品味 object 声明
android·kotlin
俩个逗号。。18 小时前
Kotlin 扩展函数详解
开发语言·kotlin
su1ka1112 天前
Kotlin(3)基本语法
kotlin
su1ka1112 天前
Kotlin(4)面向对象
kotlin
鹧鸪晏2 天前
搞懂 kotlin 泛型 out 和 in 关键字
android·kotlin