2014-02-15 2 views
0

В Прологе, как я случайно выбираю 2 значения из набора из 52 карт? то есть Player1 (X, Y), X будет любой картой из 52 и Y другой, и они должны быть разными. Игрок2 получит такое же лечение, и его карты должны отличаться от тех, которые уже выбраны. Благодарю.Выберите 2 случайных значения из набора констант

ответ

1

В SWI-Prolog Я хотел бы сделать pick_card/3

pick_card(Cards, Card, Rest) :- 
    length(Cards, N), random_between(1, N, R), nth1(R, Cards, Card, Rest). 

и применять его в 2 раза

pick_two_cards(Cards, C1,C2, Rest) :- 
    pick_card(Cards, C1, R1), 
    pick_card(R1, C2, Rest). 
+0

Wow Интересный enouth , Единственная часть, которая мне непонятна, - это предикат nth1. Если я не ошибаюсь, он связывает карту с найденным случайным числом. Если да, то почему там «Отдых»? – vincent

+0

Просто держать pick_card * повторно использовать *. Добавление карт ввода/вывода/Rest вы можете повторно использовать в более широком контексте. В противном случае просто «отбросить» нежелательный выходной аргумент - так называемая проекция ... – CapelliC

1

В основном, задача состоит в том, чтобы попробовать 4 различных элементов из набора [1 .. 52].

В Python, например, есть стандартная функция для этого, и код будет

random.sample(range(1, 52 + 1), 4) 

Я смотрел, как Python реализует random.sample(range(1..N + 1), K) - это в основном только K шагов генерации случайных чисел [1 ..N], и на каждом шаге просто пытайтесь генерировать случайные числа, а в настоящее время сгенерированный номер уже выбран на предыдущем шаге. Это выглядит неэффективно, но, вероятно, необходимо архивировать однородность распределения.

Давайте создадим аналогичный (но упрощенный) предикатдля Prolog.

sample(N, K, Sample) :- 
    sample(N, K, [], Sample). 

sample(_, 0, _, []). 
sample(N, K, Selected, [X | Rest]) :- 
    K > 0, 
    new_random_index(N, Selected, X), 
    NewSelected = [X | Selected], 
    NewK is K - 1, 
    sample(N, NewK, NewSelected, Rest). 

new_random_index(N, Selected, X) :- 
    ( 
     % Can be implementation-specific. Works in B-Prolog and ECLiPSe CLP. 
     X is (random mod N) + 1, 
     \+ membchk(X, Selected) 
    ; 
     new_random_index(N, Selected, X) 
    ). 

Пар испытательных пробегов:

| ?- sample(52, 4, Sample). 
sample(52, 4, Sample). 
Sample = [40,23,38,44] ? 
yes 
| ?- sample(52, 4, Sample). 
sample(52, 4, Sample). 
Sample = [2,28,39,17] ? 
yes 

Эффективность программы может быть значительно улучшена, если membchk тест изменен на предикат, который проверка членства с помощью наборов, а не списков. Но это очень специфично для реализации.

+0

Сергей это слишком сложно для меня. Надеюсь, в следующем будущем я это понимаю. – vincent

1

Если вы хотите нарисовать случайные карточки повторно, возможно, лучше всего перетасовать весь список за один раз, а затем просто выбрать карты спереди. Некоторые Prologs (например ECLiPSe) есть библиотека предикат для этого, так что вы можете просто позвонить

lists:shuffle(Cards, [Card1,Card2|Rest]). 

Если вы хотите написать перетасовки себя, вот ловкий трюк:

shuffle(Xs, Rs) :- 
    add_random_keys(Xs, KXs), % add random key to each list element 
    keysort(KXs, KRs),   % sort by keys, perturbing original order 
    strip_keys(KRs, Rs).  % remove the keys again 

add_random_keys([], []). 
add_random_keys([X|Xs], [K-X|KXs]) :- 
    random(K), 
    add_random_keys(Xs, KXs). 

strip_keys([], []). 
strip_keys([_K-X|KXs], [X|Xs]) :- 
    strip_keys(KXs, Xs). 
Смежные вопросы