Deal cards for FreeCell
You are encouraged to solve this task according to the task description, using any language you may know.
Free Cell is the solitaire card game that Paul Alfille introduced to the PLATO system in 1978. Jim Horne, at Microsoft, changed the name to FreeCell and reimplemented the game for DOS, then Windows. This version introduced 32000 numbered deals. (The Freecell FAQ tells this history.)
As the game became popular, Jim Horne disclosed the algorithm, and other implementations of FreeCell began to reproduce the Microsoft deals. These deals are numbered from 1 to 32000. Newer versions from Microsoft have 1 million deals, numbered from 1 to 1000000; some implementations allow numbers outside that range.
The algorithm uses this linear congruential generator from Microsoft C:
- is in range 0 to 32767.
- Rosetta Code has another task, linear congruential generator, with code for this RNG in several languages.
The algorithm follows:
- Seed the RNG with the number of the deal.
- Create an array of 52 cards: Ace of Clubs, Ace of Diamonds, Ace of Hearts, Ace of Spades, 2 of Clubs, 2 of Diamonds, and so on through the ranks: Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King. The array indexes are 0 to 51, with Ace of Clubs at 0, and King of Spades at 51.
- Until the array is empty:
- Choose a random card at index ≡ next random number (mod array length).
- Swap this random card with the last card of the array.
- Remove this random card from the array. (Array length goes down by 1.)
- Deal this random card.
- Deal all 52 cards, face up, across 8 columns. The first 8 cards go in 8 columns, the next 8 cards go on the first 8 cards, and so on.
Order to deal cards | Game #1 | Game #617 |
---|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
JD 2D 9H JC 5D 7H 7C 5H KD KC 9S 5S AD QC KH 3H 2S KS 9D QD JS AS AH 3C 4C 5C TS QH 4H AC 4D 7S 3S TD 4S TH 8H 2C JH 7D 6D 8S 8D QS 6C 3D 8C TC 6S 9C 2H 6H |
7D AD 5C 3S 5S 8C 2D AH TD 7S QD AC 6D 8H AS KH TH QC 3H 9D 6S 8D 3D TC KD 5H 9S 3C 8S 7H 4D JS 4C QS 9C 9H 7C 6H 2C 2S 4S TS 2H 5D JC 6C JH QH JD KS KC 4H |
Deals can also be checked against FreeCell solutions to 1000000 games. (Summon a video solution, and it displays the initial deal.)
Write a program to take a deal number and deal cards in the same order as this algorithm. The program may display the cards with ASCII, with Unicode, by drawing graphics, or any other way.
BBC BASIC
<lang bbcbasic> *FLOAT 64
hand% = 617 REM Initialise card library: SYS "LoadLibrary", "CARDS.DLL" TO cards% IF cards% = 0 ERROR 100, "No CARDS library" SYS "GetProcAddress", cards%, "cdtInit" TO cdtInit% SYS "GetProcAddress", cards%, "cdtDraw" TO cdtDraw% SYS cdtInit%, ^dx%, ^dy% VDU 23,22,8*dx%;5*dy%;8,16,16,128 REM Initialise deck: DIM card&(51) FOR I% = 0 TO 51 : card&(I%) = I% : NEXT REM Shuffle deck: dummy% = FNrng(hand%) FOR I% = 51 TO 0 STEP -1 C% = FNrng(-1) MOD (I% + 1) SWAP card&(C%), card&(I%) NEXT REM Display deck: FOR I% = 0 TO 51 C% = card&(51 - I%) X% = (I% MOD 8) * dx% Y% = (I% DIV 8) * dy% * 2 / 3 SYS cdtDraw%, @memhdc%, X%, Y%, C%, 0, 0 NEXT SYS "InvalidateRect", @hwnd%, 0, 0 *GSAVE freecell END DEF FNrng(seed) PRIVATE state, M% IF seed >= 0 THEN state = seed ELSE state = (state * 214013 + 2531011) FOR M% = 52 TO 31 STEP -1 IF state >= 2^M% state -= 2^M% NEXT ENDIF = state >> 16</lang>
- Output:
Bracmat
<lang bracmat>( ( createArray
= array rank ranks suit suits . A 2 3 4 5 6 7 8 9 T J Q K:?ranks & :?array & whl ' ( !ranks:%?rank ?ranks & ♣ ♦ ♥ ♠:?suits & whl ' ( !suits:%?suit ?suits & !array str$(!rank !suit):?array ) ) & !array )
& ( deal
= A B D L Z pick card dealt deck , i last rand row state . !arg:(?deck:? [?L.?state) & 8:?row & :?dealt & ( pick = sep . ( -1+!row:>0:?row & " ":?sep | \n:?sep&8:?row ) & !dealt !arg !sep:?dealt ) & 2^31:?B & 2^16:?D & " 'Hard code' the numbers B and D into the rand function using macro expansion. (Gives a marginally faster execution speed.) " & ' ( . mod$(!state*214013+2531011.$B):?state & div$(!state.$D) ) : (=?rand) & !L+1:?L & whl ' ( mod$(rand$.!L+-1:?L):?i & !deck:?A [!i %?card ?Z & ( !Z:?Z %@?last&!A !last !Z | !A ) : ?deck & pick$!card ) & pick$\n & str$!dealt )
& createArray$:?deck & put$("Game #1\n","dealt.txt",NEW) & put$(deal$(!deck.1),"dealt.txt",APP) & put$("
Game #617
","dealt.txt",APP)
& put$(deal$(!deck.617),"dealt.txt",APP)
&
)</lang>
Content of dealt.txt
:
Game #1 J♦ 2♦ 9♥ J♣ 5♦ 7♥ 7♣ 5♥ K♦ K♣ 9♠ 5♠ A♦ Q♣ K♥ 3♥ 2♠ K♠ 9♦ Q♦ J♠ A♠ A♥ 3♣ 4♣ 5♣ T♠ Q♥ 4♥ A♣ 4♦ 7♠ 3♠ T♦ 4♠ T♥ 8♥ 2♣ J♥ 7♦ 6♦ 8♠ 8♦ Q♠ 6♣ 3♦ 8♣ T♣ 6♠ 9♣ 2♥ 6♥ Game #617 7♦ A♦ 5♣ 3♠ 5♠ 8♣ 2♦ A♥ T♦ 7♠ Q♦ A♣ 6♦ 8♥ A♠ K♥ T♥ Q♣ 3♥ 9♦ 6♠ 8♦ 3♦ T♣ K♦ 5♥ 9♠ 3♣ 8♠ 7♥ 4♦ J♠ 4♣ Q♠ 9♣ 9♥ 7♣ 6♥ 2♣ 2♠ 4♠ T♠ 2♥ 5♦ J♣ 6♣ J♥ Q♥ J♦ K♠ K♣ 4♥
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <locale.h>
wchar_t s_suits[] = L"♣♦♥♠", s_nums[] = L"A23456789TJQK";
- define RMAX32 ((1U << 31) - 1)
static int seed = 1; int rnd(void) { return (seed = (seed * 214013 + 2531011) & RMAX32) >> 16; } void srnd(int x) { seed = x; }
void show(const int *c) { int i; for (i = 0; i < 52; c++) { printf(" \033[%dm%lc\033[m%lc", 32 - (1 + *c) % 4 / 2, s_suits[*c % 4], s_nums[*c / 4]); if (!(++i % 8) || i == 52) putchar('\n'); } }
void deal(int s, int *t) { int i, j; srnd(s);
for (i = 0; i < 52; i++) t[i] = 51 - i; for (i = 0; i < 51; i++) { j = 51 - rnd() % (52 - i); s = t[i], t[i] = t[j], t[j] = s; } }
int main(int c, char **v) { int s, card[52]; if (c < 2 || (s = atoi(v[1])) <= 0) s = 11982;
setlocale(LC_ALL, "");
deal(s, card); printf("Hand %d\n", s); show(card);
return 0; }</lang>
Common Lisp
<lang lisp>(defun make-rng (seed)
#'(lambda ()
(ash (setf seed (mod (+ (* 214013 seed) 2531011) (expt 2 31))) -16)))
(defun split (s) (map 'list #'string s))
(defun make-deck (seed)
(let ((hand (make-array 52 :fill-pointer 0))
(rng (make-rng seed)))
(dolist (s (split "A23456789TJQK")) (dolist (d (split "♣♦♥♠"))
(vector-push (concatenate 'string d s) hand)))
(dotimes (i 52)
(rotatef (aref hand (- 51 i)) (aref hand (mod (funcall rng) (- 52 i)))))
(nreverse hand)))
(defun show-deck (seed)
(let ((hand (make-deck seed))) (format t "~%Hand ~d~%" seed) (dotimes (i 52) (format t "~A " (aref hand i)) (if (= (mod i 8) 7) (write-line "")))))
(show-deck 1) (show-deck 617)</lang>
C#
Longer than it absolutely needs to be because I split out several independently useful classes. <lang csharp>using System; using System.Collections.Generic; using System.Text;
namespace FreeCellDeals {
public class RNG { private int _state;
public RNG() { _state = (int)DateTime.Now.Ticks; }
public RNG(int n) { _state = n; } public int Next() { return ((_state = 214013 * _state + 2531011) & int.MaxValue) >> 16; } }
public enum Rank { Ace, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King }
public enum Suit { Clubs, Diamonds, Hearts, Spades }
public class Card { private const string Ranks = "A23456789TJQK"; private const string Suits = "CDHS";
private Rank _rank; public Rank Rank { get { return _rank; } set { if ((int)value < 0 || (int)value > 12) { throw new InvalidOperationException("Setting card rank out of range"); } _rank = value; } }
private Suit _suit; public Suit Suit { get { return _suit; } set { if ((int)value < 0 || (int)value > 3) { throw new InvalidOperationException("Setting card rank out of range"); } _suit = value; } }
public Card(Rank rank, Suit suit) { Rank = rank; Suit = suit; }
public int NRank() { return (int) Rank; }
public int NSuit() { return (int) Suit; }
public override string ToString() { return new string(new[] {Ranks[NRank()], Suits[NSuit()]}); } }
public class FreeCellDeal { public List<Card> Deck { get; private set; }
public FreeCellDeal(int iDeal) { RNG rng = new RNG(iDeal);
List<Card> rDeck = new List<Card>(); Deck = new List<Card>();
for (int rank = 0; rank < 13; rank++) { for (int suit = 0; suit < 4; suit++) { rDeck.Add(new Card((Rank)rank, (Suit)suit)); } }
// Normally we deal from the front of a deck. The algorithm "deals" from the back so we reverse the // deck here to more conventionally deal from the front/start of the array. for (int iCard = 51; iCard >= 0; iCard--) { int iSwap = rng.Next() % (iCard + 1); Deck.Add(rDeck[iSwap]); rDeck[iSwap] = rDeck[iCard]; } }
public override string ToString() { StringBuilder sb = new StringBuilder(); for (int iRow = 0; iRow < 6; iRow++ ) { for (int iCol = 0; iCol < 8; iCol++) { sb.AppendFormat("{0} ", Deck[iRow * 8 + iCol]); } sb.Append("\n"); } for (int iCard = 48; iCard < 52; iCard++) { sb.AppendFormat("{0} ", Deck[iCard]); } return sb.ToString(); } }
class Program { static void Main() { Console.WriteLine(new FreeCellDeal(1)); Console.WriteLine(); Console.WriteLine(new FreeCellDeal(617)); } }
}</lang>
- Output:
JD 2D 9H JC 5D 7H 7C 5H KD KC 9S 5S AD QC KH 3H 2S KS 9D QD JS AS AH 3C 4C 5C TS QH 4H AC 4D 7S 3S TD 4S TH 8H 2C JH 7D 6D 8S 8D QS 6C 3D 8C TC 6S 9C 2H 6H 7D AD 5C 3S 5S 8C 2D AH TD 7S QD AC 6D 8H AS KH TH QC 3H 9D 6S 8D 3D TC KD 5H 9S 3C 8S 7H 4D JS 4C QS 9C 9H 7C 6H 2C 2S 4S TS 2H 5D JC 6C JH QH JD KS KC 4H
D
<lang d>import std.stdio, std.conv, std.algorithm, std.range;
struct RandomGenerator {
uint seed = 1;
@property uint next() pure nothrow { seed = (seed * 214_013 + 2_531_011) & int.max; return seed >> 16; }
}
struct Deck {
int[52] cards;
void deal(in uint seed) /*pure nothrow*/ { enum int nc = cards.length; // Must be signed for iota.
// DMD 2.055 iota isn't pure nothrow. copy(iota(nc - 1, -1, -1), cards[]);
auto rnd = RandomGenerator(seed); foreach (i, ref c; cards) swap(c, cards[(nc - 1) - rnd.next % (nc - i)]); }
void show() { foreach (row; std.range.chunks(cards[], 8)) { foreach (c; row) write(" ", "A23456789TJQK"[c / 4], "CDHS"[c % 4]); writeln(); } }
}
void main(in string[] args) {
immutable seed = (args.length == 2) ? to!uint(args[1]) : 11_982; writeln("Hand ", seed); Deck cards; cards.deal(seed); cards.show();
}</lang>
Hand 11982 AH AS 4H AC 2D 6S TS JS 3D 3H QS QC 8S 7H AD KS KD 6H 5S 4D 9H JH 9S 3C JC 5D 5C 8C 9D TD KH 7C 6C 2C TH QH 6D TC 4S 7S JD 7D 8H 9C 2H QD 4C 5H KC 8D 2S 3S
Go
<lang go>package main
import (
"fmt" "math" "math/rand" "os" "strconv" "time"
)
const sSuits = "CDHS" const sNums = "A23456789TJQK" const rMax32 = math.MaxInt32
var seed = 1
func rnd() int {
seed = (seed*214013 + 2531011) & rMax32 return seed >> 16
}
func deal(s int) []int {
seed = s t := make([]int, 52) for i := 0; i < 52; i++ { t[i] = 51 - i } for i := 0; i < 51; i++ { j := 51 - rnd()%(52-i) t[i], t[j] = t[j], t[i] } return t
}
func show(cs []int) {
for i, c := range cs { fmt.Printf(" %c%c", sNums[c/4], sSuits[c%4]) if (i+1)%8 == 0 || i+1 == len(cs) { fmt.Println() } }
}
func main() {
var game int switch len(os.Args) { case 1: rand.Seed(time.Now().UnixNano()) game = 1 + rand.Intn(32000) case 2: var err error game, err = strconv.Atoi(os.Args[1]) if err == nil && game >= 1 && game <= 32000 { break } fallthrough default: fmt.Println("usage: deal [game]") fmt.Println(" where game is a number in the range 1 to 32000") return } fmt.Printf("\nGame #%d\n", game) show(deal(game))
}</lang>
- Output:
Game #1 JD 2D 9H JC 5D 7H 7C 5H KD KC 9S 5S AD QC KH 3H 2S KS 9D QD JS AS AH 3C 4C 5C TS QH 4H AC 4D 7S 3S TD 4S TH 8H 2C JH 7D 6D 8S 8D QS 6C 3D 8C TC 6S 9C 2H 6H Game #617 7D AD 5C 3S 5S 8C 2D AH TD 7S QD AC 6D 8H AS KH TH QC 3H 9D 6S 8D 3D TC KD 5H 9S 3C 8S 7H 4D JS 4C QS 9C 9H 7C 6H 2C 2S 4S TS 2H 5D JC 6C JH QH JD KS KC 4H
Haskell
<lang haskell>import Data.Int import Data.Bits import Data.List import Data.Array.ST import Control.Monad import Control.Monad.ST import System.Environment
srnd :: Int32 -> [Int] srnd = map (fromIntegral . flip shiftR 16) .
tail . iterate (\x -> (x * 214013 + 2531011) .&. maxBound)
deal :: Int32 -> [String] deal s = runST (do
ar <- newListArray (0,51) $ sequence ["A23456789TJQK", "CDHS"] :: ST s (STArray s Int String) forM (zip [52,51..1] rnd) $ \(n, r) -> do let j = r `mod` n vj <- readArray ar j vn <- readArray ar (n - 1) writeArray ar j vn return vj) where rnd = srnd s
showCards :: [String] -> IO () showCards = mapM_ (putStrLn . unwords) .
takeWhile (not . null) . unfoldr (Just . splitAt 8)
main :: IO () main = do
args <- getArgs let s = read (head args) :: Int32 putStrLn $ "Deal " ++ show s ++ ":" let cards = deal s showCards cards</lang>
Execution:
$ runghc freecell.hs 617 Deal 617: 7D AD 5C 3S 5S 8C 2D AH TD 7S QD AC 6D 8H AS KH TH QC 3H 9D 6S 8D 3D TC KD 5H 9S 3C 8S 7H 4D JS 4C QS 9C 9H 7C 6H 2C 2S 4S TS 2H 5D JC 6C JH QH JD KS KC 4H
Icon and Unicon
<lang Icon>procedure main(A) # freecelldealer
freecelldealer(\A[1] | &null) # seed from command line
end
procedure newDeck() #: return a new unshuffled deck
every D := list(52) & i := 0 & r := !"A23456789TJQK" & s := !"CDHS" do D[i +:= 1] := r || s # initial deck AC AD ... KS return D
end
procedure freecelldealer(gamenum) #: deal a freecell hand
/gamenum := 11982 return showHand(freecellshuffle(newDeck(),gamenum))
end
procedure showHand(D) #: show a freecell hand
write("Hand:\n") every writes(" ",(1 to 8) | "\n") every writes(" ",D[i := 1 to *D]) do if i%8 = 0 then write() write("\n") return D
end
procedure freecellshuffle(D,gamenum) #: freecell shuffle
srand_freecell(gamenum) # seed random number generator D2 := [] until *D = 0 do { # repeat until all dealt D[r := rand_freecell() % *D + 1] :=: D[*D] # swap random & last cards put(D2,pull(D)) # remove dealt card from list } return D2
end
procedure srand_freecell(x) #: seed random static seed
return seed := \x | \seed | 0 # parm or seed or zero if none
end
procedure rand_freecell() #: lcrng
return ishift(srand_freecell((214013 * srand_freecell() + 2531011) % 2147483648),-16)
end</lang>
- Sample output for game 1:
Hand: 1 2 3 4 5 6 7 8 JD 2D 9H JC 5D 7H 7C 5H KD KC 9S 5S AD QC KH 3H 2S KS 9D QD JS AS AH 3C 4C 5C TS QH 4H AC 4D 7S 3S TD 4S TH 8H 2C JH 7D 6D 8S 8D QS 6C 3D 8C TC 6S 9C 2H 6H
J
Paraphrase of C: <lang j>deck=: ,/ 'A23456789TJQK' ,"0/ 7 u: '♣♦♥♠'
srnd=: 3 :'SEED=:{.y,11982' srnd seed=: do bind 'SEED' rnd=: (2^16) <.@%~ (2^31) srnd@| 2531011 + 214013 * seed
pairs=: <@<@~.@(<: , (| rnd))@>:@i.@-@# NB. indices to swap, for shuffle swaps=: [: > C.&.>/@|.@; NB. implement the specified shuffle deal=: |.@(swaps pairs) bind deck
show=: (,"2)@:(_8 ]\ ' '&,.)</lang>
- Example use:
<lang j> show deal srnd 1
J♦ 2♦ 9♥ J♣ 5♦ 7♥ 7♣ 5♥ K♦ K♣ 9♠ 5♠ A♦ Q♣ K♥ 3♥ 2♠ K♠ 9♦ Q♦ J♠ A♠ A♥ 3♣ 4♣ 5♣ T♠ Q♥ 4♥ A♣ 4♦ 7♠ 3♠ T♦ 4♠ T♥ 8♥ 2♣ J♥ 7♦ 6♦ 8♠ 8♦ Q♠ 6♣ 3♦ 8♣ T♣ 6♠ 9♣ 2♥ 6♥ show deal srnd 617 7♦ A♦ 5♣ 3♠ 5♠ 8♣ 2♦ A♥ T♦ 7♠ Q♦ A♣ 6♦ 8♥ A♠ K♥ T♥ Q♣ 3♥ 9♦ 6♠ 8♦ 3♦ T♣ K♦ 5♥ 9♠ 3♣ 8♠ 7♥ 4♦ J♠ 4♣ Q♠ 9♣ 9♥ 7♣ 6♥ 2♣ 2♠ 4♠ T♠ 2♥ 5♦ J♣ 6♣ J♥ Q♥ J♦ K♠ K♣ 4♥ </lang>
OCaml
<lang ocaml>let srnd x =
(* since OCaml's built-in int type is at least 31 (note: not 32) bits wide, and this problem takes mod 2^31, it is just enough if we treat it as an unsigned integer, which means taking the logical right shift *) let seed = ref x in fun () -> seed := (!seed * 214013 + 2531011) land 0x7fffffff; !seed lsr 16
let deal s =
let rnd = srnd s in let t = Array.init 52 (fun i -> i) in let cards = Array.init 52 (fun j -> let n = 52 - j in let i = rnd() mod n in let this = t.(i) in t.(i) <- t.(pred n); this) in (cards)
let show cards =
let suits = "CDHS" and nums = "A23456789TJQK" in Array.iteri (fun i card -> Printf.printf "%c%c%c" nums.[card / 4] suits.[card mod 4] (if (i mod 8) = 7 then '\n' else ' ') ) cards; print_newline()
let () =
let s = try int_of_string Sys.argv.(1) with _ -> 11982 in Printf.printf "Deal %d:\n" s; let cards = deal s in show cards</lang>
- Execution:
$ ocaml freecell.ml 617 Deal 617: 7D AD 5C 3S 5S 8C 2D AH TD 7S QD AC 6D 8H AS KH TH QC 3H 9D 6S 8D 3D TC KD 5H 9S 3C 8S 7H 4D JS 4C QS 9C 9H 7C 6H 2C 2S 4S TS 2H 5D JC 6C JH QH JD KS KC 4H
PARI/GP
<lang parigp>card(n)=concat(["A","2","3","4","5","6","7","8","9","T","J","Q","K"][n\4+1],["C","D","H","S"][n%4+1]); nextrand()={
(state=(214013*state+2531011)%2^31)>>16
}; deal(seed)={
my(deck=vector(52,n,n-1),t); local(state=seed); forstep(last=52,1,-1, t=nextrand()%last+1; print1(card(deck[t])if(last%8==5,"\n"," ")); deck[t]=deck[last] )
};</lang>
Perl
<lang perl>#!/usr/bin/perl
use strict; use warnings;
use utf8;
sub deal {
my $s = shift;
my $rnd = sub { return (($s = ($s * 214013 + 2531011) & 0x7fffffff) >> 16 ); };
my @d; for my $b (split "", "A23456789TJQK") { push @d, map("$_$b", qw/♣ ♦ ♥ ♠/); }
for my $idx (reverse 0 .. $#d) { my $r = $rnd->() % ($idx + 1); @d[$r, $idx] = @d[$idx, $r]; }
return [reverse @d];
}
my $hand_idx = shift(@ARGV) // 11_982;
my $cards = deal($hand_idx);
my $num_cards_in_height = 8; my $string = ;
while (@$cards) {
$string .= join(' ', splice(@$cards, 0, 8)) . "\n";
}
binmode STDOUT, ':encoding(utf-8)'; print "Hand $hand_idx\n"; print $string;</lang>
Perl 6
<lang perl6>my $game_number = @*ARGS.shift || 1;
sub ms_lcg_method ($seed) { ( 214013 * $seed + 2531011 ) % 2**31 };
- lazy list of the random sequence
my @ms_lcg := gather take $_ +> 16
for ( $game_number.&ms_lcg_method, -> $seed { $seed.&ms_lcg_method } ... * );
my @deck = <A 2 3 4 5 6 7 8 9 T J Q K> X~ <♣ ♦ ♥ ♠>;
my @game = gather while @deck {
my $index = @ms_lcg.shift % @deck; take @deck[$index]; @deck[$index] = @deck.pop;
}
say "Game #$game_number"; say @game.splice(0, min(@game.elems, 8)) while @game;</lang>
PicoLisp
Using the random generator from Linear congruential generator#PicoLisp: <lang PicoLisp>(setq *MsSeed 11982)
(de msRand ()
(>> 16 (setq *MsSeed (& (+ 2531011 (* 214013 *MsSeed)) `(dec (** 2 31))) ) ) )
(let L
(make (for Num (range 13 1) (for Suit '((32 . "♠") (31 . "♥") (31 . "♦") (32 . "♣")) (link (cons (get '`(chop "A23456789TJQK") Num) Suit)) ) ) ) (for I 51 (xchg (nth L I) (nth L (- 52 (% (msRand) (- 53 I)))) ) ) (for C L (prin " ^[[" (cadr C) "m" (cddr C) "^[[m" (car C)) (at (0 . 8) (prinl)) ) (prinl) )</lang>
PureBasic
<lang purebasic>#MaxCardNum = 51 ;zero-based count of cards in a deck Global deckSize Global Dim cards(#MaxCardNum) ;card with highest index is at the top of deck
Procedure RNG(seed.q = -1)
Static state.q If seed >= 0 state = seed Else state = (state * 214013 + 2531011) % (1 << 31) ProcedureReturn state >> 16 EndIf
EndProcedure
Procedure makeDeck(hand)
Protected i, c For i = 0 To #MaxCardNum: cards(i) = i: Next RNG(hand) ;set seed value deckSize = #MaxCardNum While deckSize c = RNG() % (deckSize + 1) Swap cards(c), cards(deckSize) deckSize - 1 Wend deckSize = #MaxCardNum
EndProcedure
Procedure showDeck(hand)
Protected i, c PrintN("Hand #" + Str(hand)) makeDeck(hand) For i = 0 To #MaxCardNum c = cards(#MaxCardNum - i) Print(" " + Mid("A23456789TJQK", (c / 4) + 1, 1) + Mid("CDHS",(c % 4) + 1, 1)) If (i + 1) % 8 = 0 Or i = #MaxCardNum: PrintN(""): EndIf Next
EndProcedure
If OpenConsole()
showDeck(1) showDeck(617) showDeck(11982) Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input() CloseConsole()
EndIf</lang>
- Sample output:
Hand #1 JD 2D 9H JC 5D 7H 7C 5H KD KC 9S 5S AD QC KH 3H 2S KS 9D QD JS AS AH 3C 4C 5C TS QH 4H AC 4D 7S 3S TD 4S TH 8H 2C JH 7D 6D 8S 8D QS 6C 3D 8C TC 6S 9C 2H 6H Hand #617 7D AD 5C 3S 5S 8C 2D AH TD 7S QD AC 6D 8H AS KH TH QC 3H 9D 6S 8D 3D TC KD 5H 9S 3C 8S 7H 4D JS 4C QS 9C 9H 7C 6H 2C 2S 4S TS 2H 5D JC 6C JH QH JD KS KC 4H Hand #11982 AH AS 4H AC 2D 6S TS JS 3D 3H QS QC 8S 7H AD KS KD 6H 5S 4D 9H JH 9S 3C JC 5D 5C 8C 9D TD KH 7C 6C 2C TH QH 6D TC 4S 7S JD 7D 8H 9C 2H QD 4C 5H KC 8D 2S 3S
Python
<lang python>from sys import argv
def randomGenerator(seed=1):
max_int32 = (1 << 31) - 1 seed = seed & max_int32
while True: seed = (seed * 214013 + 2531011) & max_int32 yield seed >> 16
def deal(seed):
nc = 52 cards = range(nc - 1, -1, -1) rnd = randomGenerator(seed) for i, r in zip(range(nc), rnd): j = (nc - 1) - r % (nc - i) cards[i], cards[j] = cards[j], cards[i] return cards
def show(cards):
l = ["A23456789TJQK"[c / 4] + "CDHS"[c % 4] for c in cards] for i in range(0, len(cards), 8): print " ", " ".join(l[i : i+8])
if __name__ == '__main__':
seed = int(argv[1]) if len(argv) == 2 else 11982 print "Hand", seed deck = deal(seed) show(deck)</lang>
- Output:
Hand 11982 AH AS 4H AC 2D 6S TS JS 3D 3H QS QC 8S 7H AD KS KD 6H 5S 4D 9H JH 9S 3C JC 5D 5C 8C 9D TD KH 7C 6C 2C TH QH 6D TC 4S 7S JD 7D 8H 9C 2H QD 4C 5H KC 8D 2S 3S
Ruby
<lang ruby># Deal cards for FreeCell.
require 'optparse'
- Parse command-line arguments.
- games = ARGV converted to Integer
- No arguments? Pick any of first 32000 games.
games = nil OptionParser.new do |o|
begin o.banner = "Usage: #{o.program_name} number..." o.parse! games = ARGV.map {|s| Integer(s)} games.empty? and games = [rand(32000)] rescue => e $stderr.puts e, o abort end
end
- Define methods for old Ruby versions.
- Enumerable#each_slice appeared in Ruby 1.8.7.
- Enumerable#flat_map appeared in Ruby 1.9.2.
module Enumerable
unless method_defined? :each_slice def each_slice(count) block_given? or return enum_for(:each_slice, count) ary = [] each {|e| ary << e ary.length == count and (yield ary.dup; ary.clear)} ary.empty? or yield ary.dup nil end end
unless method_defined? :flat_map def flat_map block_given? or return enum_for(:flat_map) ary = [] each {|e| y = yield e ary.concat(y) rescue ary.push(y)} ary end end
end
- Create original deck of 52 cards, not yet shuffled.
orig_deck = %w{A 2 3 4 5 6 7 8 9 T J Q K }.flat_map {|rank| %w{C D H S}.map {|suit| "#{rank}#{suit}"}}
games.each do |seed|
deck = orig_deck.dup
# Shuffle deck with random index from linear congruential # generator like Microsoft. state = seed 52.downto(2) do |len| state = ((214013 * state) + 2531011) & 0x7fff_ffff index = (state >> 16) % len last = len - 1 deck[index], deck[last] = deck[last], deck[index] end
deck.reverse! # Shuffle did reverse deck. Do reverse again.
# Deal cards. puts "Game ##{seed}" deck.each_slice(8) {|row| puts " " + row.join(" ")}
end</lang>
- Output:
$ ruby freecell.rb 11982 Game #11982 AH AS 4H AC 2D 6S TS JS 3D 3H QS QC 8S 7H AD KS KD 6H 5S 4D 9H JH 9S 3C JC 5D 5C 8C 9D TD KH 7C 6C 2C TH QH 6D TC 4S 7S JD 7D 8H 9C 2H QD 4C 5H KC 8D 2S 3S
Tcl
<lang tcl>proc rnd Template:*r seed {
upvar 1 ${*r} r expr {[set r [expr {($r * 214013 + 2531011) & 0x7fffffff}]] >> 16}
} proc show cards {
set suits {\u2663 \u2666 \u2665 \u2660} set values {A 2 3 4 5 6 7 8 9 T J Q K} for {set i 0} {$i < 52} {incr i} {
set c [lindex $cards $i] puts -nonewline [format " \033\[%dm%s\033\[m%s" [expr {32-(1+$c)%4/2}] \ [lindex $suits [expr {$c % 4}]] [lindex $values [expr {$c / 4}]]] if {($i&7)==7 || $i==51} {puts ""}
}
} proc deal {seed} {
for {set i 0} {$i < 52} {incr i} {lappend cards [expr {51 - $i}]} for {set i 0} {$i < 51} {incr i} {
set j [expr {51 - [rnd]%(52-$i)}] set tmp [lindex $cards $i] lset cards $i [lindex $cards $j] lset cards $j $tmp
} return $cards
}
if {![scan =[lindex $argv 0]= =%d= s] || $s <= 0} {
set s 11982
} set cards [deal $s] puts "Hand $s" show $cards</lang>
UNIX Shell
<lang bash>test $# -gt 0 || set -- $((RANDOM % 32000)) for seed; do print Game $seed:
# Shuffle deck. deck=({A,{2..9},T,J,Q,K}{C,D,H,S}) for i in {52..1}; do ((seed = (214013 * seed + 2531011) & 0x7fffffff)) ((j = (seed >> 16) % i + 1)) t=$deck[$i] deck[$i]=$deck[$j] deck[$j]=$t done
# Deal cards. print -n ' ' for i in {52..1}; do print -n ' '$deck[$i] ((i % 8 == 5)) && print -n $'\n ' done print done</lang>
- Output:
$ zsh freecell.sh 80388 Game 80388: QC 5H AS 7H 8S 4S 4H 3H QD 3S 2C 2S 7D AH 6D 3D QS TH QH 3C 2H JS 5D 5C AD TD 6H JD 5S 7S 4D 7C 9S KC TC KH 8C 9D 8D JH KS AC KD 9C 9H 6C JC 2D 4C 8H TS 6S