Чи є ці кістки неранситивними?


31

Нетранзитивні кістки - це приємні маленькі іграшки, які протистоять нашій інтуїції в теорії ймовірностей. Для цього нам знадобиться кілька визначень:

Розглянемо дві кістки А і В, які кидаються одночасно. Ми говоримо , що б'ється В , якщо ймовірність А показує більшу кількість , ніж B строго більше , ніж ймовірність B показує більшу кількість , ніж A .

Тепер розглянемо набір з трьох кісток, з етикетками , B , C . Такий набір кісток називається неперехідним, якщо

  • або A б'є B , B б'є C і C б'є A
  • або C б'є B , B б'є і б'ється C .

Як один з моїх улюблених прикладів, розгляньте кубики Grime , які мають такі сторони:

A: 3 3 3 3 3 6
B: 2 2 2 5 5 5
C: 1 4 4 4 4 4

Цікаво, що середня величина кожного штампу - 3,5, як і звичайна.

Можна показати, що:

  • Б'є B з ймовірністю 7/12.
  • B б'є C з вірогідністю 7/12.
  • C б'є А з вірогідністю 25/36.

Зараз ці кубики ще більш дивні. Якщо ми прокручуємо кожну штамп двічі і складаємо результати, порядок перемоги яких перевертається:

  • B б'є А з вірогідністю 85/144.
  • C б'є B з вірогідністю 85/144.
  • Б'є C з імовірністю 671/1296.

Назвемо набір кісток з цією властивістю Grime-нетрадиційний .

З іншого боку, якщо кубики зберігають свій початковий цикл при використанні двох кидків, ми називаємо їх сильно нетрасивними . (Якщо циклу немає для двох кидків, ми просто називаємо їх нетрасивними .)

Змагання

Беручи під увагу три шестигранного кубика, визначають , які із зазначених вище властивостей цього набору має, і вихід одного з наступних рядків: none, nontransitive, Grime-nontransitive, strongly nontransitive.

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

Ви можете припустити, що всі сторони є невід’ємними цілими числами. Ви не можете припустити, що сторони або кістки в якомусь конкретному порядку. Ви можете взяти вхід у будь-якому зручному списку чи рядковому форматі.

Це кодовий гольф, тому найкоротша відповідь (у байтах) виграє.

Випробування

none
1 2 3 4 5 6, 6 5 4 3 2 1, 1 3 5 2 4 6
1 1 1 6 6 6, 4 4 4 5 5 5, 5 5 5 5 5 5
1 1 2 5 6 6, 2 2 3 4 4 6, 2 3 3 4 4 5
0 1 2 3 4 5, 1 1 2 3 3 5, 1 2 2 2 3 5
3 13 5 7 13 7, 5 7 11 5 7 13, 5 9 13 5 7 9

nontransitive
1 2 2 4 6 6, 1 2 3 5 5 5, 2 3 4 4 4 4
1 4 4 4 4 4, 2 2 2 4 5 6, 2 3 3 3 5 5
1 2 1 6 5 6, 3 1 3 6 2 6, 2 4 2 4 4 5
3 4 6 6 7 7, 4 4 4 7 7 7, 5 5 5 5 6 7
2 5 11 11 14 14, 5 5 5 14 14 14, 8 8 8 8 8 17

Grime-nontransitive
3 3 3 3 3 6, 2 2 2 5 5 5, 1 4 4 4 4 4
1 1 4 5 5 5, 2 2 2 3 6 6, 3 3 3 4 4 4
2 1 4 6 4 4, 2 4 5 2 3 5, 3 3 6 3 3 3
11 11 13 15 15 16, 12 12 12 13 16 16, 13 13 13 14 14 14
4 4 7 16 19 19, 4 7 13 13 13 19, 4 10 10 10 16 19

strongly nontransitive
2 2 2 5 5 5, 2 3 3 3 5 5, 1 1 4 5 5 5
2 2 2 3 6 6, 2 2 2 5 5 5, 2 2 4 4 4 5
1 5 1 3 6 5, 6 6 4 2 2 1, 5 3 4 3 4 2
0 0 2 4 4 5, 0 1 1 3 5 5, 1 1 2 3 4 4
1 1 9 17 17 21, 1 5 5 13 21 21, 5 5 13 13 13 17

Якщо ви хочете ще більш ретельно перевірити свій код, Пітер Тейлор був досить люб'язним, щоб написати контрольну реалізацію, яка класифікувала всі ~ 5000 наборів кісток зі сторонами від 1 до 6 та середньою величиною 3,5. Посилання на пастебін


Я зовсім забув про неперехідні кістки. Дякую :)
npst

Чи правильний перший нетрадиційний приклад? 1 2 2 4 6 6, 1 2 3 5 5 5, 2 3 4 4 4 4Я отримую A <B 17/36, B> C 19/36, C <A 16/36.
Тобія

@Tobia Ви забуваєте, що нічия можливі. Вам також потрібно розібратися, як часто кожна кістка програє проти інших, і перевірити, чи це менше, ніж ймовірність виграшу: Так, А перемагає проти B із 17/36, але A програє проти B лише 16/36, тому A б'є B Так само, як ви сказали, C виграє проти А з 16/36, але C програє проти A лише 14/36, тому C перемагає А.
Мартін Ендер

Відповіді:


5

Діалог APL, 107 100 байт

{({+/×+/¨,¨×⍵∘.-¨1⌽⍵}{3≠|a←⍺⍺⍵:1⋄a=b←⍺⍺∘.+⍨¨⍵:2⋄3+a=-b}⍵)⊃(⊂'none'),'strongly '⍬'Grime-',¨⊂'nontransitive'}

{T←{+/×+/¨∊¨×⍵∘.-¨1⌽⍵}⋄3≠|S←T⍵:'none'⋄N←'nontransitive'⋄S=D←T∘.+⍨¨⍵:'strongly ',N⋄S=-D:'Grime-',N⋄N}

(Дякую @Tobia за це простіше, коротше, краще рішення)

Основи:

  • доручення

  • роздільник операторів

  • {} лямбда-форма

  • ⍺⍵ лівий і правий аргумент

  • A:Bохорона ("якщо Aпотім повернутися B")

T- це функція, яка повертає 3, якщо A б'є B, B б'є C, а C б'є A; -3, якщо саме навпаки; і щось середнє між іншим. Детально:

  • 1⌽⍵є однооборотним . Якщо ABC, обертання - BCA.

  • ∘.-обчислює таблицю віднімання між двома векторами (це 1 2...10 ∘.× 1 2...10була б таблиця множення, яку ми знаємо зі школи). Ми застосовуємо це між кожним ( ¨) елементом та відповідним пунктом у 1⌽⍵.

  • × синума всіх чисел у таблицях віднімання

  • ∊¨ вирівняти кожен стіл

  • +/¨і підсумуйте його. Зараз у нас є три числа, що представляють собою баланси: кількість виграшів мінус програшні випадки для кожного з A проти B, B проти C, C проти A.

  • × синум тих

  • +/ сума

Потім обробляйте справи по черзі:

  • 3≠|S←T⍵:'none'якщо T⍵абсолютне значення не 3, поверніть «немає»

  • N←'nontransitive' нам це слово знадобиться дуже багато

  • S=D←T∘.+⍨¨⍵:'strongly ',Nобчислити Tпари кісток ( ∘.+⍨¨⍵← → ⍵((∘.+)¨)⍵) і повернути «сильно ...», якщо однакові відносини серед ABC все ще зберігаються

  • S=-D:'Grime-',N ⍝ «Грим», якщо стосунки йдуть у протилежні сторони

  • N якщо все інше не вдається, просто "нетрасивний"


1
Ти побив мене до цього! Я працював над цією проблемою 3 дні тому, але тоді я перестав просто писати свою відповідь. У будь-якому випадку вона занадто схожа на вашу, тому я просто опублікую її тут. Це трохи коротше на 100 символів:{T←{+/×+/¨∊¨×⍵∘.-¨1⌽⍵}⋄3≠|S←T⍵:'none'⋄N←'nontransitive'⋄S=D←T∘.+⍨¨⍵:'strongly ',N⋄S=-D:'Grime-',N⋄N}
Тобіа

@ MartinBüttner: Правильний термін у заголовку - "символи", оскільки кількість байтів буде змінюватися залежно від діаграми, що використовується для кодування символів APL. Традиційно вони були просто закодовані у верхній половині 8-бітових байтів після ASCII. Сьогодні ми використовуємо UTF-8, але старі графіки все ще корисні ... головним чином, щоб зменшити кількість байтів до кількості символів при гольфі!
Тобія

@Tobia У коді гольф коротший козир раніше, тому ви виграєте! Я не дуже знайомий з етикетом у гольфі, але я думаю, що ви повинні опублікувати його як окрему відповідь, оскільки він суттєво відрізняється, і ви прийшли до нього самостійно.
ngn

@Tobia Я також вважаю за краще рахувати символи, але якщо мається на увазі класичне кодування, то байти = символи, тож, можливо, це не дуже важливо, як ми їх називаємо ...
ngn

@Tobia Ну, безумовно, марно подавати кількість символів у виклику, який набирає байти. Однак ніхто ніколи не сказав, що ми забиваємо байти UTF-8. Насправді тег wiki прямо говорить про те, що інше існуюче кодування може використовуватися для символів поза діапазоном ASCII. А APL має власну кодову сторінку, тому весь набір символів вкладається в байт. Політика щодо PPCG полягає у використанні цієї кодової сторінки для підрахунку APL - навряд чи справедливо покарати APL за те, що вона старша за ASCII.
Мартін Ендер

13

Пітон 2, 269

Ось приємний невеликий вираз, який оцінює функцію. Він приймає три списки цілих чисел. Проходить усі тестові справи.

lambda A,B,C,w=lambda A,B:cmp(sum(cmp(a,b)for a in A for b in B),0),x=lambda A,B:cmp(sum(cmp(a+c,b+d)for a in A for b in B for c in A for d in B),0): (w(A,B)==w(B,C)==w(C,A)!=0)*((x(A,B)==x(B,C)==x(C,A))*["","strongly ","Grime-"][x(A,B)*w(A,B)]+"nontransitive")or"none"

2

J - 311 257 байт

Оновлення (13 січня 2015 р.):

g=:4 :'(+/,x>/y)>+/,y>/x'
h=:4 :'(,+/~x)g,+/~y'
f=: 3 :0
'a b c'=:y
if. (b g a)*(c g b)*a g c do.
a=.2{y
c=.0{y
end.
'none'([`]@.((a g b)*(b g c)*c g a))((''([`]@.((b h a)*(c h b)*a h c))'Grime-')([`]@.((a h b)*(b h c)*c h a))'strongly '),'nontransitive'
)

Пояснення: Використовуючи Gerunds, спростіть if.s до@. s.

Старіша версія:

Спершу спробуйте як кодування в J, так і гольф.

g=:4 :'(+/,x>/y)>+/,y>/x'
h=:4 :'(,+/~x)g,+/~y'
f=: 3 :0
'a b c'=:y
if. (b g a)*(c g b)*a g c do.
a=.2{y
c=.0{y
end.
if. (a g b)*(b g c)*c g a do.
if. (a h b)*(b h c)*c h a do.
'strongly nontransitive'
elseif. (b h a)*(c h b)*a h c do.
'Grime-nontransitive'
elseif. do.
'nontransitive'
end.
else.
'none'
end.
)

Запустіть його, використовуючи синтаксис, подібний до наступного (додаткові пробіли для наочності):

f 3 6 $          1 1 9 17 17 21, 1 5 5 13 21 21, 5 5 13 13 13 17

Пояснення:

gвизначається як diad, що приймає два масиви, який повідомляє, якщо перша кістка б'є другу
hкістку, визначається як diad, що приймає два масиви, яка повідомляє, якщо кидати двічі та підсумовувати, чи робить биття перших кісток другий
f- це монада, яка бере таблицю і повертає рядок з правильна відповідь

Редагувати: виправити помилку в нетрадиційному стані Grime (замінивши ,на *)


Я хотів би будь-які пропозиції щодо вдосконалення. :)
Jay Bosamiya

@ MartinBüttner, я спочатку намагався це зробити, але не знав, як об'єднатись через декілька рядків (або речень, як це відомо в J), не збільшуючи довжину коду набагато більше ... знання про "дію" привело мене до створення багато речень на одне, що закінчується і скороченням коду ...
Jay Bosamiya

1

Піт 129 133

Lmsd^b2Msmsm>bkGHDPNK-ghNeNgeNhNR?^tZ<KZKZAGHmsdCm,PkP,yhkyekm,@Qb@QhbUQ?"none"|!G%G3s[*!+GH"Grime-"*qGH"strongly ""nontransitive

Спробуйте тут , або, принаймні, ви могли, але в Інтернеті evalне схожі списки списків :( Якщо ви хочете спробувати його, вручну зберігайте список із 3-х кубиків у змінну, яка не використовується програмою, а потім замініть всі екземпляри Qз цією змінною. Ініціалізація зразка:

J[[3 3 3 3 3 6)[2 2 2 5 5 5)[1 4 4 4 4 4))

Це проходить усі тести Мартіна, я не пережив усі справи Петра: P

Пояснення (це буде дузі)

Lmsd^b2

Досить проста, робить функцію, yяка повертає суму кожної декартової пари значень в ітерабелі. Еквівалент: def y(b):return map(lambda d:sum(d),product(b,repeats=2)). Це використовується для створення багатогранних штампів, що імітують метання звичайних штампів двічі.

Msmsm>bkGH

Визначає функцію gз 2-х аргументів, яка повертає, скільки разів матка б'є іншого. Еквівалентно def g(G,H):return sum(map(lambda k:sum(map(lambda b:b>k,G)),H).

DPNK-ghNeNgeNhNR?^tZ<KZKZ

Визначає функцію, Pяка бере аргумент списку двох кубиків. Це повертається -1, якщо перший матриця 'програє', 0 за нічию та 1, якщо перший манд 'виграє'. Дорівнює:

def P(N):
 K=g(N[0],N[-1]) - g(N[-1],N[0])
 return -1**(K<0) if K else 0

Призначення AGHдіє як 2-кортежневе призначення пітона. По сутіG,H=(result)

msdCm,PkP,yhkyekm,@Qb@QhbUQ

Переходимо пояснювати назад через карти. m,@Qb@QhbUQітерацію над b = 0..2 та генерування 2-х кортенів кісток з індексом b та індексом b + 1. Це дає нам кубики (A, B), (B, C), (C, A) (pyth автоматично модифікує індекси за довжиною списку).

Далі m,PkP,yhkyekповторюється результат попередньої карти, при цьому кожна пара кісток зберігається в k протягом кожного пробігу. Повертає tuple(P(k),P(tuple(y(k[0]),y(k[-1]))))для кожного значення. Це зводиться до `((A б'є B?, 2 * A б'є 2 * B), (B б'є C?, 2 * B б'є ..)).

Нарешті, msdCпідсумовує значення попередньої карти після її зшивання. Zip викликає всі значення "ударів" для однієї кістки в першому кортежі, а значення подвійних кісток - у другому.

?"none"|!G%G3s[*!+GH"Grime-"*qGH"strongly ""nontransitive

Груба річ, яка друкує результати. Якщо G = 0 або не ділиться на 3, це ловить бот +/- 3, ( |!G%G3), друкує none, в іншому випадку виводить суму списку follwing: [not(G+H)*"Grime",(G==H)*"strongly ","nontransitive"]. Я вважаю, що булеви досить зрозумілі щодо визначень у питанні. Зауважте, що G тут не може бути нульовим, оскільки це потрапило в попередню перевірку.


1

J (204)

Шлях занадто довгий, можливо, можна було б багато в гольфі, маючи більш ефективну систему для вибору правильної струни.

f=:3 :'(<,>)/"1+/"2>"1,"2(<,>)/L:0{(,.(1&|.))y'
n=:'nontransitive'
d=:3 :0
if.+/*/a=.f y do.+/*/b=.f<"1>,"2+/L:0{,.~y if.a-:b do.'strongly ',n elseif.a-:-.b do.'Grime-',n elseif.do.n end.else.'none'end.
)

1

Матлаб (427)

Це не так вже й коротко, і я впевнений, що в гольфі можна набагато більше, я просто намагався вирішити цю проблему, тому що вважав це дуже цікавим завданням, тому дякую @ MartinBüttner за створення цього завдання!

a=input();b=input();c=input();
m = 'non';l=@(a)ones(numel(a),1)*a;n=@(a,b)sum(sum(l(a)>l(b)'));g=@(a,b)n(a,b)>n(b,a);s=@(a,b,c)sum([g(a,b),g(b,c),g(c,a)]);
x=s(a,b,c);y=s(a,c,b);if x~=3 && y~=3;m=[m,'e'];else m=[m,'transitive'];o=ones(6,1);a=o*a;a=a+a';a=a(:)';b=o*b;b=b+b';b=b(:)';c=o*c;c=c+c';c=c(:)';u=s(a,b,c);
v=s(a,c,b);if u==3|| v==3;if x==3&&u==3 || y==3&&v==3 m=['strongly ',m];else m=['Grime-',m];end;end;end;disp(m);

Ось код повної довжини з деякими коментарями, якщо ви хочете спробувати зрозуміти, що відбувається. Я включив кілька тестових випадків зайця та виключив команди введення:

%nontransitive
% a = [1 2 2 4 6 6];
% b = [1 2 3 5 5 5];
% c = [2 3 4 4 4 4];

%none
% a = [1 2 3 4 5 6];
% b = [6 5 4 3 2 1];
% c = [1 3 5 2 4 6];

%grime nontransitive
% a = [3 3 3 3 3 6];
% b = [2 2 2 5 5 5];
% c = [1 4 4 4 4 4];

%strongly nontransitive
% a = [2 2 2 5 5 5];
% b = [2 3 3 3 5 5];
% c = [1 1 4 5 5 5];

m = 'non';

l=@(a)ones(numel(a),1)*a;
n=@(a,b)sum(sum(l(a)>l(b)'));
%input as row vector, tests whether the left one beats the right one:
g=@(a,b)n(a,b)>n(b,a);
s=@(a,b,c)sum([g(a,b),g(b,c),g(c,a)]);
%if one of those x,y has the value 3, we'll have intransitivity
x=s(a,b,c); 
y=s(a,c,b);
if x~=3 && y~=3 %nontransitive
    m=[m,'e'];
else %transitive
    m=[m,'transitive'];
    o=ones(6,1);
    a=o*a;a=a+a';a=a(:)'; %all possible sums of two elements of a
    b=o*b;b=b+b';b=b(:)';
    c=o*c;c=c+c';c=c(:)';
    u=s(a,b,c);
    v=s(a,c,b);

    %again: is u or v equal to 3 then we have transitivity
    if u==3 || v==3 %grime OR strongly
        % if e.g. x==3 and u==3 then the 'intransitivity' is in the same
        % 'order', that means stronlgy transitive
        if x==3 && u==3 || y==3 && v==3%strongly
            m=['strongly ',m];
        else %grime
            m=['Grime-',m];
        end   
    end
end

disp(m);

Чи не коротше, якщо ви прочитаєте масив, input()а потім призначите три елементи a,b,c? Крім того , будь ласка , використовуйте точні рядки в специфікації ( none, nontransitiveі капіталізованої Grime) ... повинен , ймовірно , навіть зберегти вам байти.
Мартін Ендер

Так, це, мабуть, коротше, я погляну на це. Рядки будуть саме тими, що я тільки що видалив dispкоманди у довгій версії, вони були лише для тестування програми, але остаточне повідомлення зберігається в m. І я виправив G.
невдача

0

JavaScript - 276 байт

function(l){r=function(i){return l[i][Math.random()*6|0]};p=q=0;for(i=0;j=(i+1)%3,i<3;++i)for(k=0;k<1e5;++k){p+=(r(i)>r(j))-(r(i)<r(j));q+=(r(i)+r(i)>r(j)+r(j))-(r(i)+r(i)<r(j)+r(j))}alert((a=Math.abs)(p)>5e3?((a(q)>5e3?p*q>0?'strongly ':'Grime-':'')+'nontransitive'):'none')}

Я не дуже хороший у ймовірності, тому, щоб бути впевненим у своїх результатах, я вважаю за краще просто кидати кістки сотні тисяч разів.

Вираз оцінює функцію, яку слід викликати лише одним аргументом: масив з трьох масивів цілих чисел. Перевірте Fiddle, щоб мати можливість самостійно запустити код.

Ось незворушена версія:

function (diceList) {
    var getRandomValue = function (idDie) {
        return diceList[idDie][Math.floor(Math.random() * 6)];
    };

    var probabilitySimpleThrow = 0;
    var probabilityDoubleThrow = 0;

    for (var idDieA = 0; idDieA < 3; ++idDieA)
    {
        var idDieB = (idDieA + 1) % 3;
        for (var idThrow = 0; idThrow < 1e5; ++idThrow)
        {
            probabilitySimpleThrow += getRandomValue(idDieA) > getRandomValue(idDieB);
            probabilitySimpleThrow -= getRandomValue(idDieA) < getRandomValue(idDieB);

            probabilityDoubleThrow += getRandomValue(idDieA) + getRandomValue(idDieA) > getRandomValue(idDieB) + getRandomValue(idDieB);
            probabilityDoubleThrow -= getRandomValue(idDieA) + getRandomValue(idDieA) < getRandomValue(idDieB) + getRandomValue(idDieB);
        }
    }

    if (Math.abs(probabilitySimpleThrow) > 5e3) {
        if (Math.abs(probabilityDoubleThrow) > 5e3) {
            if (probabilitySimpleThrow * probabilityDoubleThrow > 0) {
                var result = 'strongly ';
            }
            else {
                var result = 'Grime-';
            }
        }
        else {
            var result = '';
        }

        result += 'nontransitive';
    }
    else {
        var result = 'none';
    }

    alert(result);
}

Гм, я не думаю, що це насправді в дусі виклику. Ви в основному перетворили це з виклику теорії ймовірностей у виклик статистики. ;) ... Замість випадкових кидків ви можете просто перерахувати всі можливі кидки рівно один раз. Це дасть точні результати (і працюватиме набагато швидше).
Мартін Ендер

Я перевірю, чи це призводить до більш короткого сценарію. Дякую за вашу пораду :).
Blackhole
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.