Выведите перетасованную колоду, используя случайный ввод


9

Ввод, вывод:

Входные данные : равномерно случайная, бесконечно длинная строка «0» и «1», взятая из стандартного ввода. Предполагается, что строка действительно случайная, а не псевдослучайная. Он одинаков в том смысле, что каждый символ в равной степени может быть «0» или «1».

Осторожный! Входные данные бесконечно длинные, поэтому вы не можете хранить все это в памяти, используя функцию, подобную raw_input () в python. Если я не ошибаюсь, golfscript потерпит неудачу с бесконечным вводом, так как он помещает весь ввод в стек перед запуском.

Вывод : стандартно-случайная перетасованная стандартная колода, без джокеров. Он одинаков в том, что все заказы одинаково вероятны.

Каждая карта в выходных данных - это ее ранг, A, 2-9, T, J, Q или K, связанные с ее мастью, c, d, h или s. Например, 10 пикTs

Карты колоды должны быть разделены пробелами.

Вы не можете использовать встроенные случайные библиотеки или функции, потому что они не являются действительно случайными, только псевдослучайными.

Пример ввода

Вы можете использовать следующий скрипт Python для передачи ввода в вашу программу:

import sys, random
try:
    while True:
        sys.stdout.write(str(random.randint(0,1)))
except IOError:
    pass

Если вы сохраните скрипт как rand.py, протестируйте вашу программу с python rand.py | your_program

В Python 3 он работает как положено, но в Python 2.7 я получаю сообщение об ошибке после вывода моей программы, но только после того, как все сделано, поэтому просто игнорируйте сообщение об ошибке.

Пример вывода:

Вот как должна быть напечатана колода, если она перемешана в отсортированном порядке:

Ac 2c 3c 4c 5c 6c 7c 8c 9c Tc Jc Qc Kc Ad 2d 3d 4d 5d 6d 7d 8d 9d Td Jd Qd Kd Ah 2h 3h 4h 5h 6h 7h 8h 9h Th Jh Qh Kh As 2s 3s 4s 5s 6s 7s 8s 9s Ts Js Qs Ks

Подсчет очков:

Это код гольф. Самый короткий код выигрывает.

Пример программы:

Вот решение Python 2.7, а не игра в гольф.

import sys
def next():
    return int(sys.stdin.read(1))==1
def roll(n):
    if n==1:
        return 0
    if n%2==0:
        r=roll(n/2)
        if next():
            r+=n/2
        return r
    else:
        r=n
        while(r==n):
            r=roll(n+1)
        return r
deck = [rank+suit for suit in 'cdhs' for rank in 'A23456789TJQK']
while len(deck)>0:
    print deck.pop(roll(len(deck))),

3
«Если я не ошибаюсь, golfscript потерпит неудачу с бесконечным вводом, так как он помещает весь ввод в стек до запуска». Ну, это один из способов вывести его из строя.
dmckee --- котенок экс-модератора

Я немного смущен, прости меня. Какое отношение имеет вход к фактической перетасовке колоды? Возможно, мне просто нужно немного разъяснений.
jdstankosky

1
Вы не можете использовать псевдослучайные функции в своем коде, поэтому вам нужно использовать входные данные (которые мы предполагаем действительно случайными) для генерации случайности. Например, в python вы можете использовать (sys.stdin.read (1) == '1') для получения случайного логического значения, но вы не можете использовать (random.randint (0,1) == 1), потому что это только псевдослучайное.
картонная

Ответы:


7

Рубин, 89 87 знаков

l=*0..51;l.map{l-=[i=l[gets(6).to_i 2]||redo];$><<'A23456789TJQK'[i/4]+'cdhs'[i%4]+' '}

Редактировать: предыдущая версия

l=*0..51;(l-=[i=l[gets(6).to_i 2]];i&&$><<'A23456789TJQK'[i/4]+'cdhs'[i%4]+' ')while l[0]

3

Python 122

import sys
D=[R+S for S in'cdhs'for R in'A23456789TJQK']
while(D):
    x=int(sys.stdin.read(6),2)
    if x<len(D):print D.pop(x)

Объяснение:

Неиспользуемые карты хранятся в D. Это просто получает следующий допустимый случайный индекс из входного потока и извлекает этот элемент из D.

Если я что-то упустил, не должно быть предвзятости. Сценарий выбросит все недопустимые индексы> len(D), но это не приведет к смещению для меньших чисел, потому что каждое последующее всплывающее окно будет уменьшать индекс каждого элемента, который следует за i.


Таким образом, вы отбрасываете большую часть (бесконечного) случайного ввода? Т.е. вы перестаете перетасовать, когда у вас нет «неиспользованных» карт?
Ли

3

Perl, 80 символов

Вот еще одна реализация, которая не страдает от смещения и на два символа короче:

$/=1x9;$_=A23456789TJQK;s/./$&s$&c$&d$&h/g;%h=map{<>.$_,"$_ "}/../g;say values%h

старая реализация (82 символа):

$/=1x9;$_=A23456789TJQK;s/./$&s$&c$&d$&h/g;say map/..$/&&$&.$",sort map<>.$_,/../g

старое описание реализации:

# set input record separator (how internal readline() delimits lines) to "11111111"
$/ = 1x9; 

# constructs a string representation of all 52 cards: "AsAc(...)KdKh"
$_ = A23456789TJQK; s/./$&s$&c$&d$&h/g;

# for each pair of characters (each card) in the string $_
foreach $card (/../g)
{
    # read from STDIN until $/ is found (this may NEVER occur!), which
    # results in a random string of 1s and 0s
    $weight = <>; 

    # append the card identifier onto the random string
    $card = $weight . $card;

    # add this new card identifier to a new list
    push @cards, $card;
}

# sort the cards with their random string prefix
sort @cards;

# for each card in the "randomly sorted" list
foreach $card (@cards)
{
    # capture the final two characters from the card (the rank and suit), 
    # and append a space onto them
    $card =~ /..$/;  
    $card = $card . $";

    print $card;
}

Просто любопытно: кто-нибудь может показать, что этот подход производит каждую колоду карт с одинаковой вероятностью?
Говард

2
Если я читаю это право (IANAPH), он назначает случайные «веса» каждой карточке, а затем сортирует по весу. Когда двум карточкам назначен одинаковый вес, они будут упорядочены sort, что приведет к смещению в алфавитном порядке.
Boothby

ты прав, @boothby. сортировка оставляет это решение с уклоном в случае, если несколько карт имеют одинаковый «вес». также нельзя гарантировать, что это решение когда-либо даст результат. Я добавлю описание того, как это работает, чтобы кто-то умнее меня мог его проанализировать
ardnew

Прекрасно, если некоторые входные данные приводят к тому, что программа никогда не завершается, если вероятность того, что программа завершается, приближается к 1, когда время приближается к бесконечности. Программа-пример никогда не заканчивается на входе всех единиц. Я почти уверен, что на самом деле невозможно получить равномерную случайность, зная, что ваша программа завершается после определенного количества прочитанных битов.
картонная

1
Как вы можете выбрать равномерно случайное число от 1 до 3 с конечным числом бит? Вам нужно будет сделать это ближе к концу шаффла Фишера-Йейтса, и факториал (52) делится на 3, поэтому он разделяет ту же проблему.
картонная

3

С, 197 178 161 символ

РЕДАКТИРОВАТЬ : Использование новой случайной функции, которая намного короче - читает 4-значное целое sи использует s%64. Каждое 6-значное десятичное число, состоящее только из 0 и 1, %64приводит к уникальному результату, поэтому случайность хорошая.
Этот подход потребляет гораздо больше случайных битов, но значительно короче.

B[52],t,s,i=104;
r(){scanf("%6d",&s);s%=64;s>i&&r();}
main(){
    for(;i--;)B[i%52]=i<52
        ?r(),t=B[s],B[s]=B[i],printf("%c%c\n","23456789ATJQK"[t/4],"cdhs"[t%4]),t
        :i-52;
}

Основная логика проста - инициализировать массив из 52 дюймов с 0..51, перемешать (случайным образом заменить элемент x другим из диапазона 0..x), отформатировать печать (n / 4 = rank, n% 4 = suit) ,
Один цикл, который выполняется 104 раза, выполняет инициализацию (первые 52 запуска), перемешивание и печать (последние 52 запуска).
Случайное число генерируется путем вытягивания nслучайных битов до тех пор, пока не 1<<nбудет достигнут хотя бы желаемый максимум. Если результат больше максимального - повторите попытку.


Это сложнее, s>7?"ATJQK"[s-8]:s+50чем просто "A23456789TJQK"[s]. Во-вторых, вы можете использовать t/4и t%4вместо t%13и t/13.
Говард

Не нужно по-прежнему помещать tобратно в массив при выводе
l4m2

3

оболочка unix ~ 350

Это не коротко и не красиво, и не эффективно, однако мне было интересно, как трудно будет это сделать с помощью стандартных утилит оболочки Unix.

Этот ответ разбивает бесконечную двоичную строку на 6-битную длину и выбирает только те, которые находятся в правильном диапазоне (1-52), здесь бесконечная двоичная строка моделируется с помощью urandom и xxd:

</dev/urandom xxd -b | cut -d' ' -f2-7 | tr -d ' \n'

Измельчение и отбор производится с помощью fold, sed и bc:

random_source | {echo ibase=2; cat | fold -w6 | sed -r 's/^/if(/; s/([^\(]+)$/\1 <= 110100 \&\& \1 > 0) \1/'}

Это производит строки, такие как:

if(101010 <= 110100 && 101010 > 0) 101010

Который может быть направлен в до н.

Из этого потока чисел последовательность колоды выбрана следующим образом (я использую zsh, но большинство современных оболочек должны быть адаптированы к этому):

deck=({1..52})
seq_of_numbers | while read n; do 
  if [[ -n $deck[n] ]]; then 
    echo $n; deck[n]=""
    [[ $deck[*] =~ "^ *$" ]] && break
  fi
done

Рандомизированная числовая последовательность теперь должна быть заменена на имена карт. Последовательность имен карт легко генерируется с помощью параллельной GNU:

parallel echo '{2}{1}' ::: c d s h ::: A {2..9} T J Q K

Объединение результатов двух последних команд с вставкой и сортировкой по числам:

paste random_deck card_names | sort -n | cut -f2 | tr '\n' ' '

Все это как один чудовищный однострочник (тестируется только в zsh):

paste \
  <(deck=({1..52}); \
    </dev/urandom xxd -b | cut -d' ' -f2-7 | tr -d ' \n' |
      {echo ibase=2; fold -w6 | sed -r 's/^/if(/; s/([^\(]+)$/\1 <= 110100 \&\& \1 > 0) \1/'} | 
      bc | 
      while read n; do 
        if [[ -n $deck[n] ]]; then 
          echo $n; deck[n]=""
          [[ -z ${${deck[*]}%% *} ]] && break
        fi
      done) \
  <(parallel echo '{2}{1}' ::: c d s h ::: A {2..9} T J Q K) | 
sort -n | cut -f2 | tr '\n' ' '

Edit - добавлена ​​версия bash

Вот версия, которая работает в Bash. Я удалил в оболочке { }и индексы массива на основе нуля. Пустота массива проверяется с помощью расширения параметров, немного более эффективно и также используется в примере выше.

paste \
  <(deck=($(seq 52)); \
    </dev/urandom xxd -b | cut -d' ' -f2-7 | tr -d ' \n' | 
      (echo ibase=2; fold -w6 | sed -r 's/^/if(/; s/([^\(]+)$/\1 <= 110100 \&\& \1 > 0) \1/') | 
        bc | 
        while read n; do 
          if [[ -n ${deck[n-1]} ]]; then 
            echo $n
            deck[n-1]=""
            [[ -z ${deck[*]%% *} ]] && break
          fi
        done \
  ) \
  <(parallel echo '{2}{1}' ::: c d s h ::: A {2..9} T J Q K) | 
sort -n | cut -f2 | tr '\n' ' '; echo

2

K & R c - 275

  • v3 Индекс в строковые литералы напрямую
  • v2 предложение от luser droog в комментариях использовать строки и заменить оставшиеся charлитералы intлитералами

Golfed:

#define F for(i=52;--i;)
#define P putchar 
M=1<<9-1,i,j,k,t,v,s,a[52];r(){t=0,j=9;while(--j)t=t<<1|(getchar()==49);
return t;}main(){F a[i]=i;F{k=i+1;do{j=r();}while(j>M/k*k-1);j%=i;t=a[i];
a[i]=a[j];a[j]=t;}F{s=a[i]&3;v=a[i]>>2;P(v>7?"TJQKA"[v-8]:v+50);
P("cdhs"[s]);P(32);}}

Здесь довольно грубая сила. Я просто прочитал девять битов из входных данных, чтобы сформировать минимальный выходной сигнал ГСЧ, и делаю обычное уменьшение модуля перерисовки, если не используются значения в конце, чтобы получить равномерный выход для питания тасования выбора.

