用unity先来个一副牌的单机斗地主

简介: 用unity先来个一副牌的单机斗地主

斗地主规则

以下是一副牌的斗地主规则:

  1. 牌数:一副牌使用除大小王以外的52张牌进行游戏。
  2. 玩家人数:游戏需要3名玩家,其中一人扮演地主,其余两人为农民。
  3. 发牌:首先将一副牌洗混,并由一名玩家开始发牌。每位玩家手中均分17张牌,剩下的3张作为底牌。
  4. 叫地主:发牌结束后,进行叫地主环节。从发完牌的玩家开始,按照顺时针方向,每位玩家可以选择叫地主或不叫地主。如果有玩家叫地主,则继续轮到下一位玩家进行决策。最后叫地主的玩家成为地主,其余两名玩家合称农民。
  5. 加倍:地主在确认身份后,可以选择加倍。加倍使得游戏结果评分更高,但也带来了风险。农民可以选择不加倍或者跟倍数。加倍后的倍数将应用于游戏结果的计分。
  6. 出牌:游戏从地主开始,按顺时针方向进行。玩家可以出一手比上家大的牌、相同牌型但更大的牌,或者不出牌。牌型和出牌规则如下:
  • 单牌:一张单独的牌。
  • 对子:两张点数相同的牌。
  • 三张牌:三张点数相同的牌。
  • 三带一:三张点数相同的牌加一张单牌。
  • 三带二:三张点数相同的牌加一对牌。
  • 顺子:至少五张连续递增的牌。
  • 连对:至少三对连续递增的对子。
  • 飞机:至少两个连续递增的三张牌。
  • 炸弹:四张点数相同的牌。
  • 火箭:一对大小王(即双鬼牌)。
  1. 底牌:地主在游戏开始后可以查看底牌,并将其添加到自己的牌中。农民无法查看底牌。
  2. 结束条件:游戏继续直到有一名玩家先出完手中的牌,或其他两名玩家同时不出牌。如果地主最先出完牌,他赢得游戏。否则,农民方获胜。

洗牌算法

以下是一个使用C#编写的简单洗牌算法示例:

using System;
using System.Collections.Generic;
public class Card
{
    public string Suit { get; set; }
    public string Rank { get; set; }
}
public static class DeckOfCards
{
    public static List<Card> CreateDeck()
    {
        List<Card> deck = new List<Card>();
        string[] suits = { "Spades", "Hearts", "Diamonds", "Clubs" };
        string[] ranks = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" };
        foreach (string suit in suits)
        {
            foreach (string rank in ranks)
            {
                deck.Add(new Card { Suit = suit, Rank = rank });
            }
        }
        deck.Add(new Card { Suit = "Joker", Rank = "Small" });
        deck.Add(new Card { Suit = "Joker", Rank = "Big" });
        return deck;
    }
    public static void ShuffleDeck(List<Card> deck)
    {
        Random rng = new Random();
        int n = deck.Count;
        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);
            Card temp = deck[k];
            deck[k] = deck[n];
            deck[n] = temp;
        }
    }
}
public class Program
{
    public static void Main()
    {
        List<Card> deck = DeckOfCards.CreateDeck();
        DeckOfCards.ShuffleDeck(deck);
        foreach (Card card in deck)
        {
            Console.WriteLine($"{card.Rank} of {card.Suit}");
        }
    }
}

在上述示例中,首先定义了一个 Card 类表示一张纸牌,包含 Suit(花色)和 Rank(点数)属性。然后在 DeckOfCards 类中,使用两个数组分别表示花色和点数,通过嵌套循环生成一副牌的所有组合,并将其添加到 deck 列表中。

接着,使用 Fisher-Yates 洗牌算法对牌组进行随机排序的 ShuffleDeck 方法。

最后,在 Main 方法中,创建一副牌,然后进行洗牌并打印出洗好的牌的顺序。

请注意,这只是一个基本的洗牌示例,实际应用中还可能考虑到更复杂的需求,例如需要与玩家配合交互、维护游戏状态等。但以上示例应该可以满足最基本的洗牌需求。

