2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,2 +1,45 @@
|
|||
Implement the [[wp:Knuth shuffle|Knuth shuffle]] (a.k.a. the Fisher-Yates shuffle) for an integer array (or, if possible, an array of any type).
|
||||
The Knuth shuffle is used to create a random permutation of an array.
|
||||
The [[wp:Knuth shuffle|Knuth shuffle]] (a.k.a. the Fisher-Yates shuffle) is an algorithm for randomly shuffling the elements of an array.
|
||||
|
||||
{{task heading}}
|
||||
|
||||
Implement the Knuth shuffle for an integer array (or, if possible, an array of any type).
|
||||
|
||||
{{task heading|Specification}}
|
||||
|
||||
Given an array '''''items''''' with indices ranging from ''0'' to '''''last''''', the algorithm can be defined as follows (pseudo-code):
|
||||
|
||||
'''for''' ''i'' '''from''' ''last'' '''downto''' 1 '''do''':
|
||||
'''let''' ''j'' = random integer in range ''0'' <math>\leq</math> ''j'' <math>\leq</math> ''i''
|
||||
'''swap''' ''items''[''i''] '''with''' ''items''[''j'']
|
||||
|
||||
Notes:
|
||||
* It modifies the input array in-place. If that is unreasonable in your programming language, you may amend the algorithm to return the shuffled items as a new array instead.
|
||||
* The algorithm can also be amended to iterate from left to right, if that is more convenient.
|
||||
|
||||
{{task heading|Test cases}}
|
||||
|
||||
{| class="wikitable"
|
||||
|-
|
||||
! Input array
|
||||
! Possible output arrays
|
||||
|-
|
||||
| <tt>[]</tt>
|
||||
| <tt>[]</tt>
|
||||
|-
|
||||
| <tt>[10]</tt>
|
||||
| <tt>[10]</tt>
|
||||
|-
|
||||
| <tt>[10, 20]</tt>
|
||||
| <tt>[10, 20]</tt><br><tt>[20, 10]</tt>
|
||||
|-
|
||||
| <tt>[10, 20, 30]</tt>
|
||||
| <tt>[10, 20, 30]</tt><br><tt>[10, 30, 20]</tt><br><tt>[20, 10, 30]</tt><br><tt>[20, 30, 10]</tt><br><tt>[30, 10, 20]</tt><br><tt>[30, 20, 10]</tt>
|
||||
|}
|
||||
|
||||
(These are listed here just for your convenience; no need to demonstrate them on the page.)
|
||||
|
||||
{{task heading|Related tasks}}
|
||||
|
||||
* [[Sattolo cycle]]
|
||||
|
||||
<hr>
|
||||
|
|
|
|||
73
Task/Knuth-shuffle/AppleScript/knuth-shuffle-3.applescript
Normal file
73
Task/Knuth-shuffle/AppleScript/knuth-shuffle-3.applescript
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
-- knuthShuffle :: [a] -> [a]
|
||||
on knuthShuffle(lst)
|
||||
|
||||
-- randomSwap :: [Int] -> Int -> [Int]
|
||||
script randomSwap
|
||||
on lambda(a, i)
|
||||
if i > 1 then
|
||||
set iRand to random number from 1 to i
|
||||
|
||||
tell a
|
||||
set tmp to item iRand
|
||||
set item iRand to item i
|
||||
set item i to tmp
|
||||
it
|
||||
end tell
|
||||
else
|
||||
a
|
||||
end if
|
||||
end lambda
|
||||
end script
|
||||
|
||||
foldr(randomSwap, lst, range(1, length of lst))
|
||||
end knuthShuffle
|
||||
|
||||
|
||||
-- TEST
|
||||
|
||||
on run
|
||||
knuthShuffle(["alpha", "beta", "gamma", "delta", "epsilon", ¬
|
||||
"zeta", "eta", "theta", "iota", "kappa", "lambda", "mu"])
|
||||
end run
|
||||
|
||||
|
||||
|
||||
-- GENERIC LIBRARY FUNCTIONS
|
||||
|
||||
-- foldr :: (a -> b -> a) -> a -> [b] -> a
|
||||
on foldr(f, startValue, xs)
|
||||
tell mReturn(f)
|
||||
set v to startValue
|
||||
set lng to length of xs
|
||||
repeat with i from lng to 1 by -1
|
||||
set v to lambda(v, item i of xs, i, xs)
|
||||
end repeat
|
||||
return v
|
||||
end tell
|
||||
end foldr
|
||||
|
||||
-- Lift 2nd class handler function into 1st class script wrapper
|
||||
-- mReturn :: Handler -> Script
|
||||
on mReturn(f)
|
||||
if class of f is script then
|
||||
f
|
||||
else
|
||||
script
|
||||
property lambda : f
|
||||
end script
|
||||
end if
|
||||
end mReturn
|
||||
|
||||
-- range :: Int -> Int -> [Int]
|
||||
on range(m, n)
|
||||
if n < m then
|
||||
set d to -1
|
||||
else
|
||||
set d to 1
|
||||
end if
|
||||
set lst to {}
|
||||
repeat with i from m to n by d
|
||||
set end of lst to i
|
||||
end repeat
|
||||
return lst
|
||||
end range
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
{"mu", "theta", "alpha", "delta", "zeta", "gamma",
|
||||
"iota", "kappa", "lambda", "epsilon", "beta", "eta"}
|
||||
29
Task/Knuth-shuffle/Elena/knuth-shuffle.elena
Normal file
29
Task/Knuth-shuffle/Elena/knuth-shuffle.elena
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#import system.
|
||||
#import system'routines.
|
||||
#import extensions.
|
||||
|
||||
#symbol(const)MAX = 10.
|
||||
|
||||
#class(extension) randomOp
|
||||
{
|
||||
#method randomize
|
||||
[
|
||||
#var max := self length.
|
||||
|
||||
0 till:max &doEach: i
|
||||
[
|
||||
#var j := randomGenerator eval:i:max.
|
||||
|
||||
self exchange:i:j.
|
||||
].
|
||||
|
||||
^ self.
|
||||
]
|
||||
}
|
||||
|
||||
#symbol program =
|
||||
[
|
||||
#var a := Array new:MAX set &every:(&index:i) [ i ].
|
||||
|
||||
console writeLine:(a randomize).
|
||||
].
|
||||
|
|
@ -6,18 +6,17 @@ defmodule Knuth do
|
|||
end
|
||||
|
||||
defp random_move( n, {inputs, acc} ) do
|
||||
item = Enum.at( inputs, :random.uniform(n)-1 )
|
||||
item = Enum.at( inputs, :rand.uniform(n)-1 )
|
||||
{List.delete( inputs, item ), [item | acc]}
|
||||
end
|
||||
end
|
||||
|
||||
:random.seed( :os.timestamp )
|
||||
seq = Enum.to_list( 0..19 )
|
||||
IO.inspect Knuth.shuffle( seq )
|
||||
|
||||
seq = [1,2,3]
|
||||
Enum.reduce(1..100000, Map.new, fn _,acc ->
|
||||
k = Knuth.shuffle(seq)
|
||||
Dict.update(acc, k, 1, &(&1+1))
|
||||
Map.update(acc, k, 1, &(&1+1))
|
||||
end)
|
||||
|> Enum.each(fn {k,v} -> IO.inspect {k,v} end)
|
||||
|
|
|
|||
38
Task/Knuth-shuffle/JavaScript/knuth-shuffle-2.js
Normal file
38
Task/Knuth-shuffle/JavaScript/knuth-shuffle-2.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
(lst => {
|
||||
|
||||
// knuthShuffle :: [a] -> [a]
|
||||
let knuthShuffle = lst =>
|
||||
range(0, lst.length - 1)
|
||||
.reduceRight((a, i) => {
|
||||
let iRand = i ? randomInteger(0, i) : 0,
|
||||
tmp = a[iRand];
|
||||
|
||||
return iRand !== i ? (
|
||||
a[iRand] = a[i],
|
||||
a[i] = tmp,
|
||||
a
|
||||
) : a;
|
||||
}, lst),
|
||||
|
||||
// randomInteger :: Int -> Int -> Int
|
||||
randomInteger = (low, high) =>
|
||||
low + Math.floor(
|
||||
(Math.random() * ((high - low) + 1))
|
||||
),
|
||||
|
||||
// range :: Int -> Int -> Maybe Int -> [Int]
|
||||
range = (m, n, step) => {
|
||||
let d = (step || 1) * (n >= m ? 1 : -1);
|
||||
|
||||
return Array.from({
|
||||
length: Math.floor((n - m) / d) + 1
|
||||
}, (_, i) => m + (i * d));
|
||||
};
|
||||
|
||||
|
||||
return knuthShuffle(lst);
|
||||
|
||||
})(
|
||||
'alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu'
|
||||
.split(' ')
|
||||
);
|
||||
2
Task/Knuth-shuffle/JavaScript/knuth-shuffle-3.js
Normal file
2
Task/Knuth-shuffle/JavaScript/knuth-shuffle-3.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
["iota", "epsilon", "kappa", "theta", "gamma", "delta",
|
||||
"lambda", "eta", "zeta", "beta", "mu", "alpha"]
|
||||
56
Task/Knuth-shuffle/JavaScript/knuth-shuffle-4.js
Normal file
56
Task/Knuth-shuffle/JavaScript/knuth-shuffle-4.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
(lst => {
|
||||
|
||||
// knuthShuffle :: [a] -> [a]
|
||||
function knuthShuffle(lst) {
|
||||
let lng = lst.length;
|
||||
|
||||
return lng ? range(0, lng - 1)
|
||||
.reduceRight((a, i) => {
|
||||
let iRand = i > 0 ? randomInteger(0, i) : 0;
|
||||
|
||||
return i !== iRand ? swapped(a, i, iRand) : a;
|
||||
}, lst) : [];
|
||||
};
|
||||
|
||||
|
||||
// A non-mutating variant of swapped():
|
||||
|
||||
// swapped :: [a] -> Int -> Int -> [a]
|
||||
let swapped = (lst, iFrom, iTo) => {
|
||||
let [iLow, iHigh] = iTo > iFrom ? (
|
||||
[iFrom, iTo]
|
||||
) : [iTo, iFrom];
|
||||
|
||||
return iLow !== iHigh ? (
|
||||
[].concat(
|
||||
(iLow > 0 ? lst.slice(0, iLow) : []), // pre
|
||||
lst[iHigh], // DOWN
|
||||
lst.slice(iLow + 1, iHigh), // mid
|
||||
lst[iLow], // UP
|
||||
lst.slice(iHigh + 1) // post
|
||||
)
|
||||
) : lst.slice(0) // (unchanged copy)
|
||||
},
|
||||
|
||||
// randomInteger :: Int -> Int -> Int
|
||||
randomInteger = (low, high) =>
|
||||
low + Math.floor(
|
||||
(Math.random() * ((high - low) + 1))
|
||||
),
|
||||
|
||||
// range :: Int -> Int -> Maybe Int -> [Int]
|
||||
range = (m, n, step) => {
|
||||
let d = (step || 1) * (n >= m ? 1 : -1);
|
||||
|
||||
return Array.from({
|
||||
length: Math.floor((n - m) / d) + 1
|
||||
}, (_, i) => m + (i * d));
|
||||
};
|
||||
|
||||
|
||||
return knuthShuffle(lst);
|
||||
|
||||
})(
|
||||
'alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu'
|
||||
.split(' ')
|
||||
);
|
||||
2
Task/Knuth-shuffle/JavaScript/knuth-shuffle-5.js
Normal file
2
Task/Knuth-shuffle/JavaScript/knuth-shuffle-5.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
["mu", "theta", "beta", "eta", "delta", "epsilon",
|
||||
"kappa", "alpha", "gamma", "lambda", "zeta", "iota"]
|
||||
31
Task/Knuth-shuffle/Kotlin/knuth-shuffle.kotlin
Normal file
31
Task/Knuth-shuffle/Kotlin/knuth-shuffle.kotlin
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
object Knuth {
|
||||
internal val gen = java.util.Random()
|
||||
}
|
||||
|
||||
fun <T> Array<T>.shuffle(): Array<T> {
|
||||
val a = clone()
|
||||
var n = a.size
|
||||
while (n > 1) {
|
||||
val k = Knuth.gen.nextInt(n--)
|
||||
val t = a[n]
|
||||
a[n] = a[k]
|
||||
a[k] = t
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val str = "abcdefghijklmnopqrstuvwxyz".toCharArray()
|
||||
(1..10).forEach {
|
||||
val s = str.toTypedArray().shuffle().toCharArray()
|
||||
println(s)
|
||||
require(s.toSortedSet() == str.toSortedSet())
|
||||
}
|
||||
|
||||
val ia = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||
(1..10).forEach {
|
||||
val s = ia.shuffle()
|
||||
println(s.distinct())
|
||||
require(s.toSortedSet() == ia.toSet())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
function table.shuffle(t)
|
||||
local n = #t
|
||||
while n > 1 do
|
||||
for n = #t, 1, -1 do
|
||||
local k = math.random(n)
|
||||
t[n], t[k] = t[k], t[n]
|
||||
n = n - 1
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
math.randomseed( os.time() )
|
||||
a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
table.shuffle(a)
|
||||
|
|
|
|||
|
|
@ -1,33 +1,52 @@
|
|||
program Knuth;
|
||||
|
||||
const
|
||||
max = 10;
|
||||
startIdx = -5;
|
||||
max = 11;
|
||||
type
|
||||
list = array [1..max] of integer;
|
||||
tmyData = string[9];
|
||||
tmylist = array [startIdx..startIdx+max-1] of tmyData;
|
||||
|
||||
procedure shuffle(var a: list);
|
||||
procedure InitList(var a: tmylist);
|
||||
var
|
||||
i,k,tmp: integer;
|
||||
i: integer;
|
||||
Begin
|
||||
for i := Low(a) to High(a) do
|
||||
str(i:3,a[i])
|
||||
end;
|
||||
|
||||
procedure shuffleList(var a: tmylist);
|
||||
var
|
||||
i,k : integer;
|
||||
tmp: tmyData;
|
||||
begin
|
||||
randomize;
|
||||
for i := max downto 2 do begin
|
||||
k := random(i) + 1;
|
||||
if (a[i] <> a[k]) then begin
|
||||
tmp := a[i]; a[i] := a[k]; a[k] := tmp
|
||||
end
|
||||
for i := High(a)-low(a) downto 1 do begin
|
||||
k := random(i+1) + low(a);
|
||||
tmp := a[i+low(a)]; a[i+low(a)] := a[k]; a[k] := tmp
|
||||
end
|
||||
end;
|
||||
|
||||
procedure DisplayList(const a: tmylist);
|
||||
var
|
||||
i : integer;
|
||||
Begin
|
||||
for i := Low(a) to High(a) do
|
||||
write(a[i]);
|
||||
writeln
|
||||
end;
|
||||
|
||||
{ Test and display }
|
||||
var
|
||||
a: list;
|
||||
a: tmylist;
|
||||
i: integer;
|
||||
|
||||
begin
|
||||
for i := 1 to max do
|
||||
a[i] := i;
|
||||
shuffle(a);
|
||||
for i := 1 to max do
|
||||
write(a[i], ' ');
|
||||
writeln
|
||||
randomize;
|
||||
InitList(a);
|
||||
DisplayList(a);
|
||||
writeln;
|
||||
For i := 0 to 4 do
|
||||
Begin
|
||||
shuffleList(a);
|
||||
DisplayList(a);
|
||||
end;
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
/*REXX program shuffles a deck of playing cards using the Knuth shuffle.*/
|
||||
rank='A 2 3 4 5 6 7 8 9 10 J Q K' /*pips of the playing cards. */
|
||||
suit='♣♠♦♥' /*suit " " " " */
|
||||
parse arg seed .; if seed\=='' then call random ,,seed /*repeatability?*/
|
||||
say '────────────────── getting a new deck out of the box ···'
|
||||
deck.1='highJoker' /*good decks have a color joker, */
|
||||
deck.2='lowJoker' /*··· and a black & white joker. */
|
||||
cards=2 /*now, two cards are in the deck.*/
|
||||
/*REXX program shuffles a deck of playing cards (with jokers) using the Knuth shuffle.*/
|
||||
rank= 'A 2 3 4 5 6 7 8 9 10 J Q K' /*pips of the various playing cards. */
|
||||
suit= '♣♠♦♥' /*suit " " " " " */
|
||||
parse arg seed . /*obtain optional argument from the CL.*/
|
||||
if datatype(seed,'W') then call random ,,seed /*maybe use for RANDOM repeatability.*/
|
||||
say '══════════════════ getting a new deck out of the box ···'
|
||||
@.1= 'highJoker' /*good decks have a color joker, and a */
|
||||
@.2= 'lowJoker' /* ··· black & white joker. */
|
||||
cards=2 /*now, there're 2 cards are in the deck*/
|
||||
do j =1 for length(suit)
|
||||
do k=1 for words(rank); cards=cards+1
|
||||
deck.cards=substr(suit,j,1)word(rank,k)
|
||||
do k=1 for words(rank); cards=cards + 1
|
||||
@.cards=substr(suit, j, 1)word(rank, k)
|
||||
end /*k*/
|
||||
end /*j*/
|
||||
call showDeck
|
||||
say '────────────────── shuffling' cards "cards ···"
|
||||
do s=cards by -1 to 2; rand=random(1,s)
|
||||
parse value deck.rand deck.s with deck.s deck.rand
|
||||
/* [↑] swap two cards in the deck*/
|
||||
call show
|
||||
say; say '══════════════════ shuffling' cards "cards ···"
|
||||
do s=cards by -1 to 2; ?=random(1,s); parse value @.? @.s with @.s @.?
|
||||
/* [↑] swap two cards in the deck. */
|
||||
end /*s*/
|
||||
call showDeck
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────SHOWDECK subroutine─────────────────*/
|
||||
showDeck: _=; do m=1 for cards; _=_ deck.m; end /*m*/; say _; say; return
|
||||
call show
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
show: _=; do m=1 for cards; _=_ @.m; end /*m*/; say _; return
|
||||
|
|
|
|||
|
|
@ -1,30 +1,27 @@
|
|||
/*REXX program shuffles a deck of playing cards using the Knuth shuffle.*/
|
||||
rank = 'ace deuce trey 4 5 6 7 8 9 10 jack queen king' /*use pip names.*/
|
||||
suit = 'club spade diamond heart' /* " suit " */
|
||||
say '────────────────── getting a new deck out of the box ···'
|
||||
deck.1 = ' color joker' /*good decks have a color joker, */
|
||||
deck.2 = ' b&w joker' /*··· and a black & white joker. */
|
||||
cards=2 /*now, two cards are in the deck.*/
|
||||
/*REXX program shuffles a deck of playing cards (with jokers) using the Knuth shuffle.*/
|
||||
rank = 'ace deuce trey 4 5 6 7 8 9 10 jack queen king' /*use pip names for cards*/
|
||||
suit = 'club spade diamond heart' /* " suit " " " */
|
||||
say '══════════════════ getting a new deck out of the box ···'
|
||||
@.1= ' color joker' /*good decks have a color joker, and a */
|
||||
@.2= ' b&w joker' /* ··· black & white joker. */
|
||||
cards=2 /*now, there're 2 cards are in the deck*/
|
||||
do j =1 for words(suit)
|
||||
do k=1 for words(rank); cards=cards+1 /*bump counter.*/
|
||||
deck.cards=right(word(suit,j),7) word(rank,k) /*assign.*/
|
||||
do k=1 for words(rank); cards=cards+1 /*bump the card counter. */
|
||||
@.cards=right(word(suit,j),7) word(rank,k) /*assign a card name. */
|
||||
end /*k*/
|
||||
end /*j*/
|
||||
|
||||
call showDeck 'ace' /*inserts blank when ACE is found*/
|
||||
say '────────────────── shuffling' cards "cards ···"
|
||||
call show 'ace' /*inserts blank when an ACE is found.*/
|
||||
say; say '══════════════════ shuffling' cards "cards ···"
|
||||
|
||||
do s=cards by -1 to 2; rand=random(1,s) /*get random number for swap*/
|
||||
_=deck.rand; deck.rand=deck.s; deck.s=_ /*swap 2 cards in card deck.*/
|
||||
end /*s*/
|
||||
|
||||
call showDeck
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────SHOWDECK subroutine─────────────────*/
|
||||
showDeck: parse arg break; say /*get sep card, shows blank line*/
|
||||
do m=1 for cards /*traipse through the deck. */
|
||||
if pos(break,deck.m)\==0 then say /*a blank: easier to read cards.*/
|
||||
say 'card' right(m,2) '───►' deck.m /*display a particular card. */
|
||||
end /*m*/
|
||||
say /*show a trailing blank line. */
|
||||
do s=cards by -1 to 2; ?=random(1,s); _=@.?; @.?=@.s; @.s=_
|
||||
end /*s*/ /* [↑] swap two cards in the deck. */
|
||||
call show
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
show: parse arg break; say /*get separator card, show blank line. */
|
||||
do m=1 for cards /* [↓] traipse through the card deck. */
|
||||
if pos(break,@.m)\==0 then say /*show a blank to read cards easier. */
|
||||
say 'card' right(m, 2) '───►' @.m /*display a particular card from deck. */
|
||||
end /*m*/
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue