Czy te kości są nieprzechodnie?


31

Kości nieprzechodnie są ładnymi, małymi zabawkami, które przeczą naszej intuicji w teorii prawdopodobieństwa. Potrzebujemy kilku definicji tego wyzwania:

Rozważ dwie kości A i B, które są rzucane jednocześnie. Mówimy, że bije B jeśli prawdopodobieństwo A wykazujący większą liczbę niż B jest większe niż prawdopodobieństwo B wykazujące większą liczbę niż A .

Rozważmy teraz zestaw trzech kości, z etykietami , B , C . Taki zestaw kości nazywany jest nieprzechodnim, jeśli

  • albo A bije B , B bije C i C bije A
  • lub C uderzeń B , B bije i uderzeń C .

Jako jeden z moich ulubionych przykładów, rozważ kości Grime , które mają następujące strony:

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

Co ciekawe, średnia każdej kości wynosi 3,5, podobnie jak zwykła kostka.

Można pokazać, że:

  • A bije B z prawdopodobieństwem 7/12.
  • B pokonuje C z prawdopodobieństwem 7/12.
  • C bije A z prawdopodobieństwem 25/36.

Teraz te konkretne kości są jeszcze dziwniejsze. Jeśli rzucimy każdą kością dwa razy i zsumujemy wyniki, kolejność bitów zostanie odwrócona:

  • B pokonuje A z prawdopodobieństwem 85/144.
  • C bije B z prawdopodobieństwem 85/144.
  • A bije C z prawdopodobieństwem 671/1296.

Nazwijmy zestaw kości z tą właściwością Nieprzechodnie nieprzepuszczalne .

Z drugiej strony, jeśli kości zachowają swój pierwotny cykl przy użyciu dwóch rzutów, nazywamy je silnie nieprzechodnie . (Jeśli nie ma cyklu dla dwóch rzutów, po prostu nazywamy je nieprzechodnimi ).

Wyzwanie

Biorąc pod uwagę trzy sześciościenne określić, które z powyższych właściwości ten zestaw posiada i jedno wyjście z następujących ciągów: none, nontransitive, Grime-nontransitive, strongly nontransitive.

Możesz napisać program lub funkcję, wziąć dane wejściowe przez STDIN, argument wiersza poleceń, monit lub argument funkcji i zapisać wynik w STDOUT lub zwrócić go jako ciąg.

Możesz założyć, że wszystkie strony są liczbami całkowitymi nieujemnymi. Nie możesz zakładać, że boki lub kości są w określonej kolejności. Możesz wprowadzać dane w dowolnym dogodnym formacie listy lub ciągu.

To jest kod golfowy, więc wygrywa najkrótsza odpowiedź (w bajtach).

Przypadki testowe

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

Jeśli chcesz jeszcze dokładniej przetestować swój kod, Peter Taylor był na tyle uprzejmy, że napisał implementację referencyjną, która sklasyfikowała wszystkie ~ 5000 zestawów kości o bokach od 1 do 6 i średnio 3,5. Link do wklejania


Zupełnie zapomniałem o nieprzechodnich kościach. Dziękuję :)
npst

Czy pierwszy nieprzechodni przykład jest poprawny? 1 2 2 4 6 6, 1 2 3 5 5 5, 2 3 4 4 4 4Dostaję A <B 17/36, B> C 19/36, C <A 16/36.
Tobia,

@Tobia Zapomniałeś, że losowanie jest możliwe. Musisz także obliczyć, jak często każda kostka przegrywa z innymi, i sprawdzić, czy to mniej niż prawdopodobieństwo wygranej: Tak A wygrywa z B przy 17/36, ale A przegrywa z B tylko 16/36, więc A bije B Podobnie, C wygrywa z A 16/36, jak powiedziałeś, ale C przegrywa z A tylko 14/36, więc C bije A.
Martin Ender

Odpowiedzi:


5

Dyalog APL, 107 100 bajtów

{({+/×+/¨,¨×⍵∘.-¨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}

(Dzięki @Tobia za to prostsze, krótsze, lepsze rozwiązanie)

Podstawy:

  • zadanie

  • separator instrukcji

  • {} forma lambda

  • ⍺⍵ argument lewy i prawy

  • A:B straż („jeśli A to wróć B”)

Tjest funkcją, która zwraca 3, jeśli A bije B, B bije C, a C bije A; -3, jeśli jest dokładnie odwrotnie; i coś pomiędzy nimi. Szczegółowo:

  • 1⌽⍵jest jednym obrotem . Jeśli jest ABC, rotacja to BCA.

  • ∘.-oblicza tabelę odejmowania między dwoma wektorami ( 1 2...10 ∘.× 1 2...10byłaby to tabliczka mnożenia, którą znamy ze szkoły). Stosujemy to między każdym ( ¨) elementem i odpowiadającym mu elementem w1⌽⍵ .

  • × podpis wszystkich liczb w tabelach odejmowania

  • ∊¨ spłaszcz każdy stół

  • +/¨i podsumuj to. Mamy teraz trzy liczby, które reprezentują salda: liczba wygranych minus przegrane przypadki dla każdej z A vs B, B vs C, C vs A.

  • × podpis tych

  • +/ suma

Następnie kolejno zajmuj się skrzynkami:

  • 3≠|S←T⍵:'none' Jeśli T⍵ wartość bezwzględna nie wynosi 3, zwróć „brak”

  • N←'nontransitive' bardzo potrzebujemy tego słowa

  • S=D←T∘.+⍨¨⍵:'strongly ',Noblicz Tpary kości ( ∘.+⍨¨⍵← → ⍵((∘.+)¨)⍵) i zwróć „zdecydowanie ...”, jeśli nadal utrzymują się te same relacje między ABC

  • S=-D:'Grime-',N ⍝ „Brud”, jeśli relacje są w przeciwnych kierunkach

  • N jeśli wszystko inne zawiedzie, po prostu „nieprzechodni”


1
Pobiłeś mnie do tego! Pracowałem nad tym problemem 3 dni temu, ale potem przestałem pisać moją odpowiedź. W każdym razie jest zbyt podobny do twojego, więc opublikuję go tutaj. Jest nieco krótszy przy 100 znakach:{T←{+/×+/¨∊¨×⍵∘.-¨1⌽⍵}⋄3≠|S←T⍵:'none'⋄N←'nontransitive'⋄S=D←T∘.+⍨¨⍵:'strongly ',N⋄S=-D:'Grime-',N⋄N}
Tobia,

@ MartinBüttner: Prawidłowy termin w tytule to „znaki”, ponieważ liczba bajtów będzie się różnić w zależności od zestawu znaków używanego do kodowania symboli APL. Tradycyjnie były one po prostu zakodowane w górnej połowie 8-bitowych bajtów, po ASCII. Obecnie używamy UTF-8, ale stare zestawy znaków są nadal przydatne… głównie w celu zmniejszenia liczby bajtów do liczby znaków podczas gry w golfa!
Tobia,

@Tobia W kodzie golfowym krótsze atuty wcześniej, więc wygrywasz! Nie jestem do końca zaznajomiony z etykietą golfa, ale myślę, że powinieneś opublikować ją jako osobną odpowiedź, ponieważ jest ona zasadniczo inna i doszedłeś do niej niezależnie.
ngn

@Tobia Wolę też liczyć znaki, ale jeśli sugerowane jest klasyczne kodowanie, to bajty = znaki, więc może tak naprawdę nie ma znaczenia, jak je nazywamy ...
ngn

@Tobia Cóż, zdecydowanie jest bezużyteczne podawanie liczby postaci w wyzwaniu, które zdobywa bajty. Jednak nikt nigdy nie powiedział, że oceniamy w bajtach UTF-8. W rzeczywistości tag wiki wyraźnie mówi, że dla znaków spoza zakresu ASCII można zastosować inne istniejące kodowanie. A APL ma własną stronę kodową, więc cały zestaw znaków mieści się w bajcie. Polityka PPCG polega na wykorzystaniu tej strony kodowej do zliczania APL - nie jest sprawiedliwe karanie APL za starsze niż ASCII.
Martin Ender

13

Python 2, 269

Oto miłe, małe wyrażenie, które odnosi się do funkcji. Akceptuje trzy listy liczb całkowitych. Przechodzi wszystkie przypadki testowe.

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 bajtów

Aktualizacja (13 stycznia 2015 r.):

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'
)

Objaśnienie: Używając Gerunds, uprość if.s do @.s.

Starsza wersja:

Najpierw spróbuj zarówno kodowania w J, jak i gry w golfa.

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.
)

Uruchom go, używając składni podobnej do następującej (dodatkowe spacje dla przejrzystości):

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

Wyjaśnienie:

gjest definiowany jako diad biorący dwie tablice, który mówi, czy pierwsza kostka bije drugą kostkę
hjest definiowany jako diad biorący dwie tablice, który mówi, czy rzucanie dwa razy i sumowanie, czy pierwsza kostka bije drugą
fjest monadą, która bierze tabelę i zwraca ciąg znaków z poprawna odpowiedź

Edit: Fix błąd w grime-nieprzechodnie warunku (zastępując ,z *)


Chciałbym sugestie dotyczące ulepszeń. :)
Jay Bosamiya,

@ MartinBüttner, początkowo próbowałem tego, ale nie wiedziałem, jak połączyć kilka wierszy (lub zdań, jak to jest znane w J) bez zwiększania długości kodu o wiele więcej ... poznanie "gerunds" doprowadziło mnie do wiele zdań w jedno, co kończy się również skróceniem kodu ...
Jay Bosamiya,

1

Pyth 129 133

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

Wypróbuj tutaj , a przynajmniej możesz, ale online evalnie lubi list list :( Jeśli chcesz go wypróbować, ręcznie zapisz listę 3 kości w zmiennej nieużywanej przez program, a następnie zamień wszystkie wystąpienia Qtej zmiennej. Przykładowa inicjalizacja:

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

To przechodzi wszystkie przypadki testowe Martina, nie mam serca, aby przejrzeć wszystkie przypadki Petera: P

Wyjaśnienie (to będzie doozy)

Lmsd^b2

Całkiem prosta, sprawia, że ​​funkcja yzwraca sumę każdej pary kartezjańskich wartości w iterowalnym. Odpowiednik: def y(b):return map(lambda d:sum(d),product(b,repeats=2)). Służy do tworzenia matryc wielostronnych, które symulują rzucanie zwykłymi matrycami dwa razy.

Msmsm>bkGH

Definiuje funkcję g2 argumentów, która zwraca liczbę przypadków, gdy kostka bije inną. Odpowiednik def g(G,H):return sum(map(lambda k:sum(map(lambda b:b>k,G)),H).

DPNK-ghNeNgeNhNR?^tZ<KZKZ

Definiuje funkcję, Pktóra przyjmuje jako argument listę dwóch kości. Zwraca -1, jeśli pierwsza kość „przegrywa”, 0 dla remisu i 1, jeśli pierwsza kość „wygrywa”. Równoważny:

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

W AGHwyznacza działa jak pyton Zadanie 2-krotnego. GłównieG,H=(result)

msdCm,PkP,yhkyekm,@Qb@QhbUQ

Wyjaśniam wstecz przez mapy. m,@Qb@QhbUQiteruje powyżej b = 0..2 i generuje 2 krotki kostek o indeksie b i indeksie b + 1. To daje nam kości (A, B), (B, C), (C, A) (pyth automatycznie modyfikuje indeksy według długości listy).

Następnie, m,PkP,yhkyekiteruje wynik poprzedniej mapy, a każda para kości jest przechowywana w kilogramach dla każdego przebiegu. Zwraca tuple(P(k),P(tuple(y(k[0]),y(k[-1]))))dla każdej wartości. Sprowadza się to do (((A bije B ?, 2 * A bije 2 * B), (B bije C ?, 2 * B bije ...)).

Na koniec msdCsumuje wartości poprzedniej mapy po jej spakowaniu. Zip powoduje, że wszystkie wartości pojedynczych kości „biją” w pierwszej krotce, a wartości podwójnych kości w drugiej.

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

Obrzydliwa rzecz, która drukuje wyniki. Jeśli G jest 0 lub nie jest podzielna przez 3, to połowy bot +/- 3, ( |!G%G3), druki none, inaczej wypisuje sumę listy follwing: [not(G+H)*"Grime",(G==H)*"strongly ","nontransitive"]. Myślę, że booleany są dość oczywiste w odniesieniu do definicji w pytaniu. Zauważ, że G nie może być tutaj zero, ponieważ jest to wychwycone przez poprzednią kontrolę.


1

J (204)

O wiele za długo, prawdopodobnie można by go dużo zagrać w golfa, mając bardziej wydajny system doboru odpowiedniej struny.

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

Matlab (427)

Nie jest tak krótki i jestem pewien, że można go jeszcze bardziej pograć w golfa, po prostu próbowałem rozwiązać to wyzwanie, ponieważ myślałem, że to bardzo fajne zadanie, więc dziękuję @ MartinBüttner za stworzenie tego wyzwania!

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);

Oto pełny kod z komentarzami, jeśli chcesz spróbować zrozumieć, co się dzieje. Podałem kilka przypadków testowych zając i wykluczyłem polecenia wejściowe:

%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);

Czy nie jest krótsze, jeśli czytasz tablicę jeden, input()a następnie przypisujesz trzy elementy a,b,c? Ponadto, należy użyć dokładnie sznurki w specyfikacji ( none, nontransitivei skapitalizowanych Grime) ... powinien chyba nawet zaoszczędzić bajtów.
Martin Ender

Tak, to prawdopodobnie będzie krótsze, przyjrzę się temu. Ciągi będą dokładnie tymi, które właśnie usunąłem disppolecenia w długiej wersji, były one tylko do testowania programu, ale końcowy komunikat jest przechowywany w m. I poprawiłem G.
flawr

0

JavaScript - 276 bajtów

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')}

Prawdopodobnie nie jestem zbyt dobry, więc aby być pewnym moich wyników, wolę rzucić kostką setki tysięcy razy.

Wyrażenie zwraca wartość do funkcji, którą należy wywołać tylko z jednym argumentem: tablicą trzech tablic liczb całkowitych. Sprawdź skrzypce, aby móc samodzielnie uruchomić kod.

Oto wersja bez golfa:

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);
}

Hm, nie sądzę, że tak naprawdę jest w duchu wyzwania. Zasadniczo zmieniłeś to z wyzwania teorii prawdopodobieństwa w wyzwanie statystyczne. ;) ... Zamiast losowych rzutów, możesz po prostu wyliczyć wszystkie możliwe rzuty dokładnie raz. To dałoby dokładne wyniki (i działałoby znacznie szybciej).
Martin Ender

Sprawdzę, czy to prowadzi do bardziej zwięzłego skryptu. Dzięki za radę :).
Blackhole
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.