发牌算法

以下是一个简单的C#代码示例,用于实现斗地主游戏的发牌算法:

using System;
using System.Collections.Generic;
public class Card
{
    public string Suit { get; set; }
    public string Rank { get; set; }
}
public static class DeckOfCards
{
    public static List<Card> CreateDeck()
    {
        List<Card> deck = new List<Card>();
        string[] suits = { "Spades", "Hearts", "Diamonds", "Clubs" };
        string[] ranks = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" };
        foreach (string suit in suits)
        {
            foreach (string rank in ranks)
            {
                deck.Add(new Card { Suit = suit, Rank = rank });
            }
        }
        deck.Add(new Card { Suit = "Joker", Rank = "Small" });
        deck.Add(new Card { Suit = "Joker", Rank = "Big" });
        return deck;
    }
    public static void ShuffleDeck(List<Card> deck)
    {
        Random rng = new Random();
        int n = deck.Count;
        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);
            Card temp = deck[k];
            deck[k] = deck[n];
            deck[n] = temp;
        }
    }
    public static List<List<Card>> DealCards(List<Card> deck, int numberOfPlayers)
    {
        List<List<Card>> players = new List<List<Card>>();
        for (int i = 0; i < numberOfPlayers; i++)
        {
            players.Add(new List<Card>());
        }
        int currentPlayer = 0;
        foreach (Card card in deck)
        {
            players[currentPlayer].Add(card);
            currentPlayer = (currentPlayer + 1) % numberOfPlayers;
        }
        
        return players;
    }
}
public class Program
{
    public static void Main()
    {
        List<Card> deck = DeckOfCards.CreateDeck();
        DeckOfCards.ShuffleDeck(deck);
        List<List<Card>> players = DeckOfCards.DealCards(deck, 3);
        Console.WriteLine("Player A1:");
        foreach (Card card in players[0])
        {
            Console.WriteLine($"{card.Rank} of {card.Suit}");
        }
        Console.WriteLine("Player A2:");
        foreach (Card card in players[1])
        {
            Console.WriteLine($"{card.Rank} of {card.Suit}");
        }
        Console.WriteLine("Player SanGe:");
        foreach (Card card in players[2])
        {
            Console.WriteLine($"{card.Rank} of {card.Suit}");
        }
    }
}

在这个示例中,使用了之前在洗牌示例中提供的 CardDeckOfCards 类。在 DealCards 方法中,我们将游戏牌组按顺序分发给每个玩家。通过循环,依次将牌发给每个玩家直到没有剩余牌。

Main 方法中,首先创建一副牌并进行洗牌。然后使用 DealCards 方法将牌发给三个玩家,并依次打印每个玩家手中的牌。

出牌算法

下面是更新后的斗地主出牌算法,根据实际的斗地主比牌规则来判断牌的大小:

