lambda s:all(n==reduce(lambda n,c:-~[n,n%3+n%4][c>'L']%5,s,n)for n in range(5))
Try it online!
This uses the group-theoretic approach from Ilmari Karonen's GolfScript answer to my 2014 challenge, in particular to the bonus question.
Instead of the ant crawling around the dodecahedron, we imagine it stays in place while the dodecahedron turns under its feet. We must determine whether the sequence of rotations returns the dodecahedron to the initial position.
There are 60 rotation of the dodecahedron -- 12 faces times 5 positions per face. These rotations can be expressed as permutations of 5 elements. Specifically, they permute 5 colored tetrahedra shown below that partition the 20 vertices of the dodecahedron.
We could take each rotation and write down which color tetrahedron moves onto which color's position to obtain a permutation of the five colors. Specifically, these are the even permutations, which are half of the 5!=120 permutations of five elements, or 60, forming the alternating group \$A_5\$ on five elements. The other 60 odd permutations would involve reflecting the dodecahedron and well as rotating it, so they do not figure in this problem.
We want to choose two even permutations that represent the rotations from the ant turning left and right. As noted by Ilmari Karonen, the two permutations must have order 5, corresponding to five left or five right turns brining the ant back to the same place. Moreover, their product must have order 5 as well, and neither can be a power of the other.
There are many choices for the two permutations. If we think of them as permuting the values 0 to 4, the pair our code uses is 12340
and 13042
. The first one simply adds one modulo 5. From here, there's 5 choices for the other one: 13042, 14302, 24310, 32041, 32410
. The code uses 13042
because it happens to have a short expression in Python 1+(n%3+n%4)%5
, or just n%3+n%4
if we "share" the +1
and %5
for the other case`. I found this via some brute-forcing.
Now let's take another look at the code:
lambda s:all(n==reduce(lambda n,c:-~[n,n%3+n%4][c>'L']%5,s,n)for n in range(5))
Try it online!
To check that the sequence of permutations combines to the identity, we test each starting value n
from range(5)
, apply the sequence of permutations to it using reduce
, and check that all
of them end up at the initial value. The -~
is a shortcut to add one.
74 bytes
lambda s:0in[n==reduce(lambda n,c:-~[n,48/~n][c>'L']%5,s,n)for n in 0,1,2]
Try it online!
Outputs True/False swapped.
I found 48/~n
as a shorter alternative for the second permutation when it is incremented and taken mod 5.
Also, instead of checking that the permutation maps each of 0,1,2,3,4
to themselves, this only checks 0,1,2
. This suffices because the map is bijective, so once 0,1,2
are fixed, 3
and 4
have to either map to themselves or swap, and because the permutation is even they can't swap.
65 bytes
S=s=`321.`
for c in input():s=(s+s[ord(c)%9:3]+s)[3:8]
print s==S
Try it online!
This uses a different mapping pair: 34012, 34120
. These are nice to implement as operations on lists, moving the last two elements to the front in both cases, and for the latter cycling the last 3. To start, we just need any sequence of 5 distinct elements, so we use `321.`
which equals '321.0'
.
61 bytes
n=27
for c in input():n=n%16*64|n/16*4**(c>'L')%63
print n<28
Try it online!
This uses bitwise shenanigans, much like my 2018 answer with cubes. It implements the permutations 34012, 34120
.
The number n
encode 5 fields of bits 2 each, say abcde
. Each step permutes these bits to either deabc
or debca
using bitwise operations. n%16*64
moves de
into the first two positions, while n/16*4**(c>'L')%63
makes abc
in the last 3 positions and then conditionally transforms it to bca
if an R
is read.
Initial, these five fields are 00123
, which translates into n=27
in base 4. It's fine that the first 2 of them are the same, as no sequence of permutations can solely swap them because all the permutations are even. Because n=27
is the smallest possible permutation of the fields, we can use n<28
to check that the final state is the same as the initial one.
60 bytes
L=1;R=1j
for c in input():exec c+"=(L+R)%5%5j"
print L*1j==R
Try it online!
A new method based on alephalpha's finding that \$A_5 \cong PSL(2,5)\$. A cute trick here is using L
and R
for variables so we can plug the character we read and exec
.
We interpret the L
's and R
's as instructions to set either L=L+R
or R=L+R
. If this always results in either getting back the original values mod 5 or getting back their negations mod 5, then the instructions give a closed loop.
It suffices to test that this works for both the initial "basis vectors" L=1, R=0
and L=0, R=1
. Instead of testing twice, we run both tests in parallel using complex numbers, with one case in the real part and the other in the imaginary part, so L=1, R=1j
. Python 2 has a wacky complex modulus that lets us %5
to reduce the real part and %5j
to reduce the imaginary part.
In the end, we can if we're in one of the success cases of the original L=1,R=1j
or its negation mod 5 of L=4,R=4j
. It turns out it suffices to check L*1j==R
as shown by this code testing for false positives.
59 bytes
L=1;R=1j
exec"=(L+R)%5%5j;".join(input()+' ')
print L*1j==R
Try it online!
Saves one byte from above using .join
to create the string to execute.