[练习贴]扑克的洗牌和发牌

因过年,家人聚在一起玩扑克牌,突发奇想,这个洗牌发牌若做成程序是如何完成的?
故在闲暇时间对这个发牌洗牌过程用代码进行实现。

首先,我们得先创建出一副扑克 ,众所周知,扑克是由xxx组成的54张牌,所以我们先从小小的一张牌开始。

首先我们分析一张牌所包含的信息:数值、花色类型(大小王没有花色)
所以我们先创建牌类(Card.dart):

class Card {
    String name;
    String type;

    Card(this.name, this.type);

    @override
    String toString() {
        return 'Card{name: $name, type: $type}';
    }
}

有了牌类了,就可以创建一副扑克(Poker.dart):

class Poker {
    static const List<String> POKER_NAMES = const [
        'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
    static const List<String> CARD_TYPES = const['♠', '♣', '︎♥', '︎♦︎'];
    List<Card> _cards;

    Poker(){
        _cards = new List<Card>();
        _cards.add(new Card("大王", null));
        _cards.add(new Card("小王", null));
        for (String type in CARD_TYPES) {
            for (String name in POKER_NAMES) {
                _cards.add(new Card(name, type));
            }
        }
    }

    get cards => _cards;
}

如同刚买的新扑克一样,按照顺序的排列着。
下一步就是该如何洗牌呢?
首先我们会将扑克分成两份,然后将两份微微弯曲后,一点点的随机数量的释放,使其再合成一份,然后重复3~5次,就将一副牌重新打乱。
那么通过代码该如何模拟该过程呢

首先是将牌先分成两份,因为手工分配,不可能完美的将牌分成两份数量一样的,所以我这通过随机数来模拟获取中间点

//模拟粗略的将整副牌分成两份
Random _random = new Random.secure();
int halfNumber = tempCards.length ~/ 2 + _random.nextInt(10);

//创建一个临时集合,用于存放洗完后的牌
List<Card> tempCards = new List<Card>();
tempCards.addAll(_cards);

List<Card> tempCards1 = tempCards.sublist(0, halfNumber);
List<Card> tempCards2 = tempCards.sublist(halfNumber);

tempCards.clear();

牌分好了,就开始将牌微微弯曲,然后左右手随机的开始释放牌,按照程序来说就是从这个两堆牌的末尾随机抽一部分牌,然后将其叠加在一起,为实现末尾随机抽牌过程,我们可以创建个方法实现:

/**
* 从尾部抽取随机数量的牌
* @Param cords 欲抽取的牌组
* @Param random 随机数对象
* @Param minNumber 最小牌数
*/
static List<Card> getLastRandomCards(List<Card> cards,
    {Random random, int minNumber = 4}) {
    int randomNumber = 0;
    if (cards.length <= minNumber) {
        randomNumber = cards.length;
    } else {
        random = random ?? new Random.secure();
        randomNumber = random.nextInt(cards.length - minNumber) + minNumber;
    }

    var startPosition = cards.length - randomNumber;
    List<Card> randomCards = cards.sublist(startPosition);

    cards.removeRange(startPosition, cards.length);

    return randomCards;
}

然后通过循环完成整个流程

List<Card> randomCards;
while (true) {
    /** 如果第二堆牌没有了,就直接结束循环 */
    if (tempCards2.length == 0) {
        tempCards.addAll(tempCards1);
        break;
    }

    randomCards = getLastRandomCards(tempCards1, random: _random);
    tempCards.addAll(randomCards);

    /** 如果第一堆牌没有了,就直接结束循环 */
    if (tempCards1.length == 0) {
        tempCards.addAll(tempCards2);
        break;
    }

    randomCards = getLastRandomCards(tempCards2, random: _random);
    tempCards.addAll(randomCards);
}

然后,这个流程只是完成了一遍的清洗,为了打乱,会进行多遍上面的步骤,所以完成洗牌过程如下:

/**
* 洗牌
* @Param minCount 最小次数
*/
void shuffle({minCount = 5}) {
    /** 随机洗牌次数 */
    var shuffleCount = _random.nextInt(3) + minCount;
    print('随机洗牌次数:$shuffleCount');

    List<Card> tempCards = new List<Card>();
    tempCards.addAll(_cards);

    /**
     * 洗牌方法
     */
    for (int i = 0; i < shuffleCount; i++) {
        /** 先将牌大致的分成两堆 */
        int halfNumber = _random.nextInt(10) + tempCards.length ~/ 2;
        List<Card> tempCards1 = tempCards.sublist(0, halfNumber);
        List<Card> tempCards2 = tempCards.sublist(halfNumber);

        tempCards.clear();

        List<Card> randomCards;
        while (true) {
            /** 如果第二堆牌没有了,就直接结束循环 */
            if (tempCards2.length == 0) {
                tempCards.addAll(tempCards1);
                break;
            }

            randomCards = getLastRandomCards(tempCards1, random: _random);
            tempCards.addAll(randomCards);

            /** 如果第一堆牌没有了,就直接结束循环 */
            if (tempCards1.length == 0) {
                tempCards.addAll(tempCards2);
                break;
            }

            randomCards = getLastRandomCards(tempCards2, random: _random);
            tempCards.addAll(randomCards);
        }
    }
    _cards.clear();
    _cards.addAll(tempCards);
}

既然牌洗好了,下面该开始发牌了,因不同的玩法需不同的人数,所以我们通过参数来指定发几份牌

/**
* 发牌
* @Param count 发牌份数
*/
List<List<Card>> licensing({int count = 4}) {
    List<List<Card>> cards = new List<List<Card>>();
    if (count < 1) {
        throw new Exception("发牌份数不得小于0");
    } else if (count > _cards.length) {
        throw new Exception("发牌份数不得大于总牌数");
    }

    for (int i = 0; i < _cards.length; i++) {
        int position = i % count;

        if (cards.length <= position) {
            cards.add(new List<Card>());
        }

        cards[position].add(_cards[i]);
    }

    return cards;
}

来看看结果:

import 'Poker.dart';

main(List<String> args) {
  var poker = new Poker();
  poker.cards.forEach(print);

  print("\n开始洗牌...");
  poker.shuffle();
  poker.cards.forEach(print);


  print("\n开始发牌...");
  var licensing = poker.licensing(count: 4);
  licensing.forEach(print);
}
Card{name: 大王, type: null}
Card{name: 小王, type: null}
Card{name: A, type: ♠}
Card{name: 2, type: ♠}
Card{name: 3, type: ♠}
Card{name: 4, type: ♠}
Card{name: 5, type: ♠}
Card{name: 6, type: ♠}
Card{name: 7, type: ♠}
Card{name: 8, type: ♠}
Card{name: 9, type: ♠}
Card{name: 10, type: ♠}
Card{name: J, type: ♠}
Card{name: Q, type: ♠}
Card{name: K, type: ♠}
Card{name: A, type: ♣}
Card{name: 2, type: ♣}
Card{name: 3, type: ♣}
Card{name: 4, type: ♣}
Card{name: 5, type: ♣}
Card{name: 6, type: ♣}
Card{name: 7, type: ♣}
Card{name: 8, type: ♣}
Card{name: 9, type: ♣}
Card{name: 10, type: ♣}
Card{name: J, type: ♣}
Card{name: Q, type: ♣}
Card{name: K, type: ♣}
Card{name: A, type: ︎♥}
Card{name: 2, type: ︎♥}
Card{name: 3, type: ︎♥}
Card{name: 4, type: ︎♥}
Card{name: 5, type: ︎♥}
Card{name: 6, type: ︎♥}
Card{name: 7, type: ︎♥}
Card{name: 8, type: ︎♥}
Card{name: 9, type: ︎♥}
Card{name: 10, type: ︎♥}
Card{name: J, type: ︎♥}
Card{name: Q, type: ︎♥}
Card{name: K, type: ︎♥}
Card{name: A, type: ︎♦︎}
Card{name: 2, type: ︎♦︎}
Card{name: 3, type: ︎♦︎}
Card{name: 4, type: ︎♦︎}
Card{name: 5, type: ︎♦︎}
Card{name: 6, type: ︎♦︎}
Card{name: 7, type: ︎♦︎}
Card{name: 8, type: ︎♦︎}
Card{name: 9, type: ︎♦︎}
Card{name: 10, type: ︎♦︎}
Card{name: J, type: ︎♦︎}
Card{name: Q, type: ︎♦︎}
Card{name: K, type: ︎♦︎}

开始洗牌...
随机洗牌次数:6
Card{name: Q, type: ︎♥}
Card{name: 5, type: ︎♦︎}
Card{name: 7, type: ♠}
Card{name: A, type: ︎♦︎}
Card{name: 2, type: ︎♦︎}
Card{name: 3, type: ︎♦︎}
Card{name: A, type: ♣}
Card{name: 2, type: ♠}
Card{name: 7, type: ︎♥}
Card{name: 8, type: ︎♥}
Card{name: 4, type: ♠}
Card{name: 5, type: ♠}
Card{name: 9, type: ︎♦︎}
Card{name: 10, type: ︎♦︎}
Card{name: 7, type: ︎♦︎}
Card{name: 8, type: ︎♦︎}
Card{name: 9, type: ︎♥}
Card{name: 10, type: ︎♥}
Card{name: J, type: ︎♥}
Card{name: 2, type: ︎♥}
Card{name: 3, type: ︎♥}
Card{name: 4, type: ︎♥}
Card{name: 小王, type: null}
Card{name: A, type: ♠}
Card{name: 8, type: ♠}
Card{name: J, type: ︎♦︎}
Card{name: Q, type: ︎♦︎}
Card{name: K, type: ︎♦︎}
Card{name: 大王, type: null}
Card{name: 3, type: ♠}
Card{name: 6, type: ♣}
Card{name: 7, type: ♣}
Card{name: 8, type: ♣}
Card{name: 9, type: ♣}
Card{name: 10, type: ♣}
Card{name: J, type: ♣}
Card{name: 4, type: ︎♦︎}
Card{name: 4, type: ♣}
Card{name: 2, type: ♣}
Card{name: 3, type: ♣}
Card{name: 6, type: ︎♦︎}
Card{name: 6, type: ︎♥}
Card{name: Q, type: ♣}
Card{name: K, type: ♣}
Card{name: A, type: ︎♥}
Card{name: J, type: ♠}
Card{name: Q, type: ♠}
Card{name: K, type: ♠}
Card{name: 5, type: ♣}
Card{name: K, type: ︎♥}
Card{name: 6, type: ♠}
Card{name: 5, type: ︎♥}
Card{name: 9, type: ♠}
Card{name: 10, type: ♠}

开始发牌...
[Card{name: Q, type: ︎♥}, Card{name: 2, type: ︎♦︎}, Card{name: 7, type: ︎♥}, Card{name: 9, type: ︎♦︎}, Card{name: 9, type: ︎♥}, Card{name: 3, type: ︎♥}, Card{name: 8, type: ♠}, Card{name: 大王, type: null}, Card{name: 8, type: ♣}, Card{name: 4, type: ︎♦︎}, Card{name: 6, type: ︎♦︎}, Card{name: A, type: ︎♥}, Card{name: 5, type: ♣}, Card{name: 9, type: ♠}]
[Card{name: 5, type: ︎♦︎}, Card{name: 3, type: ︎♦︎}, Card{name: 8, type: ︎♥}, Card{name: 10, type: ︎♦︎}, Card{name: 10, type: ︎♥}, Card{name: 4, type: ︎♥}, Card{name: J, type: ︎♦︎}, Card{name: 3, type: ♠}, Card{name: 9, type: ♣}, Card{name: 4, type: ♣}, Card{name: 6, type: ︎♥}, Card{name: J, type: ♠}, Card{name: K, type: ︎♥}, Card{name: 10, type: ♠}]
[Card{name: 7, type: ♠}, Card{name: A, type: ♣}, Card{name: 4, type: ♠}, Card{name: 7, type: ︎♦︎}, Card{name: J, type: ︎♥}, Card{name: 小王, type: null}, Card{name: Q, type: ︎♦︎}, Card{name: 6, type: ♣}, Card{name: 10, type: ♣}, Card{name: 2, type: ♣}, Card{name: Q, type: ♣}, Card{name: Q, type: ♠}, Card{name: 6, type: ♠}]
[Card{name: A, type: ︎♦︎}, Card{name: 2, type: ♠}, Card{name: 5, type: ♠}, Card{name: 8, type: ︎♦︎}, Card{name: 2, type: ︎♥}, Card{name: A, type: ♠}, Card{name: K, type: ︎♦︎}, Card{name: 7, type: ♣}, Card{name: J, type: ♣}, Card{name: 3, type: ♣}, Card{name: K, type: ♣}, Card{name: K, type: ♠}, Card{name: 5, type: ︎♥}]

本文来自 艾幻翔 投稿,如若转载,请注明出处:http://www.cndartlang.com/466.html

发表评论

登录后才能评论