using System;
using System.Collections.Generic;
public class Card
{
    public string Suit { get; set; }
    public string Rank { get; set; }
}
public static class GameLogic
{
    public static bool CanPlay(List<Card> playedCards, List<Card> hand)
    {
        if (playedCards.Count == 0)
            return true; // 没有牌被打出去,可以出任何牌
        // 判断牌型是否一致且手牌中的牌比已出的牌大
        if (hand.Count >= playedCards.Count && IsSameType(playedCards, hand) && IsBigger(hand, playedCards))
            return true;
        return false; // 默认不能打出牌
    }
    public static bool IsValidPlay(List<Card> playedCards)
    {
        if (IsSingle(playedCards) || IsPair(playedCards) || IsTriplet(playedCards) ||
            IsStraight(playedCards) || IsBomb(playedCards))
        {
            return true;
        }
        return false; // 默认为不合法
    }
    // 判断是否为单张
    public static bool IsSingle(List<Card> cards)
    {
        return cards.Count == 1;
    }
    // 判断是否为对子
    public static bool IsPair(List<Card> cards)
    {
        return cards.Count == 2 && cards[0].Rank == cards[1].Rank;
    }
    // 判断是否为三张相同的牌
    public static bool IsTriplet(List<Card> cards)
    {
        return cards.Count == 3 && cards[0].Rank == cards[1].Rank && cards[1].Rank == cards[2].Rank;
    }
    // 判断是否为顺子
    public static bool IsStraight(List<Card> cards)
    {
        if (cards.Count < 5 || cards.Count > 12)
            return false;
        cards.Sort((a, b) => RankToInt(a.Rank).CompareTo(RankToInt(b.Rank)));
        for (int i = 0; i < cards.Count - 1; i++)
        {
            if (RankToInt(cards[i + 1].Rank) - RankToInt(cards[i].Rank) != 1)
                return false;
        }
        return true;
    }
    // 判断是否为炸弹(四张相同的牌)
    public static bool IsBomb(List<Card> cards)
    {
        return cards.Count == 4 && cards[0].Rank == cards[1].Rank &&
               cards[1].Rank == cards[2].Rank && cards[2].Rank == cards[3].Rank;
    }
    // 判断牌型是否一致
    public static bool IsSameType(List<Card> playedCards, List<Card> hand)
    {
        if (IsSingle(playedCards))
        {
            return IsSingle(hand);
        }
        else if (IsPair(playedCards))
        {
            return IsPair(hand);
        }
        else if (IsTriplet(playedCards))
        {
            return IsTriplet(hand);
        }
        else if (IsStraight(playedCards))
        {
            return IsStraight(hand);
        }
        else if (IsBomb(playedCards))
        {
            return IsBomb(hand);
        }
        return false;
    }
    // 判断手牌中的牌是否比已出的牌大
    public static bool IsBigger(List<Card> hand, List<Card> playedCards)
    {
        if (IsSingle(playedCards) && IsSingle(hand))
        {
            return RankToInt(hand[0].Rank) > RankToInt(playedCards[0].Rank);
        }
        else if (IsPair(playedCards) && IsPair(hand))
        {
            return RankToInt(hand[0].Rank) > RankToInt(playedCards[0].Rank);
        }
        else if (IsTriplet(playedCards) && IsTriplet(hand))
        {
            return RankToInt(hand[0].Rank) > RankToInt(playedCards[0].Rank);
        }
        else if (IsStraight(playedCards) && IsStraight(hand) && hand.Count == playedCards.Count)
        {
            return RankToInt(hand[0].Rank) > RankToInt(playedCards[0].Rank);
        }
        else if (IsBomb(playedCards) && IsBomb(hand))
        {
            return RankToInt(hand[0].Rank) > RankToInt(playedCards[0].Rank);
        }
        return false;
    }
    // 将牌面大小转换为整数用于比较
    public static int RankToInt(string rank)
    {
        switch (rank)
        {
            case "3":
                return 3;
            case "4":
                return 4;
            case "5":
                return 5;
            case "6":
                return 6;
            case "7":
                return 7;
            case "8":
                return 8;
            case "9":
                return 9;
            case "10":
                return 10;
            case "J":
                return 11;
            case "Q":
                return 12;
            case "K":
                return 13;
            case "A":
                return 14;
            case "2":
                return 15;
            case "小王":
                return 16;
            case "大王":
                return 17;
            default:
                return 0;
        }
    }
    public static void Main()
    {
        List<Card> playedCards = new List<Card>(); // 已经打出的牌
        List<Card> hand = new List<Card>(); // 手中的牌
        // 添加示例牌
        hand.Add(new Card() { Suit = "Spades", Rank = "3" });
        hand.Add(new Card() { Suit = "Hearts", Rank = "3" });
        hand.Add(new Card() { Suit = "Clubs", Rank = "5" });
        hand.Add(new Card() { Suit = "Diamonds", Rank = "5" });
        hand.Add(new Card() { Suit = "Spades", Rank = "6" });
        // 先出牌的情况
        if (CanPlay(playedCards, hand))
        {
            // 在此处根据自己的策略选择要打出的牌
            List<Card> cardsToPlay = new List<Card>();
            if (IsValidPlay(cardsToPlay))
            {
                // 在此处将打出的牌从手中移除,并添加到已打出的牌中
                foreach (Card card in cardsToPlay)
                {
                    hand.Remove(card);
                    playedCards.Add(card);
                }
                // 在此处执行相应的动作,比如更新游戏状态等
                Console.WriteLine("Player plays cards: ");
                foreach (Card card in cardsToPlay)
                {
                    Console.WriteLine($"{card.Rank} of {card.Suit}");
                }
            }
            else
            {
                Console.WriteLine("Invalid play.");
            }
        }
        else
        {
            Console.WriteLine("Cannot play any cards.");
        }
        // 跟着出牌的情况
        // 假设已经有其他玩家出了一些牌,并且有一张最新的牌需要跟进
        List<Card> lastPlayedCards = new List<Card>();
        // 在此处根据自己的策略选择要打出的牌
        List<Card> cardsToPlay2 = new List<Card>();
        if (CanPlay(playedCards, cardsToPlay2))
        {
            if (IsValidPlay(cardsToPlay2))
            {
                // 在此处将打出的牌从手中移除,并添加到已打出的牌中
                foreach (Card card in cardsToPlay2)
                {
                    hand.Remove(card);
                    playedCards.Add(card);
                }
                // 在此处执行相应的动作,比如更新游戏状态等
                Console.WriteLine("Player follows the cards played: ");
                foreach (Card card in cardsToPlay2)
                {
                    Console.WriteLine($"{card.Rank} of {card.Suit}");
                }
            }
            else
            {
                Console.WriteLine("Invalid play.");
            }
        }
        else
        {
            Console.WriteLine("Cannot play any cards.");
        }
    }
}

在此示例中,我们添加了判断牌型是否一致以及手牌中的牌是否比已出的牌大的逻辑。同时,我们增加了判断单张、对子、三张、顺子和炸弹等不同牌型的方法。

判断输赢

斗地主判断赢牌的算法可以根据出牌人是农民还是地主进行不同的判断。以下是一个简单的算法示例:

  1. 创建一个保存每张牌数量的数组,初始化为0。
  2. 根据游戏规则进行牌面的计算,将每个玩家手中的牌加入到相应的数组中。
  3. 当农民或地主出牌时,分别计算该玩家出牌后的数组情况。
  4. 比较每个数组中牌的数量来确定胜利者。

具体步骤如下:

对于农民:

  1. 创建一个保存每张牌数量的数组,初始化为0。
  2. 农民出牌后,将出的牌从数组中减去相应数量。
  3. 判断数组中是否还有牌数量为0的情况,如果有,则判定农民胜利。

对于地主:

  1. 创建一个保存每张牌数量的数组,初始化为0。
  2. 地主出牌后,将出的牌从数组中减去相应数量。
  3. 判断数组中是否还有牌数量为0的情况,如果有,则判定地主胜利。

叫分,翻倍,炸弹算法

叫分、翻倍和炸弹是斗地主中的重要规则。以下是关于叫分、翻倍和炸弹的算法示例:

  1. 叫分算法:
  • 游戏开始时,每位玩家可以选择进行叫分,叫分范围一般为1到3。
  • 叫分的算法可以基于玩家手中的牌数、牌型、牌力等因素来进行判断。
  • 例如,可以设计一个简单规则,根据玩家手中的牌总点数、大牌数量、有无炸弹等情况来进行评估并作出叫分的决策。
  1. 翻倍算法:
  • 在游戏中,当玩家抢地主成功后可以选择是否进行翻倍。
  • 翻倍通常是将当前的底分翻倍,一般有1倍、2倍和3倍等选项。
  • 翻倍的算法可以根据玩家手中的牌数、牌型、牌力以及对手的叫分情况等因素来进行判断。
  • 例如,可以设计一个简单规则,如果玩家手中有牌数量较多、有强力牌型或者对手叫分较高,则更倾向于选择翻倍。
  1. 炸弹算法:
  • 炸弹是斗地主中的特殊牌型,由连续四张相同点数的牌组成。
  • 炸弹的强度很高,可以打败除王炸外的其他牌型。
  • 当有玩家出炸弹时,其他玩家必须依次出更大的炸弹或者王炸才能胜出。
  • 炸弹的算法可以基于牌面的点数和数量进行判断。
