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: