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.