洗牌

December 3, 2021

洗牌就是給定一組資料…將之打亂、重新排列。

解法思路

單純地隨機產生 1 ∼ N 的亂數,逐一將資料根據亂數放到指定位置,後續就必須考慮產生的亂數是否重複的問題,運氣不好重複次數多的話,執行速度就慢了,這不是一個好方法。

可以逐一走訪資料,每次產生一個資料長度內的一個亂數,將目前位置與該亂數位置的資料交換,走訪完畢後,也就重新排列了。

程式實作

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define N 52

typedef struct {
    char suit[3];
    char symbol[3];
} Card;

void shuffle(Card*);
void card(int, char*);
void suit(int, char*);
void symbol(int, char*);

int main(void) {
    srand(time(0));
    
    Card cards[N];
    shuffle(cards);
    int i;
    for(i = 0; i < N; i++) {
        printf("%s%s%c", cards[i].suit, cards[i].symbol, 
            (i + 1) % 13 ? ' ' : '\n');
    }

    return 0;
} 


void shuffle(Card* cards) {
    int i;
    for(i = 0; i < N; i++) {
        suit(i + 1, cards[i].suit);
        symbol(i + 1, cards[i].symbol);
    }
    for(i = 0; i < N; i++) {
        int j = rand() % 52;
        Card tmp = cards[i];
        cards[i] = cards[j];
        cards[j] = tmp;
    }
}

void suit(int number, char* suit) {
    switch((number - 1) / 13) { 
         case 0: strcpy(suit, "桃"); break;
         case 1: strcpy(suit, "心"); break;
         case 2: strcpy(suit, "磚"); break;
         case 3: strcpy(suit, "梅");
    }
}

void symbol(int number, char* symbol) {
    int remain = number % 13;
    switch(remain) { 
        case 0:  sprintf(symbol, "%c ", 'K'); break;
        case 1:  sprintf(symbol, "%c ", 'A'); break;
        case 11: sprintf(symbol, "%c ", 'J'); break;
        case 12: sprintf(symbol, "%c ", 'Q'); break;
        default: sprintf(symbol, "%-2d", remain);
    }     
}
import java.util.*;

class Card {
    private String suit;
    private String symbol;
    
    public Card(String suit, String symbol) {
        this.suit = suit;
        this.symbol = symbol;
    }
    
    public String toString() { return suit + symbol; }
}

public class Poker {
    private static List<Card> cards = new ArrayList<>(52);
    static {
        for(int i = 0; i < 52; i++) {
            cards.add(new Card(suit(i + 1), symbol(i + 1)));
        }
    }

    private static String suit(int number) {
        switch((number - 1) / 13) { 
            case 0 : return "桃";
            case 1 : return "心";
            case 2 : return "磚";
            default: return "梅";
        }
    }
    
    private static String symbol(int number) {
        int remain = number % 13;
        switch(remain) { 
            case 0 : return String.format("%c ", 'K');
            case 1 : return String.format("%c ", 'A');
            case 11: return String.format("%c ", 'J');
            case 12: return String.format("%c ", 'Q');
            default: return String.format("%-2d", remain);
        } 
    }

    public static Card[] shuffle() {
        for(int i = 0; i < cards.size(); i++) {
            Collections.swap(cards, i, 
                (int) (Math.random() * cards.size() - 1));
        }
        return cards.toArray(new Card[52]);
    }

    public static void main(String args[]) { 
        Card[] cards = shuffle();
        for(int i = 0; i < cards.length; i++) {
            System.out.printf(
                "%s%c", cards[i], (i + 1) % 13 == 0 ? '\n' : ' '); 
        }
    } 
}
from random import randint
from functools import reduce

class Card:
    def __init__(self, suit, symbol):
        self.suit = suit
        self.symbol = symbol
        
    def __str__(self):
        return self.suit + self.symbol

