Então você definitivamente está errado quando faz:
tr -dc ... </dev/urandom
Você não precisa -d elete nada. Se o seu objetivo é aleatoriedade - então você deve usar tudo o que conseguir.
Por exemplo:
tr 'deck()( HOME=/dev/null; ${deck:+"echo"}
tr=$(printf '[%s*19]' 1 2 3 4 5 6 7 8 9 a b c d)
tr 'time (deck|wc -l)
-7' "[J*9]$tr" |
dd cbs=1 obs=2 conv=unblock |
paste -d'W\nX\nY\nZ' - ~ - ~ - ~ - ~ |
sed ' /^J/d;1!G;/^\(..\).*/d
h;s/\n/&/51;tq' -e'd;:q' -eq
) <"${1:-/dev/urandom}"
-7' '[H*64][D*64][C*64][S*]' </dev/urandom |...
... que sempre retornaria um [HDCS] w / out excluindo qualquer entrada e retornaria em um espectro de bytes de entrada aleatórios.
Eu escrevi uma função que irá preencher um baralho embaralhado:
52
( deck | wc -l; ) \
0.03s user 0.04s system 224% cpu 0.028 total
Fazendo ...
draw() if [ -n "${1##*[!0-9]*}" ] || return 2
then case $((${#deck}>($1*3)))$deck in
(?*[!0-9W-Za-d[:space:]]*)
return 2;;
(0*) deck=$deck$(deck)
draw "$1";;
(1*) eval " hand='$(echo "$deck" |
sed "$1 N;s/\n/' deck='/")'"
esac; fi
... imprime ...
show() case $1 in
(*[!0-9W-Za-d[:space:]]*|'') return 2;;
(*) ( eval " $(printf "T='\t' E=3 nl='\n'")"
str(){ m=$1 l=\$2 r=\$i$3 d=......
set 9 8 7 6 5 4 3 2 1
for i in d c b a "$@"
do [ "$i" = d ] && M=ROYAL || M=STRAIGHT M=${M#"$m"}
eval printf "\"\ts/.*$l$d$r.*/"'$M${M:+ }$m:/;t$a.1\n"'
[ "$1" = 1 ] && unset a r l d i m M && break
shift; done; }
knd(){ c=$1 m="$1 OF A KIND" IFS=$nl
shift; s="$*"; set -f .'\1'
until [ "$#" -gt "$((c-1))" ]
do set "$@" "$@"
done; shift "$(($#-(c-1)))"
printf %b "\t/\([a-d0-9]\)$@/{\n"
for s in $s; do eval 'printf "\t\t%s\n" "'"$s\""; done
printf "\tt$a.1\n\t}\n"; unset l c a s IFS; }
br(){ case $a.$1 in
(.*|*[!0-9]*.) return 2;;
(*.-t) printf "\n:$a.0\n%s\n" \
"$a!b${n:-$((a+1)).0}";;
(*.-b) printf ":$a.1\n";;esac;shift
for s do eval 'printf "\t%s\n" "'"$s\"";done
unset n IFS a s; }
for k in k1.2,1.2 k1.1,1.1 uk1.1,1.1
do echo "$1" | sort -"$k"; echo
done| sed -ne:n -e'$!N;s/\n\(.\)//;tn
x;/./!g;x;$G;s/\n$//p' |
sed -ne"$( a=1 br -t
a=1 str FLUSH '\(.\)' '\'
a=1 br -b 's/.*\([W-Z]\).......\1.*/FLUSH:/' /:/h /^\[RS]/be n
a=2 br -t
a=2 knd 4 s/.\*/\$m:/
a=2 knd 3 s/// '/\(.\)[W-Z]/!s/.*[W-Z]/$m:/' s//FULLHOUSE:/
a=2 knd 2 s///2 tP 's/.*/$m:/' :P 's/.*[W-Z]/2 PAIR:/'
a=2 br -b /^\[F4]/h x //h //be x /:/h n
n=e a=3 br -t
a=3 str STRAIGHT .
a=3 br -b /:/h x h)
:e" -e'5!n;5!be' -e'y/123456789abcd/234567891JQKA/
s/\(.\)\([W-Z]\)/ '"$E[0;3;47m $E[m /g"'
s/W\([^ ]* \)/1♦ /g;s/X\([^ ]* \)/1♥ /g
s/Y\([^ ]* \)/0♠ /g;s/Z\([^ ]* \)/0♣ /g
s/ 1/10/g;x;s/.*[^:]//;/.\{8\}/!s/$/'"$T/;G;s/\n/$T/
s/\([^m]*m\)\{26\} /&\$nl\$nl$T$T/g;s/[[:space:]]*$//p"
) esac
deck() usa como padrão os dados aleatórios do linux /dev/urandom PRNG, mas se for chamado com um argumento, interpretará isso como um nome de arquivo para uma fonte alternativa de entrada aleatória.
E todas as cartas devolvidas - (uma por linha) - são únicas. Não se incomoda tentar randomizar os trajes e atribuí-los na ordem round-robin. Ele não precisa se preocupar: a ordem dos valores das cartas já é aleatória, e as cartas terão que ser removidas para uniques em uma ordem aleatória de qualquer maneira, e então o resultado da poda operação é ternos aleatórios.
sed realmente lida com isso. O que sed faz é:
-
%código%
- limpar todos os Jokers (valores de byte
/^J/d )
-
%código%
- Em todas as linhas, mas a primeira é
0-$(((256%13)-1)) uma cópia do 1!G old space anexado ao espaço padrão.
-
%código%
- Se houver outro cartão em sua pilha atual que corresponda ao cartão que acabou de comprar,
G elimina o espaço padrão e não salva nada ...
- ... caso contrário, se a linha atual for única, copiará a pilha atual para
h old space.
- A primeira linha é sempre
/^\(.*\)\n.*/d;h eld.
-
%código%
- Se houver 51
d ewlines no espaço padrão nesse momento, h h uits entrada e imprime o deck para stdout ...
- ... senão
/\(.*\n\)\{51\}/q;d elimina o espaço padrão e não imprime nada.
Agora, se você quiser \n ...
1 2 3 4 5 6 7 8 9 a b c d
2 3 4 5 6 7 8 9 10 J Q K A
... que é uma função que preencheria automaticamente as variáveis atuais do shell sed e q conforme necessário. Ele puxa da parte superior de d o número de cartões solicitados em draw e coloca esses cartões em $hand . $deck é aparado a partir do topo de cada vez. Se $deck for chamado e $1 não for suficientemente grande o suficiente para preencher $hand conforme solicitado, então $deck será reabastecido com um novo% embaralhado draw() .
E por último:
W X Y Z
♦ ♥ ♠ ♣
Em todos os $deck e $hand , os cartões são armazenados em ordem de classificação como esta:
sort -k1.1,1.1
E os fatos também ...
ROYAL FLUSH
STRAIGHT FLUSH
4 OF A KIND
FULLHOUSE
FLUSH
STRAIGHT
3 OF A KIND
2 PAIR
2 OF A KIND
Isso facilita - cada cartão tem 2 bytes e eles sempre serão classificados de maneira apropriada. Os cartões em $deck e $deck são todos deck() ewline delimited - always. Então, em draw() , a parte mais difícil é feita simplesmente como ...
y/123456789abcd/234567891JQKA/
... onde ordenamos a mão no primeiro byte de cada linha. O resto é apenas comparar - que $hand faz ... um lote de. Ele lida com 2,3,4 de um tipo, fullhouse, 2 pares, royal straight, straight, royal flush e straight flush. Ele preferirá informar sobre eles na seguinte ordem, independentemente de quantos cards forem encontrados em seu primeiro argumento:
tr -dc ... </dev/urandom
Observe que a função $deck não está necessariamente vinculada a nenhum dos outros dois - ela pode ser chamada com um argumento gerado de qualquer maneira que coincida com o esquema de codificação mencionado acima e produzirá a saída desejada. Cada uma das funções pode se sustentar de maneira modular quando / se necessário.
Note também que não há limite de 5 cartas para qualquer uma das três funções - elas devem lidar com mãos de qualquer tamanho. E todos eles são projetados para trabalhar com \n persistente (com verificação de erros) - e, portanto, podem ser usados com algum nível de persistência.
É no final de show() que a codificação é decodificada . Todos os valores codificados são convertidos em uma única ação:
tr 'deck()( HOME=/dev/null; ${deck:+"echo"}
tr=$(printf '[%s*19]' 1 2 3 4 5 6 7 8 9 a b c d)
tr 'time (deck|wc -l)
-7' "[J*9]$tr" |
dd cbs=1 obs=2 conv=unblock |
paste -d'W\nX\nY\nZ' - ~ - ~ - ~ - ~ |
sed ' /^J/d;1!G;/^\(..\).*/d
h;s/\n/&/51;tq' -e'd;:q' -eq
) <"${1:-/dev/urandom}"
-7' '[H*64][D*64][C*64][S*]' </dev/urandom |...
Acontece imediatamente em uma única tradução de sed sem qualquer perigo de editar o valor por engano duas vezes.
Sua saída é semelhante a: