洗撲克牌(亂數排列)


說明

洗撲克牌的原理其實與亂數排列是相同的,都是將一組數字(例如1∼N)打亂重新排列,只不過洗撲克牌多了一個花色判斷的動作而已。

解法

初學者通常會直接想到,隨機產生1∼N的亂數並將之存入陣列中,後來產生的亂數存入陣列前必須先檢查陣列中是否已有重複的數字,如果有這個數就不存入,再重新產生下一個數,運氣不好的話,重複的次數就會很多,程式的執行速度就很慢了,這不是一個好方法。

以1∼52的亂數排列為例好了,可以將陣列先依序由1到52填入,然後使用一個迴圈走訪陣列,並隨機產生1∼52的亂數,將產生的亂數當作索引取出陣列值,並與目前陣列走訪到的值相交換,如此就不用擔心亂數重複的問題了,陣列走訪完畢後,所有的數字也就重新排列了。

至於如何判斷花色?這只是除法的問題而已,取商數判斷花色,取餘數判斷數字,您可以直接看程式比較清楚。

實作:C    Java    Python    Scala    Ruby    JavaScript    Haskell

  • C
#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);
}
}

  • Java
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' : ' ');
}
}
}

  • Python
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 " ")

  • Scala
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 ' ')
}

  • Ruby
# encoding: Big5
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

  • JavaScript
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());

  • Haskell
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]