相关文章
|
6天前
|
移动开发 前端开发 安全
技术心得记录:怎么更快地合成大西瓜?搞懂游戏的源码,闭着眼睛都能成功!
技术心得记录:怎么更快地合成大西瓜?搞懂游戏的源码,闭着眼睛都能成功!
|
20天前
|
Java
Java实现一个打飞机的小游戏【附源码】
Java实现一个打飞机的小游戏【附源码】
22 0
|
2月前
羊了个羊游戏开发实战教程(3):卡牌的放置和消除
羊了个羊游戏开发实战教程(3):卡牌的放置和消除
39 0
|
存储 Java
Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能(下)
文章目录 1 开发环境及游戏展示 1.1 游戏主界面 1.2 移动界面 1.3 奖励界面 1.4 F加速功能界面 1.5 死亡界面 2 需求分析 3 系统设计 3.1 系统总体功能设计 3.2 系统总体流程设计 4 功能设计 4.1 贪吃蛇移动及加速功能设计 4.2 贪吃蛇吃食物加速及死亡判定功能的设计 4.2.1 贪吃蛇吃食物加速功能的设计 4.2.2 贪吃蛇死亡判定功能的设计 4.3 贪吃蛇主动加速功能的设计 4.4 贪吃蛇奖励机制功能的设计 5 项目结构与项目实现 5.1 项目结构及类间关系 5.2 项目完整源码 5.2.1 Images类
|
Python
Python实现超级玛丽游戏系列教程03玛丽跳跃
Python实现超级玛丽游戏系列教程03玛丽跳跃
133 0
Python实现超级玛丽游戏系列教程03玛丽跳跃
|
小程序 搜索推荐 开发者
谈谈宝石方块游戏中的设计
宝石方块是在上一个俄罗斯方块工程的基础上改编的,所以制作起来很快,我只用了不到两天的时间就完成了游戏的功能,后续又花了几天的时间制作游戏的界面,优化游戏的体验。
120 0
|
Java 开发工具
Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能(上)
文章目录 1 开发环境及游戏展示 1.1 游戏主界面 1.2 移动界面 1.3 奖励界面 1.4 F加速功能界面 1.5 死亡界面 2 需求分析 3 系统设计 3.1 系统总体功能设计 3.2 系统总体流程设计 4 功能设计 4.1 贪吃蛇移动及加速功能设计 4.2 贪吃蛇吃食物加速及死亡判定功能的设计 4.2.1 贪吃蛇吃食物加速功能的设计 4.2.2 贪吃蛇死亡判定功能的设计 4.3 贪吃蛇主动加速功能的设计 4.4 贪吃蛇奖励机制功能的设计 5 项目结构与项目实现 5.1 项目结构及类间关系 5.2 项目完整源码 5.2.1 Images类
Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能(上)
|
Java 图形学
Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能(中)
文章目录 1 开发环境及游戏展示 1.1 游戏主界面 1.2 移动界面 1.3 奖励界面 1.4 F加速功能界面 1.5 死亡界面 2 需求分析 3 系统设计 3.1 系统总体功能设计 3.2 系统总体流程设计 4 功能设计 4.1 贪吃蛇移动及加速功能设计 4.2 贪吃蛇吃食物加速及死亡判定功能的设计 4.2.1 贪吃蛇吃食物加速功能的设计 4.2.2 贪吃蛇死亡判定功能的设计 4.3 贪吃蛇主动加速功能的设计 4.4 贪吃蛇奖励机制功能的设计 5 项目结构与项目实现 5.1 项目结构及类间关系 5.2 项目完整源码 5.2.1 Images类
Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能(中)
|
存储 图形学
Unity实战之王者荣耀段位计算
Unity实现王者荣耀段位计算
Unity实战之王者荣耀段位计算
|
搜索推荐 算法 Shell
【漫画】七种最常见的排序算法(动图版)(中)
【漫画】七种最常见的排序算法(动图版)
147 1
【漫画】七种最常见的排序算法(动图版)(中)