class Poker:
    cards = [Card(
        {0: "桃", 1: "心", 2: "磚", 3: "梅"}[i // 13],
        {0: "K ", 1: "A ", 11: "J ", 12: "Q "}.get(
            (i + 1) % 13, "%-2d" % ((i + 1) % 13))
    ) for i in range(52)]
    
    @staticmethod
    def shuffle():
        def swap(cards, i, j):
            a, b = sorted([i, j])
            return cards if a == b else (cards[0:a] + [cards[b]] + 
                       cards[a + 1:b] + [cards[a]] + cards[b + 1:])
        return reduce(lambda cards, i: swap(cards, i, randint(0, 51)),
                   range(len(Poker.cards)), Poker.cards)

cards = Poker.shuffle()
for i in range(len(cards)):
    print(cards[i], end = "\n" if (i + 1) % 13 == 0 else " ")
import scala.util.Random

class Card(st: String, sym: String) {
    def suit = st
    def symbol = sym
    override def toString = st + sym
}

object Poker {
    private def suit(number: Int) = (number - 1) / 13 match {
        case 0 => "桃";
        case 1 => "心"
        case 2 => "磚"
        case 3 => "梅"
    }
    
    private def symbol(number: Int) = {
        val remain = number % 13
        remain match { 
            case 0  => "%c ".format('K')
            case 1  => "%c ".format('A')
            case 12 => "%c ".format('Q')
            case 11 => "%c ".format('J')
            case _  => "%-2d".format(remain)
        } 
    }
    
    val cards = (for(i <- 0 until 52) 
                    yield new Card(suit(i), symbol(i))).toList
    
    private val random = new Random
    
    def shuffle = {
        def swap(cards: List[Card], i: Int, j: Int) = {
            val List(a, b) = List(i, j).sortWith(_ < _)
            if(a == b) cards else (cards.take(a) ++ 
                (cards(b) :: cards.slice(a + 1, b)) ++ 
                (cards(a) :: cards.drop(b + 1)))
        }
        (cards /: (0 until cards.size))((cards, i) => 
            swap(cards, i, (random.nextDouble * cards.size - 1).toInt))
    }
}

val cards = Poker.shuffle
for(i <- 0 until cards.size) {
    printf("%s%c", cards(i), if((i + 1) % 13 == 0) '\n' else ' ')
}
# encoding: UTF-8
class Card
    def initialize(suit, symbol)
        @suit = suit
        @symbol = symbol
    end
        
    def to_s
        @suit + @symbol
    end
end

class Poker
    def self.suit(number)
        case (number - 1) / 13
            when 0; "桃"
            when 1; "心"
            when 2; "磚"
            when 3; "梅"
        end
    end
    
    def self.symbol(number)
        remain = number % 13
        case remain
            when 0;  "K "
            when 1;  "A "
            when 11; "J "
            when 12; "Q "
            else; sprintf("%-2d", remain)
        end
    end
    
    def self.shuffle
        swap = ->(cards, i, j) {
            a, b = [i, j].sort
            a == b ? cards : (cards.take(a) + [cards[b]] + 
                cards[a + 1...b] + [cards[a]] + cards.drop(b + 1))
        }
        
        (0...(@@cards.size)).reduce(@@cards) { |cards, i|
            swap.call(cards, i, (rand() * 51).to_i)
        }
    end
    
    @@cards = (0...52).map { |i| Card.new(suit(i + 1), symbol(i + 1))}
end

cards = Poker.shuffle
(0...cards.size).each do |i|
    printf("%s%c", cards[i], (i + 1) % 13 == 0 ? "\n" : " ")
end
function Card(suit, symbol) {
    this.suit = suit;
    this.symbol = symbol;
}

Card.prototype.toString = function() {
    return this.suit + this.symbol;
};

var Poker = function() {
    function suit(number) {
        switch(parseInt((number - 1) / 13)) {
            case 0 : return "桃";
            case 1 : return "心";
            case 2 : return "磚";
            case 3 : return "梅";
        }
    }
    
    function symbol(number) {
        var remain = number % 13;
        switch(remain) {
            case 0 : return 'K ';
            case 1 : return 'A ';
            case 11: return 'J ';
            case 12: return 'Q ';
            default: return remain + 
                new Array(3 - (remain + '').length).join(' ');
        }
    }

    var cards = [];
    for(var i = 0; i < 52; i++) {
        cards.push(new Card(suit(i + 1), symbol(i + 1)));
    }
    
    return {
        shuffle: function() {
            for(var i = 0; i < cards.length; i++) {
                var j = parseInt(Math.random() * cards.length - 1);
                var tmp = cards[i];
                cards[i] = cards[j];
                cards[j] = tmp;
            }
            return cards.slice(0, cards.length);
        }
    };
}();

print(Poker.shuffle());
import Data.List
import System.Random

data Card = Card {suit :: [Char], symbol :: [Char]}

instance Show Card where
    show card = (suit card) ++ (symbol card)
    
shuffle rList = 
    foldl (\cards (i, r) -> swap cards i r) cards (zip [0..51] rList)
    where suit number = 
              case (number - 1) `div` 13 of 0 -> "S"
                                            1 -> "H"
                                            2 -> "D"
                                            3 -> "C"
          symbol number =
              case remain of 0  -> "K"
                             1  -> "A"
                             11 -> "J"
                             12 -> "Q"
                             _  -> show(remain)
              where remain = number `mod` 13
          slice from to = take (to - from) . drop from
          swap cards i j =
              if a == b then cards 
              else (take a cards) ++ 
                  ((cards !! b) : (slice (a + 1) b cards)) ++ 
                  ((cards !! a) : (drop (b + 1) cards))
              where [a, b] = sort [i, j]
          cards = [Card (suit \$ i + 1) (symbol \$ i + 1) | i <- [0..51]]
          
main = do
    gen <- getStdGen
    print \$ shuffle \$ rand gen 52
    where rand gen n= take n \$ randomRs (0, 51) gen::[Int]