| Bytes | Lang | Time | Link |
|---|---|---|---|
| 097 | Uiua | 241009T165913Z | nyxbird |
| 214 | Haskell | 241008T215612Z | colossus |
| 053 | Vyxal | 240919T084455Z | emanresu |
| 427 | Matlab | 150108T194928Z | flawr |
| 100 | Dyalog APL | 150113T024301Z | ngn |
| 257 | J | 150110T222549Z | Jay Bosa |
| 204 | J | 150112T191330Z | ɐɔıʇǝɥʇu |
| nan | 150109T180024Z | FryAmThe | |
| 276 | JavaScript | 150108T143909Z | Blackhol |
| 269 | Python 2 | 150108T012428Z | feersum |
Uiua, 97 bytes
⨬"none"(⊂:"nontransitive"⨬("Grime-"|""|"strongly ")+1×)⊸⌵:∩(×=3⊃⌵±/+≡(±/+♭/⊞(±-))⊏⍉⊟⤙↻1⇡3)≡♭≡⊞+..
Try it! (← commented explanation)
Takes input as a 3x6 array
Essentially, we generate the two-throws as their own (3x36) array, and get every possible win and loss for 0 against 1, 1 against 2, and 2 against 0 as -1/0/1. If you take the sign of the sum, you end up with a 3-element list with the signs for wins and losses (ie. [1 `1 1]). If the absolute value of the sum isn't three, there's no cycle, and if there is, the sign of the sum tells you which direction it's in. So, we can use ×=3⊃⌵± to turn the list into -1 for a counterclockwise cycle, 1 for a clockwise cycle, or 0 for no cycle. After that you can switch twice (once to see if the one-throws make a cycle, and once to see if and how the two-throws make a cycle.)
I think this is golfable? The :s and .s seem like they might be replaceable somehow.
Haskell, 214 bytes
a#b=sum[signum$p-q|p<-a,q<-b]>0
(a!b)c=a#b&&b#c&&c#a
n="nontransitive"
d a=[i+j|i<-a,j<-a]
h(w,x,y,z)|w&&y||x&&z="strongly "++n|w&&z||x&&y="Grime-"++n|w||x=n|1>0="none"
(a?b)c=h(a!b$c,c!b$a,d a!d b$d c,d c!d b$d a)
The a#b operator returns True if a beats b. Step one is double iterating over both lists, subtracting their results, running those through signum. That gives us a 1, 0, or -1 for each possible result of rolling A and B where 1 represents A winning, -1 is B winning, and 0 is a tie. If the sum of all these results is positive that means A wins more than it loses.
The (a!b)c operator returns True if A beats B, B beats C, and C beats A.
The d function doubles up a die by double iterating over it and adding the results. Basically creates a 36 sided die with every possible result of two rolls.
In the h function w will be true if the die cycle forward, x will be true if the dice cycle backward, and y and z are the same but for the doubled dice. We then check for the double cases first, then checking for a simple nontransitive relationship, and finally return "none" if all else fails.
Finally we have (a?b)c which takes our three dice and passes h the required flags.
Vyxal, 53 bytes
ƛẊṠ;"ƛǔ¨£ǒ-±ṠṠ±₌≈h*;3βȧ`Gr⋏≬-
ġƈ `↵`⟑¢›≤ive`+‛»≤pǏǔi
A bit of a mess, but I'm pretty happy with it.
The main "trick" this answer uses is the following: By checking whether each dice beats the next, we get an array of signs -1/0/1, which will be [-1, -1, -1] if we have a decreasing cycle and [1, 1, 1] if we have an increasing cycle. This can then be turned into -1/1 for cycles and 0 otherwise by multiplying the first item by whether all items are the same. Since I'm performing this check for both the dice and their doubled rolls, this results in a pair of signs with the following possibilities:
[0, 0],[0, -1]or[0, 1]ifnonei.e. there is no first cycle, and we don't care about the second.[1, -1]or[-1, 1]ifGrime-nontransitive- there are two cycles and they're opposite.[1, 0]or[-1, 0]ifnontransitive- there is no second cycle.[1, 1]or[-1, -1]ifstrongly nontransitive- there are two identical cycles.
The clever part is converting these into base 3 and taking the absolute value. Then, none maps to 0 or 1, Grime-nontransitive maps to 2, nontransitive maps to 3 and strongly nontransitive maps to 4. From here it's easy to index into a list.
ƛ ; # Over each dice
ẊṠ # Sum all pairs from it, giving the distribution of two rolls of each
" # Pair these with the original dice
ƛ ; # Over both the original and doubled dice,
# Calculate the winner of each pair:
ǔ¨£ # Over each pair of dice
ǒ-± # Compare all pairs of values from each
ṠṠ± # Sum and take the sign
# This results in [1, 1, 1] if increasing cycle, [-1, -1, -1] if decreasing cycle
* # Multiply
h # The first item
₌≈ # By whether they're all equal
# Giving 1/-1 for cycles, 0 otherwise
# Now we have [0, x] if none, [1,-1] / [-1,1] if Grime,
# [1,1]/[-1,-1] if strong and [1,0]/[-1,0] otherwise
3βȧ # Convert to base 3 and take the absolute value, giving
# 0/1->none, 2->grime, 3->nontransitive, 4->strong
i i # Index into
`...`↵ # ["Grime-","","strongly "]
`...`+ # + "nontransitive"
‛»≤p # With "none" prepended
Ǐǔ # twice
Matlab (427)
It is not that short and I am sure it can be golfed a lot more, I just tried to solve this challenge because I thought it was a very fun task, so thanks @MartinBüttner for creating this challenge!
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);
Here the full length code with some comments if you want to try to understand what's going on. I included some test cases hare and excluced the input commands:
%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);
Dyalog APL, 107 100 bytes
{T←{+/×+/¨∊¨×⍵∘.-¨1⌽⍵}⋄3≠|S←T⍵:'none'⋄N←'nontransitive'⋄S=D←T∘.+⍨¨⍵:'strongly ',N⋄S=-D:'Grime-',N⋄N}
(Thanks @Tobia for this simpler, shorter, better solution)
Basics:
←assignment⋄statement separator{}lambda form⍺⍵left and right argumentA:Bguard ("ifAthen returnB")
T is a function that returns 3 if A beats B, B beats C, and C beats A; -3 if the exact opposite is the case; and something inbetween otherwise. In detail:
1⌽⍵is the one-rotation of⍵. If⍵is ABC, the rotation is BCA.∘.-computes a subtraction table between two vectors (1 2...10 ∘.× 1 2...10would be the multiplication table we know from school). We apply this between each (¨) item of⍵and its corresponding item in1⌽⍵.×signum of all numbers in the subtraction tables∊¨flatten each table+/¨and sum it. We now have three numbers that represent balances: number of winning minus losing cases for each of A vs B, B vs C, C vs A.×signum of those+/sum
Then handle the cases in turn:
3≠|S←T⍵:'none'ifT⍵'s absolute value isn't 3, return 'none'N←'nontransitive'we'll need this word a lotS=D←T∘.+⍨¨⍵:'strongly ',NcomputeTfor pairs of dice (∘.+⍨¨⍵←→⍵((∘.+)¨)⍵) and return "strongly..." if the same relationships among ABC still holdS=-D:'Grime-',N⍝ "Grime" if the relationships are in the opposite directionsNif all else fails, just "nontransitive"
J - 311 257 bytes
Update (13 Jan 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'
)
Explanation: Using Gerunds, simplify the if.s to @.s.
Older version:
First try at both coding in J as well as golfing.
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.
)
Run it using a syntax similar to following (extra spaces for clarity):
f 3 6 $ 1 1 9 17 17 21, 1 5 5 13 21 21, 5 5 13 13 13 17
Explanation:
g is defined as a diad taking two arrays that tells if first dice beats second dice
h is defined as a diad taking two arrays that tells if throwing twice and summing, does first dice beat second
f is a monad that takes a table and returns a string with the right answer
Edit: Fix a mistake in Grime-nontransitive condition (replacing , with *)
J (204)
Way too long, could probably be golfed a lot by having a more efficient system for picking the right string.
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.
)
Pyth 129 133
Lmsd^b2Msmsm>bkGHDPNK-ghNeNgeNhNR?^tZ<KZKZAGHmsdCm,PkP,yhkyekm,@Qb@QhbUQ?"none"|!G%G3s[*!+GH"Grime-"*qGH"strongly ""nontransitive
Try it here, or at least you could, but the online eval doesn't seem to like lists of lists :( If you want to try it there, manually store a list of 3 dice into a variable not used by the program and then replace all instances of Q with that variable. A sample initialization:
J[[3 3 3 3 3 6)[2 2 2 5 5 5)[1 4 4 4 4 4))
This passes all of Martin's test cases, I haven't the heart go through all of Peter's cases :P
Explanation (this is gonna be a doozy)
Lmsd^b2
Pretty simple, makes a function y that returns the sum of each Cartesian pair of values in an iterable. Equivalent to: def y(b):return map(lambda d:sum(d),product(b,repeats=2)). This is used to create many-sided dies that simulate throwing the regular dies twice.
Msmsm>bkGH
Defines a function g of 2 arguments that returns how many times a die beats another. Equivalent to def g(G,H):return sum(map(lambda k:sum(map(lambda b:b>k,G)),H).
DPNK-ghNeNgeNhNR?^tZ<KZKZ
Defines a funtion P that takes a list of two dice as its argument. This returns -1 if the first die 'loses', 0 for a tie and 1 if the first die 'wins'. Equivalent to:
def P(N):
K=g(N[0],N[-1]) - g(N[-1],N[0])
return -1**(K<0) if K else 0
The AGH assigns acts like a python 2-tuple assignment. Essentially G,H=(result)
msdCm,PkP,yhkyekm,@Qb@QhbUQ
Going to explain backwards through the maps. m,@Qb@QhbUQ iterates over b=0..2 and generates 2-tuples of dice with index b and index b+1. This gives us dice (A,B),(B,C),(C,A) (pyth automatically mods indexes by the length of the list).
Next, m,PkP,yhkyek iterates over the result of the previous map, with each dice pair being stored in k over each run. Returns tuple(P(k),P(tuple(y(k[0]),y(k[-1])))) for each value. That boils down to `((A beats B?, 2*A beats 2*B), (B beats C?, 2*B beats..)).
Finally, msdC sums the values of the previous map after it has been zipped. The zip causes all of the single dice 'beats' values in the first tuple, and the double dice values in the second.
?"none"|!G%G3s[*!+GH"Grime-"*qGH"strongly ""nontransitive
A gross thing that prints out the results. If G is 0 or not divisible by 3, this catches bot +/- 3, (|!G%G3), prints none, otherwise prints the sum of the follwing list: [not(G+H)*"Grime",(G==H)*"strongly ","nontransitive"]. I think the booleans are fairly self-explanatory with regard to the definitions in the question. Do note that G cannot be zero here, as that is caught by the previous check.
JavaScript - 276 bytes
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')}
I'm not really good in probability, so to be sure of my results, I prefer to just throw the dice hundreds of thousands times.
The expression evaluates to a function, that should be called with only one argument: an array of three arrays of integers. Check the Fiddle to be able to run the code by yourself.
Here is the ungolfed version:
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);
}
Python 2, 269
Here's a nice little expression that evaluates to a function. It accepts three lists of integers. Passes all test cases.
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"