Эта версия без игры в гольф отличается тем, что она использует входные данные, /dev/urandomа не описанный формат ввода.

#include <stdio.h>
M=1<<8-1, /* RANDMAX */
  i, j, k, /* counters */
  t, /* temporary for swapping, and accumulating */
  a[52]; /* the deck */
r(){ /* limited, low precision rand() that depends on a random stream
    of '0' and '1' from stdin */
  t=0,j=9;
  while(--j)t=t<<1|(getchar()&1);
  return t;
}
main(){
  for(i=52;--i;)a[i]=i;  /* initialize the deck */
  for(i=52;--i;){
    /*  printf("shuffling %d...\n",i); */
    k=i+1;
    do { /* draw *unifromly* with a a-unifrom generator */
      j=r(); 
      /* printf("\t j=0x%o\n",j); */
    }while(j>M/k*k-1); /* discard values we can't mod into evently */
    j%=i;
    t=a[i];a[i]=a[j];a[j]=t; /* swap */
  }
  for(i=52;--i;){ /* output the deck */
    j=a[i]&3;
    k=a[i]>>2;
    putchar(k>7?"TJQKA"[k-8]:k+'2');
    putchar("cdhs"[j]);
    putchar(' ');
  }
}

+1 Мне нужно многому научиться. Кстати, а почему бы "TJQKA"и нет "cdhs"?
Люсер Дрог

Ой. Правильно. ints. Я понял Может быть, стоит того, чтобы сохранить все знаки препинания. Мог бы даже факторchargetcharputchar
принять

1
Замены макросов должны получить много, потому что они должны начинаться #define N и заканчиваться символом новой строки, который считается как символ, и это 11 плюс бит, который вы заменяете. Конечно, есть еще несколько символов для замены некоторых или всех литералов символов на литералы int, но здесь уже поздно ... возможно, я сделаю это в другой раз.
dmckee --- котенок экс-модератора

@luserdroog Прояснитель сейчас. Конечно, строки лучше - хотя вы должны указать тип - потому что символы - это просто короткие целые числа. Кроме того, я могу комбинировать их, и замены ASCII получают кучу ударов за один раз.
dmckee --- котенок экс-модератора

0

PHP, 158 символов

Добавлены новые строки, чтобы блок кода не набирал полосы прокрутки, их можно безопасно удалить.

for($i=52,$x='shdcKQJT98765432A';$i--;$c[]=$x[4+$i%13].$x[$i/13]);
while(ord($i=fgetc(STDIN)))$c[$i]^=$c[$a]^=$c[$i]^=$c[$a=2+($a+++$i)%50];
die(join(' ',$c));

Прежде чем мне скажут добавить a <?php, пусть будет известно, что вы можете легко вызывать PHP без этого тега, используя:cat golf.php | php -a

Де-гольф и прокомментировал:

// Abuse of the for construct to save a bit of space, and to make things more obscure looking in general.
for (
    // Card suit and number are reversed because we're using a decrementor to count
    // down from 52, instead of up to 52
    $i = 52,
    $x = 'shdcKQJT98765432A';
    // Condition AND per-loop decrement
    $i--;
    // Add a new element to the array comprising of $i mod 13 + 4 (to skip suit ids)
    // followed by simply $i divided by 13 to pick a suit id.
    $c[] =
        $x[4 + $i % 13] .
        $x[$i / 13]
);

while(

    // Assignment inside the condition, a single character from input.
    ord($i = fgetc(STDIN))
)
    // In-place swap. Shorter than using a single letter temporary variable.
    // This is the pseudo-random shuffle.
    $c[$i] ^=
    $c[$a] ^=
    $c[$i] ^=
    $c[
        // We use the input (0 or 1) to identify one of two swap locations at the
        // start of the array. The input is also added to an accumulator (to make
        // the increments "random") that represents a swap destination.
        $a = 2 + ($a++ + $i) % 50
    ];

// Dramatic way of doing "echo" in the same space.
die(
    join(' ', $c)
);

Есть две ожидаемые ошибки, которые не влияют на вывод программы.

Во-первых, потому что $aне инициализируется, но NULL преобразуется в 0, и программа продолжается.

Вторая причина в том, что поток символов, похоже, откуда-то получает новую строку, даже если он не предоставлен (добрый старый PHP), а это неопределенный индекс в массиве. Это последний символ ввода и не влияет на вывод.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.