text:
Braincopterify an image
Introduction
Braincopter is an esoteric Brainf*** derivative that encodes a Brainf***
program as an image. As a 2D language, it uses two additional commands; they
rotate the instruction pointer (initially pointing right) clockwise and
counterclockwise. Braincopter is very similar to Brainloller, except that
instead of using distinct colours as different commands, it instead calculates
the command based on the RGB value of each pixel.
Braincopter calculates the command for each pixel based on the formula
N = (65536 * R + 256 * G + B) % 11, where N is the command number. The
mapping from command numbers to Brainf*** commands is as follows:
0  >
1  <
2  +
3  -
4  .
5  ,
6  [
7  ]
8  rotate instruction pointer to the right (clockwise)
9  rotate instruction pointer to the left (counterclockwise)
10 NOP

Braincopter is useful for steganography, or the hiding of secret messages in
something else, as the colour of each pixel in any given photo can be changed
just slightly to give the desired operation. Such changed pictures are often
indistinguishable from the originals.
Challenge
Write a program or function that takes an image and a string of brainf*** code
as input and produces the original image with the brainf*** code encoded in it.
To do this, take each pixel in the original image and replace it with the RGB
value closest to the colour of the original pixel that evaluates to the correct
Braincopter instruction. Colour difference for the purposes of this challenge is
defined as abs(R1 - R2) + abs(G1 - G2) + abs(B1 - B2). In the case of a tie in
which two colours resolving to the same Braincopter command are equally close to
the original colour, either can be chosen.
For example, if the original colour is #FF8040 and needs to be modified to
produce a '1' instruction in Braincopter, #FF7F40 should be chosen.
Braincopter will exit when the instruction pointer runs off the edge of the
image, so we'll keep it on the image by using the 8 and 9 commands (rotate
instruction pointer clockwise and counterclockwise respectively). It's easiest
to explain the format of the encoding with an example.
For the input +[[->]-[-<]>-]>.>>>>.<<<<-.>>-.>.<<.>>>>-.<<<<<++.>>++. and an
8x9 image, the instructions will be laid out like this (using Brainf*** commands
instead of the Braincopter equivalents, and unicode representations of the turns
):
+ [ [ - > ] - ↲
↳ - > ] < - [ ↲
↳ ] > . > > > ↲
↳ < < < < . > ↲
↳ - . > > - . ↲
↳ > . < < . > ↲
↳ > > > - . < ↲
↳ + + < < < < ↲
↳ . > > + + . N

(Where N is a NOP.) As you can see, control flow travels from left to right
until it hits the first set of clockwise turns, then travels right to left
across the second row, et cetera. Your program must use this control flow. The
brainf*** input will always be able to fit in the image; however, you may not
assume it will always fit the image exactly. If it's too small, pad it with
NOPs; the Braincopter code must still have the clockwise/counterclockwise turns on either side, though.
You may assume that the Brainf*** input will contain only the eight characters
><+-,.[].
Use the official Braincopter interpreter to test the outputs of your
program or function.
Test cases
Input:

++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.

Example output:

Braincopter output:
Hello World!

Input:

>++++++++++[<++++++++++>-]>>>>>>>>>>>>>>>>++++[>++++<-]>[<<<<<<<++>+++>++++>++++++>+++++++>+++++++>++++>-]<++<+++++<++++++++++<+++++++++<++++++<<<<<<<<<<<<<[>+>+>[-]>>>>[-]>[-]<<<<<<<[>>>>>>+>+<<<<<<<-]>>>>>>[<<<<<<+>>>>>>-]+>---[<->[-]]<[>>>>>>.>.>..<<<<<<<<<<<<+<<[-]>>>>>>-]<<<<<[>>>>>+>+<<<<<<-]>>>>>[<<<<<+>>>>>-]+>-----[<->[-]]<[>>>>>>>>>>.<.<..<<<<<<<<<<<<+<[-]>>>>>-]<+>[-]>[-]>[-]<<<[>+>+>+<<<-]>[<+>-]+>----------[<->[-]]<[<<+>[-]>-]>[-]>[-]<<<<[>>+>+>+<<<<-]>>[<<+>>-]+>----------[<->[-]]<[<<<+>[-]>>-][-]>[-]<<<<<[>>>>+>+<<<<<-]>>>>[<<<<+>>>>-]+>[<->[-]]<[[-]>[-]<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>++++++++[<++++++>-]<.-.[-]][-]>[-]<<<[>>+>+<<<-]>>>[<<<+>>>-]<[>++++++++[<++++++>-]<.[-]][-]>[-]<<[>+>+<<-]>>[<<+>>-]++++++++[<++++++>-]<.[-]]>>>>.<<<<<<<<<<<-]

Output:

Braincopter output:
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17...

Input:

>>+[>>[>]>+>,[>>++++[>++++++++<-]>[<<<[>+>+<<-]>[<+>-]>[<<->>[-]]>-]<<<<->[<+>-[<->-[-[-[-[-[-[-[-[-[<+>-[-[-[-[<->-[-[-[-[-[-[-[-[-[-[-[-[-[<+>-[<->-[<+>-[<->>>+++[>+++++++++<-]>+[<<<[>+>+<<-]>[<+>-]>[<<->>[-]]>-]<<<[<+>-[<->-[<+>-[<->[-]]<[-<++>]>]]<[-<+>]>]]<[-<++++++>]>]]]]]]]]]]]]]]]<[-<+++++>]>]<[-<++++++++>]>]<[-<++++>]>]<[-<+++++++>]>]]]]]]]]]]<[-<+++>]>]]<[-<<[<]<->>[>]>]>]<[-<<[<]<->>[>]>]<<[<]<]>>[>]>>>>>>+<<<<<<<[<]>[[<<[<]<<+>+>>[>]>-]<<[<]<[>>[>]>+<<[<]<-]+<-[-[-[-[-[-[-[->->>[>]>[>]>>>>>[>[>>]>>>]>>[<<<<+>>+>>-]<<[>>+<<-]>>>[<<<<+>+>>>-]<<<[>>>+<<<-]<[->>>>>[<<<<<+>+>>>>-]<<<<[>>>>+<<<<-]<[<++++++++++>-]]>>>>>>[<<<<<<+>+>>>>>-]<<<<<[>>>>>+<<<<<-]<[->>>>>>>[<<<<<<<+>+>>>>>>-]<<<<<<[>>>>>>+<<<<<<-]<[<<++++++++++[>++++++++++<-]>>-]]<.[-]<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]<[<]<<]>[->>[>]>[>]>>>>>[>[>>]>>>]>[>>]<<[->[-]>>>>[<<+>>->[<<+>>->[<<+>>-]>]>>>]<<<<<<<[<<]>[<<<<<[<<]>]>[>>]<<]>>>>>[>[>>]>>>]<<<<<[<<]>[>[>>]<<[->>+<[>>+<<-]<<<]>->>+<<<<<<<[<<]>]>+>>>>>[>[>>]>>>]>,[>+>+<<-]>[<+>-]>[[>+>+<<-]>>[<<+>>-]<[-<->[-<->[-<->[-<->[-<->[-<->[-<->[-<->[-<->[[-]<-><<<---------->+>>]]]]]]]]]]<]<[>+>+<<-]>[<+>-]>[-[-[-[-[-[-[-[-[-[-<<---------->+>[-[-[-[-[-[-[-[-[-[[-]<<---------->+>]]]]]]]]]]]]]]]]]]]]<<[>>+>+<<<-]>>[<<+>>-]+>[<<<+>>->[-]]<[-<[>+>+<<-]>[<+>-]>[<<<+>>>[-]]<]<[>+>+<<-]>[<+>-]>[<<+>>[-]]<<<<+[-[<<<<<<[<<]>[<<<<<[<<]>]>[>>]<+>>>>[>[>>]>>>]>-]>[>]<[[>+<-]<]<<<<<<[<<]>[>[>>]<<[>[>>+<<-]>+<<-<<]>->>+<<<<<<<[<<]>]>[>>]+>>>>>[>[>>]>>>]>]<<<<<<[<<]>[<<<<<[<<]>]>[>>]<<->>>>>[<<+>>->[<<+>>->[<<+>>-]>]>>>]<<<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]+>[>>]>>>[-]>[-]+<<<<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]+<<<<<[<<]>-<<<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]>[->[<<<[<<]<<+>+>>>[>>]>-]<<<[<<]<[>>>[>>]>+<<<[<<]<-]+<[[-]>->>>[>>]>-<+[<<]<<]>[->>>[>>]>+++++++++<<<[<<]<]>>>[>>]+>>]<<-<<<<[>>>>+>+<<<<<-]>>>>[<<<<+>>>>-]>[-<<[>+>+<<-]>[<+>-]>>+<[[-]>-<]>[-<<<<->[-]>>>>[<<+>>->[<<+>>->[<<+>>-]>]>>>]<<<<<<<[<<]>[<<<<<[<<]>]>[>>]>>]<]<<<[<<]<<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]>>+<[->[<<<[<<]<<+>+>>>[>>]>-]<<<[<<]<[>>>[>>]>+<<<[<<]<-]<[-[-[-[-[-[-[-[-[-[->>>>[>>]>[-]>[-]+>+<<<<<[<<]<<]]]]]]]]]]>>>>[>>]+>>]>[-<<<[<<]<<+>+>>>[>>]>]<<<[<<]<[>>>[>>]>+<<<[<<]<-]<[->>>>[>>]>[>[>>]<<[>[>>+<<-]>+<<-<<]>->>+>[>>]>]<<<[<<]>[<<<<<[<<]>]<<<]<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]>[>>]>>>[>[>>]>>>]>+[<<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]<[>+<-]>[<<[<]<<+>+>>[>]>-]<<[<]<[>>[>]>+<<[<]<-]+<-[-[>-<[-]]>[->>[>]>[>]>>>>>[>[>>]>>>]>[>>]>>>[>[>>]>>>]>[>]+[<]<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]>[>>]>>>[>[>>]>>>]>[>]<-<[<]<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]<[<]<]>>[>]>[>]>>>>>[>[>>]>>>]>[>>]>>>[>[>>]>>>]>]<<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]>>[<<<+>+>>-]<<[>>+<<-]>>>[<<<<+>+>>>-]<<<[>>>+<<<-]<<+>[[-]<-<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]>[>]>>>>>[>[>>]>>>]<]<[->>>[>>]>>>[>[>>]>>>]>+[<<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]>[<<[<]<<+>+>>[>]>-]<<[<]<[>>[>]>+<<[<]<-]+<-[-[>-<[-]]>[->>[>]>[>]>>>>>[>[>>]>>>]>[>>]>>>[>[>>]>>>]>[>]<-<[<]<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]<[<]<]<]>[->>[>]>[>]>>>>>[>[>>]>>>]>[>>]>>>[>[>>]>>>]>[>]+[<]<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]<[<]<]>>[>]>[>]>>>>>[>[>>]>>>]>[>>]>>>[>[>>]>>>]>]<<<<<<[<<]>[<<<<<[<<]>]<<<<<[<<]>[<<<<<[<<]>]<<[<]>[<+>-]>[>]>>>>>[>[>>]>>>]<<]<<<[<<]>[<<<<<[<<]>]<<[<]<[<]<]>>[>]>]

Output:

Braincopter output:
This is a Brainf*** self-interpreter. It separates code from input by !;
for example, the input ,[.,]!Hello, World!\0 will output Hello, World!,
assuming the \0 was replaced by a null byte.
Scoring
This is code-golf, so the shortest answer wins. Happy golfing!

It seems that Braincopter makes art. Real art.

Python, 664 656
usage : python snippet.py image.png <bf script>
R=range;_=R(256);a=abs
def C(c):R,G,B=c;return'><+-.,[]RLN'[(65536*R+256*G+B)%11]
def D(c,d):R,G,B=c;F,V,H=d;return a(R-F)+a(G-V)+a(B-H)
def E(c1,i):return min([(c,D(c1,c))for c in[(r,g,b)for r in _ for g in _ for b in _]if C(c)==i],key=lambda x:x[1])[0]
def B(b,w,h):
 x,y,d=0,0,1
 for c in(b[0]+'R'.join(['L'+s for s in[s[::-1]if i%2 else s for i,s in enumerate([(b[1:]+'N'*w*h)[q:q+w-2]for q in R(0,w*h,w-2)])]])[1:])[:w*h][:-1]+'N':
  yield c,(a(x),y)
  x+=d
  if c=='R':x=0;y+=1;d*=-1
import sys
from PIL import Image
I=Image.open(sys.argv[1]).convert('RGB')
W,H=I.size
P=I.load()
for i,p in B(sys.argv[2],W,H):P[p]=E(P[p],i)
I.save(sys.stdout,"PNG")

explanations to come ...


text:
Inverse permutation index
Introduction
The lexicographical permutations of a list with n elements can be numbered from 0 to n! - 1. For example, the 3! = 6 permutations of (1,2,3) would be (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).
When a permutation is applied to a list, its elements are ordered in the same order as the numbers in the permutation. For example, applying the permutation (2,3,1) to l = (a,b,c) yields (l[2],l[3],l[1]) = (b,c,a).
The inverse of a permutation is defined as the permutation that reverses this operation, i.e. applying a permutation and then its inverse (or vice versa) does not modify the array. For example, the inverse of (2,3,1) is (3,1,2), since applying that to (b,c,a) yields (a,b,c).
Also, a permutation's inverse applied to the permutation itself yields the integers 1…n. For example, applying (3,1,2) to (2,3,1) yields (1,2,3).
We now define the function revind(x) as the index of the inverse permutation of the permutation with index x. (This is A056019, if you're interested.)
Since a permutation with index i only modifies the last k items of the list iff 0 ≤ i < k!, we can add any number of elements to the start of the list without affecting revind(i). Therefore the length of the list does not affect the result.
Challenge
Your task is to implement revind(x). You will write a full program or function that takes a single nonnegative integer x as input/argument and outputs/returns the result as a single nonnegative integer.
The input and output may be 0-indexed or 1-indexed, but this must be consistent between them.
Builtins that generate permutations by index, return the index of a permutation or find the inverse permutation are banned. (Builtins that generate all permutations or the next permutation are allowed.)
Standard code-golf rules apply.
Examples
The examples below are 0-indexed.
Input    Output
0        0
1        1
2        2
3        4
4        3
5        5
6        6
13       10
42       51
100      41
1000     3628
2000     3974
10000    30593
100000   303016

Reference implementation (Python 3)
def revind(n):
    from math import factorial
    from itertools import permutations, count
    l = next(filter(lambda x: factorial(x) > n, count(1)))
    pms = list(permutations(range(l)))
    return [k for k in range(len(pms)) if tuple(pms[n][i] for i in pms[k]) == pms[0]][0]

The scatter plot looks quite funny. :)

I had to look up the definition of inverse permutation to understand this challenge. I find your example with (a,b,c) extremely unclear. Please include a proper explanation of what an inverse permutation is.

@Fatalize This is kinda hard to explain simply. Better now?

Jelly has the atom Ụ (grade up) which sorts the indices of an array by their corresponding values. This happens to invert a permutation of 1, …, n, but it doesn't work for other permutations. Is Ụ a forbidden built-in?

@Dennis Hard question. Technically, it finds the inverse of any permutation after it's been applied to any strictly increasing list. Therefore I'm going to say not allowed. (If someone strictly disagrees, feel free to comment. I may change this if the community so desires.)

Jelly, 6 bytes
ịŒ!⁺iR

I/O uses 1-based indexing. Very slow and memory-hungry.
Verification
As long as the input does not exceed 8! = 40320, it is sufficient to consider all permutations of the array [1, …, 8]. For the last test case, the permutations of [1, …, 9] suffice.
With slightly modified code that only considers the permutations of the first 8 or 9 positive integers, you can Try it online! or verify all remaining test cases.
How it works
ịŒ!⁺iR  Main link. Argument: n

 Œ!     Yield all permutations of [1, ..., n].
ị       At-index; retrieve the n-th permutation.
   ⁺    Duplicate the Œ! atom, generating all permutations of the n-th permutation.
     R  Range; yield [1, ..., n].
    i   Index; find the index of [1, ..., n] in the generated 2D array.

Alternate approach, 6 bytes (invalid)
Œ!Ụ€Ụi

It's just as long and it uses the forbidden grade up atom Ụ, but it's (arguably) more idiomatic.
By prepending 8 (or 9 for the last test case), we can actually Try it online!
How it works
Œ!Ụ€Ụi  Main link. Argument: n

Œ!      Yield all permutations of [1, ..., n].
  Ụ€    Grade up each; sort the indices of each permutation by the corresponding
        values. For a permutation of [1, ..., n], this inverts the permutation.
    Ụ   Grade up; sort [1, ..., n!] by the corresponding inverted permutations
        (lexicographical order).
     i  Index; yield the 1-based index of n, which corresponds to the inverse of
        the n-th permutation.

Mathematica, 74 bytes
Max@k[i,Flatten@Outer[i=Permutations[j=Range@#];k=Position,{i[[#]]},j,1]]&

Uses 1-indexing. Very inefficient. (uses ~11GB of memory when the input is 11)
Explanation
j=Range@#

Generate a list from 1 to N. Store that in j.
i=Permutations[...]

Find all permutations of j. Store that in i.
k=Position

Store the Position function in k. (to reduce byte-count when using Position again)
Flatten@Outer[...,{i[[#]]},j,1]

Find the inverse permutation of the N-th permutation.
Max@k[i,...]

Find the k (Position) of the inverse permutation in i (all permutations)
Using built-ins, 46 43 bytes
a[(a=Ordering)/@Permutations@Range@#][[#]]&

1-indexed.

"Builtins that ... find the inverse permutation are banned"

@GregMartin, ah, I somehow missed that part and only saw the "return the index of a permutation" part. Silly me... The new code doesn't have that issue.

yep, I agree it was easy to miss. 74 bytes—still pretty impressive!

05AB1E, 14 13 bytes
Very memory inefficient. Now even more memory inefficient (but 1 byte shorter).
0-based range.
Uses CP-1252 encoding.
ƒ¹ÝœD¹èNkˆ}¯k

Try it online!
or as a Modified test suite
Explanation
ƒ               # for N in range[0 .. x]
 ¹ÝœD           # generate 2 copies of all permutations of range[0 .. x]
     ¹è         # get permutation at index x
       Nkˆ      # store index of N in that permutation in global list
         }      # end loop
          ¯k    # get index of global list (inverse) in list of permutations

MATL, 15 bytes
:Y@tGY)Z)G:=!Af

Input and output are 1-based.
Similar to @MartinEnder's CJam answer, but finds the inverse permutation by composing all possible permutations with that specified by the input, and seeing which has become the identity permutation.
It runs out of memory in the online compiler for input 10.
Try it online!
Explanation
:      % Implicitly input N. Push range [1 2 ... N]
Y@     % Matrix witll all permutations of size N. Each permutation is a row
tGY)   % Duplicate. Get the N-th row
Z)     % Use that as a column index into the matrix of all permutations
G:=    % Compare each row with [1 2 ... N]
!Af    % Find index of the row that matches. Implicitly display

Pyth, 12 bytes
xJ.phQxL@JQh

Test suite
0 indexed.
Explanation:
xJ.phQxL@JQh
xJ.phQxL@JQhQ    Implicit variable introduction
                 Q = eval(input())
  .phQ           Form all permutations of range(Q+1), namely [0, 1, .. Q]
 J               Save to J.
        @JQ      Take the Qth element of J.
      xL   hQ    Map all elements of [0, 1, ..., Q] to their index in above
x                Find the index in J of the above.

CJam, 16 bytes
ri_)e!_@=_$\f#a#

Indices are 0-based.
Try it online!
I doesn't get a lot more inefficient than this... runs out of memory with Java's default settings for inputs greater than 8 (but works in principle for arbitrary inputs given a sufficient number of universes of time and memory).
Explanation
ri    e# Read input and convert to integer N.
_)e!  e# Duplicate N, get all permutations of [0 1 ... N].
_@=   e# Duplicate permutations, get the Nth permutation.
_$    e# Duplicate and sort to get the sorted range [0 1 ... N].
\f#   e# For each of these values, get its index in the Nth permutation.
      e# This inverts the permutation.
a#    e# Find the index of this new permutation in the list of all permutations.

GAP, 108 bytes
h:=l->n->PositionProperty(l,p->l[n]*p=());
f:=n->h(Set(SymmetricGroup(First([1..n],k->Factorial(k)>=n))))(n);

1-indexed. Newlines not counted, they are not needed. I don't really have to assign the final function to a name, but ...
h is a curried function taking a list of permutations and an index into that list and returning the index of the inverse permuation. Without restrictions, I'd just do Position(l,l[n]^-1). f calls that function with the sorted permutations of a big enough symmetric group and the given n.
I could just write SymmetricGroup(n), then the function could be computed for values up to 9. Since there are already much smaller solutions, I prefer to be able to do this:
gap> f(100001);
303017

A really efficient 0-indexed solution that works for arguments below 99! (and can be made to work for arguments below 999! at the cost of one byte) is this one:
f:=function(n)
 local m,l,p,i,g;
 m:=First([1..99],k->Factorial(k)>n);
 g:=List([m-1,m-2..0],Factorial);
 l:=[1..m];
 p:=[];
 for i in g do
  Add(p,Remove(l,QuoInt(n,i)+1));
  n:=n mod i;
 od;
 return Sum(ListN(List([1..m],i->Number([1..Position(p,i)],j->p[j]>i)),g,\*));
end;

After deleting whitespace, this has 255 bytes.

Nice work! I hoped to get some efficient solutions too.

J, 55 50 bytes
g=:/:~i.@#
[:(#\.#.+/@(<{.)\.)@g(-i.)@>:g@g@,/@#:]

Based on the J essay on Permutation Index.
This code only requires memory on the order of n but uses more time since it sorts the list n times and searches it n times for each index.
Using the builtin /: which is able to find the grade of a list and the inverse of a permutation, there is a 42 byte solution that is more efficient.
[:(#\.#.+/@(<{.)\.)@/:(-i.)@>:/:@/:@,/@#:]

This version only requires 44 seconds to compute the last test case when compared against the other which requires 105 seconds.
Usage
   g =: /:~i.@#
   f =: [:(#\.#.+/@(<{.)\.)@g(-i.)@>:g@g@,/@#:]
   (,.f"0) 0 1 2 3 4 5 6 13 42 100 1000 2000 10000
    0     0
    1     1
    2     2
    3     4
    4     3
    5     5
    6     6
   13    10
   42    51
  100    41
 1000  3628
 2000  3974
10000 30593
   timex 'r =: f 100000'
105.787
   r
303016

+1 for memory efficiency that golfing languages can't touch.

JavaScript (ES6), 163 120 110 bytes

f=(n,a=[],i=0,r=0,[j,...b]=a)=>n?a.splice(n%-~i,0,i)|f(n/++i|0,a,i):i?f(n,b,i-1,b.reduce((r,k)=>r+=k>j,r*i)):r
<input type=number min=0 oninput=o.textContent=f(+this.value)><pre id=o>

0-indexed. Works by converting the index to a permutation, inverting it, then converting back to an index. Edit: Saved about 25% by making f invert and reverse the permutation, then making g convert the reversed permutation back to an index. Saved a further 10 bytes by combining the two recursive calls into a single function. Ungolfed:
function index(n) {
    var a = [0];
    for (var i = 1; n = Math.floor(n / i); i++) {
        var j = i - n % (i + 1);
        for (var k = 0; k < i; k++) {
            if (a[k] > j) a[k]++;
        }
        a.push(j);
    }
    a = [...a.keys()].map(k => a.indexOf(k));
    while (i) {
        n *= i--;
        j = a.pop();
        for (k = 0; k < i; k++) {
            if (a[k] > j) n++;
        }
    }
    return n;
}

@JonathanAllan Sorry, I thought I'd spotted a last-second 9-byte saving but I failed to test it thoroughly. I've reverted back to my previous version.

Very swish implementation now.

@JonathanAllan Turns out to be even more swish if I get f to invert the permutation instead of g...

Jelly, 14 13 9 bytes
-4 bytes thanks to @Dennis (which he golfed further using the quick ⁺ in his answer)
Œ!ịịŒ!$iR

Another very slow implementation.
1-based indexing employed here, so expected results are:
input:  1 2 3 4 5 6 7 8  9 10 11
output: 1 2 3 5 4 6 7 8 13 19  9

No point in even putting up an online IDE link, as TIO kills at an input of 10. Local results (last is very slow and required a tonne of memory!):
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 1
1
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 2
2
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 3
3
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 4
5
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 5
4
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 6
6
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 7
7
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 8
8
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 9
13
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 10
19
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 11
9

How?
Œ!ịịŒ!$iR - Main link 1: n
      $   - last two links as a monad
    Œ!    -     permutations of implicit range [1,2,3,...,n]
   ị      -     value at index n (the nth permutation)
Œ!        - permutations of implicit range [1,2,3,...,n]
  ị       - value at index (the indexes of the permuted values in the nth permutation)
       i  - index of
        R - range [1,2,3,...,n]

Note: no need to sort the permutations as we are using the same ordering for both finding the permutation and and it's inverse.

Can't test it from my phone, but couldn't you get rid of link 2 and make the main one ÇịịÇ$iR?

Actually, the R before Œ! is implicit, so Œ!ịịŒ!$iR should do the job.

Yeah, this was a very rushed entry before meeting friends.

Python 2, 116 114 bytes
from itertools import*
def f(n):r=range(n+1);l=list(permutations(r));print l.index(tuple(l[n].index(v)for v in r))

repl.it
0-based. Slow and memory hungry but short on bytes.

Using no permutation functions; both memory and time efficient. 289 285 bytes
-4 bytes thanks to @Christian Sievers (full permutation already formed)
h=lambda n,v=1,x=1:v and(n>=v and h(n,v*x,x+1)or(v,x-1))or n and h(n-1,0,n*x)or x
i=lambda p,j=0,r=0:j<len(p)and i(p,j+1,r+sum(k<p[j]for k in p[j+1:])*h(len(p)-j-1,0))or r
def f(n):t,x=h(n);g=range(x);o=g[:];r=[];exec"t/=x;x-=1;r+=[o.pop(n/t)];n%=t;"*x;return i([r.index(v)for v in g])

I know it's code golf but I think @Pietu1998 is interested in efficient implementations also.
See it in action at repl.it
While this uses more bytes than the reference implementation comparing for n=5000000:
ref:    6GB 148s
this: 200KB <1ms

f is the reverse index function.
f first gets the next factorial above n, t, and the integer whose factorial that is, x by calling h(n), and sets g=range(x), the items that will make up the permutation, o=g[:], and the permutation holder, r=[]
Next it constructs the permutation at index n by poping the indexes of the factorial base representation of n in turn from the items, o, and appending them to r. The factorial base representation is found by div and mod of n with t where t is div'd by x and x decrements down to 1.
Finally it finds the index of the reverse permutation by calling i with the reverse permutation, [r.index(v)for v in g]
h is a dual-purpose function for either calculating a factorial of a non-negative integer or calculating both the next factorial above a non-negative integer and the integer that makes that factorial.
In it's default state v=1 and it does the latter by multiplying v by x (also initially 1) and incrementing x until n is at least as big, then it returns v and x-1 in a tuple.
To calculate n! one calls h(n,0) which multiples x (initially 1) by n and decrements n until n is 0 when it returns x.
i provides the lexicographical index of a permutation, p, of the items [0,1,...n] by adding up the products of the factorial of the factorial base of each index, h(len(p)-j-1,0), and how many items to the right of the index are less than the value at that index, sum(k<p[j]for k in p[j+1:]).

I think you don't need to special case the last item when constructing the permutation. I didn't in my 255 byte GAP solution.

I add it separately at the end because otherwise there would be a divide by zero error when it does t/=x.

Took me a while to see: the loop already does it all, you can replace (r+o) by r.

Uh, you are right! Thank you so much.

Python 2, 130 129 bytes
p=lambda x,k,j=1:x[j:]and p(x,k/j,j+1)+[x.pop(k%j)]
n=input();r=range(n+2);k=0
while[p(r*1,n)[i]for i in p(r*1,k)]>r:k+=1
print k

Actually, 18 11 bytes
This answer uses the algorithm in Dennis' Jelly answer but is 0-indexed. Golfing suggestions welcome! Try it online!
4╞r;)╨E╨♂#í

Ungolfing
      Implicit input n.
4╞    Push 4 duplicates of n. Stack: n, n, n, n
r;)   Push the range [0...n], and move a duplicate of that range to BOS for later.
╨E    Push the n-length permutations of [0...n] and get perm_list[n].
        Stack: perm_list[n], n, [0...n]
╨     Push the n-length permutations of perm_list[n].
♂#    Convert every "list" in the zip to an actual list.
        Stack: perm(perm_list[n]), [0...n]
í     Get the index of [0...n] in the list of permutations of perm_list[n].
      Implicit return.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
A game of atomic proportions
Your task make a bot that plays Atomas, with the highest score.
How the game works:
The gameboard starts with a ring of 6 "atoms", with numbers ranging from 1 to 3. You can "play" an atom between two atoms, or on another atom, depending on the atom itself.
You can either have a normal atom, or a special atom.
The normal atom:
You can play a normal atom between any two available atoms on the board.
You start off with atoms in the range 1 to 3, but the range increases by 1 once every 40 moves (so after 40 moves, the range becomes 2 to 4).
If there are atoms on the board that are lower than the range, it has a 1 / no. of atoms of that number on the board chance of spawning.
Let's say you have a 2 to play, and the board looks like this:
   1 1 2 1

Let's place the 2 to the right of the 1.
The board now becomes:
   1 1 2 1 2

Note: the board wraps around, so the 1 on the far left is actually next to the 2 on the far right. This will be important later.
There are 4 types of "special" atoms, and they are:
The + atom:
This atom is played between two atoms. It has a 1 in 5 chance of spawning.
If the atoms on both sides of the + atom are the same, fusion occurs. Here's how it works:
The two atoms fuse together to create an atom one higher.
(So, two 3 atoms fuse together to form one 4 atom.)
While the atoms on both sides of the fused atom are equal:
    If the atoms on the side >= the fused atom:
        The new fused atom = the old fused atom's value + 2.
    If the atoms on the side < the fused atom:
        The new fused atom = the old fused atom's value + 1.

Example:
   1 1 3 2 2 3  (the 1 on the left-hand side "wraps back"
                 to the 3 on the right-hand side)

Let's use the + on the two 2's in the middle.

-> 1 1 3 3 3    (the two 2's fused together to make a 3)
-> 1 1 5        (the two 3's fused with the 3, and because 3 >= 3,
                 the new fused atom = 3 + 2 = 5)
-> 6            (the two 1's fused with the 5, since the board wraps,
                 and because 1 < 5, the new fused atom = 5 + 1 = 6)

Because the atoms on the sides of the 6 don't exist, fusion stops,
and the board is now [6].

If the atoms on both sides of the + atom are different, then the + stays on the board.
Example:
   1 3 2 3 1 1

Let's use the + on the 2 and 3 in the middle.

-> 1 3 2 + 3 1 1 (2 != 3, so the + stays on the board)

The - atom:
This atom is played on another atom. It has a 1 in 10 chance of spawning.
The - atom removes an atom from the board, and gives you a choice to either:

play the removed atom next round, or
turn it into a + atom to play next round.

Example:
   1 3 2 3 1 1

Let's use the - on the left-hand 2.

-> 1 3 3 1 1    (the 2 is now removed from the board)

Let's turn it into a +, and place it in between the 3's.

-> 1 4 1 1      (the two 3's fused together to make a 4)
-> 5 1          (the two 1's fused with the 4, and because 1 < 4,
                 the new fused atom = 4 + 1 = 5)

The black + atom (B):
This atom is played between 2 atoms. It has a 1 in 80 chance of spawning, and only spawns once your score > 750.
This atom is basically the same as the + atom, except that it fuses any two atoms together, even +'s. From then on, it follows the + rule (it only fuses atoms together if the atoms on both sides of the fused atom are equal).
The fused atom as a result of the black + is equal to:

the higher number atom in the fusion + 3
4 if the two fused atoms are +'s

Example:
   1 3 2 1 3 1

Let's use the black + on the 2 and 1 in the middle.

-> 1 3 5 3 1    (the 2 and 1 fused together to make a 2 + 3 = 5)
-> 1 6 1        (+ rule)
-> 7            (+ rule)

Another example:
   2 + + 2

Let's use the black + on the two +'s.

-> 2 4 2        (the two +'s fused together to make a 4)
-> 5            (+ rule)

The clone atom (C):
This atom is played on another atom. It has a 1 in 60 chance of spawning, and only spawns once your score > 1500.
The clone atom allows you to choose an atom, and play it next round.
Example:
   1 1 2 1

Let's use the clone on the 2, and place it to the right of the 1.

-> 1 1 2 1 2

Here is my build of the game, in Python 2:
import random
import subprocess

logs='atoms.log'
atom_range = [1, 3]
board = []
score = 0
move_number = 0
carry_over = " "
previous_moves = []

specials = ["+", "-", "B", "C"]

def plus_process(user_input):
    global board, score, previous_moves, matches
    previous_moves = []
    matches = 0

    def score_calc(atom):
        global score, matches
        if matches == 0:
            score += int(round((1.5 * atom) + 1.25, 0))
        else:
            if atom < final_atom:
                outer = final_atom - 1
            else:
                outer = atom
            score += ((-final_atom + outer + 3) * matches) - final_atom + (3 * outer) + 3
        matches += 1

    if len(board) < 1 or user_input == "":
        board.append("+")
        return None
    board_start = board[:int(user_input) + 1]
    board_end = board[int(user_input) + 1:]
    final_atom = 0
    while len(board_start) > 0 and len(board_end) > 0:
        if board_start[-1] == board_end[0] and board_end[0] != "+":
            if final_atom == 0:
                final_atom = board_end[0] + 1
            elif board_end[0] >= final_atom:
                final_atom += 2
            else:
                final_atom += 1
            score_calc(board_end[0])
            board_start = board_start[:-1]
            board_end = board_end[1:]
        else:
            break
    if len(board_start) == 0:
        while len(board_end) > 1:
            if board_end[0] == board_end[-1] and board_end[0] != "+":
                if final_atom == 0:
                    final_atom = board_end[0]
                elif board_end[0] >= final_atom:
                    final_atom += 2
                else:
                    final_atom += 1
                score_calc(board_end[0])
                board_end = board_end[1:-1]
            else:
                break
    if len(board_end) == 0:
        while len(board_start) > 1:
            if board_start[0] == board_start[-1] and board_start[0] != "+":
                if board_start[0] >= final_atom:
                    final_atom += 2
                else:
                    final_atom += 1
                score_calc(board_start[0])
                board_start = board_start[1:-1]
            else:
                break
    if matches == 0:
        board = board_start + ["+"] + board_end
    else:
        board = board_start + [final_atom] + board_end
        for a in range(len(board) - 1):
            if board[a] == "+":
                if board[(a + 1) % len(board)] == board[a - 1]:
                    board = board[:a - 1] + board[a:]
                    plus_process(a)
                    break

def minus_process(user_input, minus_check):
    global carry_over, board
    carry_atom = board[int(user_input)]
    if user_input == len(board) - 1:
        board = board[:-1]
    else:
        board = board[:int(user_input)] + board[int(user_input) + 1:]
    if minus_check == "y":
        carry_over = "+"
    elif minus_check == "n":
        carry_over = str(carry_atom)

def black_plus_process(user_input):
    global board
    if board[int(user_input)] == "+":
        if board[int(user_input) + 1] == "+":
            inter_atom = 4
        else:
            inter_atom = board[int(user_input) + 1] + 2
    else:
        if board[int(user_input)] + 1 == "+":
            inter_atom = board[int(user_input)] + 2
        else:
            inter_list = [board[int(user_input)], board[int(user_input) + 1]]
            inter_atom = (inter_list.sort())[1] + 2
    board = board[int(user_input) - 1:] + [inter_atom] * 2 + board[int(user_input) + 1:]
    plus_process(int(user_input) - 1)

def clone_process(user_input):
    global carry_over
    carry_over = str(board[int(user_input)])

def regular_process(atom,user_input):
    global board
    if user_input == "":
        board.append(random.randint(atom_range[0], atom_range[1]))
    else:
        board = board[:int(user_input) + 1] + [int(atom)] + board[int(user_input) + 1:]

def gen_specials():
    special = random.randint(1, 240)
    if special <= 48:
        return "+"
    elif special <= 60 and len(board) > 0:
        return "-"
    elif special <= 64 and len(board) > 0 and score >= 750:
        return "B"
    elif special <= 67 and len(board) > 0 and score >= 1500:
        return "C"
    else:
        small_atoms = []
        for atom in board:
            if atom not in specials and atom < atom_range[0]:
                small_atoms.append(atom)
        small_atom_check = random.randint(1, len(board))
        if small_atom_check <= len(small_atoms):
            return str(small_atoms[small_atom_check - 1])
        else:
            return str(random.randint(atom_range[0], atom_range[1]))

def specials_call(atom, user_input):
    specials_dict = {
        "+": plus_process,
        "-": minus_process,
        "B": black_plus_process,
        "C": clone_process
    }
    if atom in specials_dict.keys():
        if atom == "-":
            minus_process(user_input[0], user_input[1])
        else:
            specials_dict[atom](user_input[0])
    else:
        regular_process(atom,user_input[0])

def init():
    global board, score, move_number, carry_over, previous_moves
    board = []
    score = 0

    for _ in range(6):
        board.append(random.randint(1, 3))

    while len(board) <= 18:
        move_number += 1
        if move_number % 40 == 0:
            atom_range[0] += 1
            atom_range[1] += 1
        if carry_over != " ":
            special_atom = carry_over
            carry_over = " "
        elif len(previous_moves) >= 5:
            special_atom = "+"
        else:
            special_atom = gen_specials()
        previous_moves.append(special_atom)
        bot_command = "python yourBot.py"
        bot = subprocess.Popen(bot_command.split(),
                               stdout = subprocess.PIPE,
                               stdin = subprocess.PIPE)
        to_send="/".join([
            # str(score),
            # str(move_number),
            str(special_atom),
            " ".join([str(x) for x in board])
        ])
        bot.stdin.write(to_send)
        with open(logs, 'a') as f:f.write(to_send+'\n')
        bot.stdin.close()
        all_user_input = bot.stdout.readline().strip("\n").split(" ")
        specials_call(special_atom, all_user_input)

    print("Game over! Your score is " + str(score))

if __name__ == "__main__":
    for a in range(20):
        with open(logs, 'a') as f:f.write('round '+str(a)+'-'*50+'\n')
        init()

How the bot thing works:
Input

Your bot will get 2 inputs: the atom that is currently in play, and the state of the board.
The atom will be like so:

+ for a + atom
- for a - atom
B for a Black + atom
C for a Clone atom
{atom} for a normal atom

The state of the board will be like so:

atom 0 atom 1 atom 2... atom n, with the atoms separated by spaces (atom n wraps back to atom 1, to simulate a "ring" gameboard)

These two will be separated by a /.

Example inputs:
1/1 2 2 3   (the atom in play is 1, and the board is [1 2 2 3])
+/1         (the atom in play is +, and the board is [1] on its own)

Output

You will output a string, depending on what the atom in play is.

If the atom is meant to be played between two atoms:

Output the gap you want to play the atom in. The gaps are like in between each atom, like so:
atom 0, GAP 0, atom 1, GAP 1, atom 2, GAP 2... atom n, GAP N

(gap n indicates you want to place the atom between atom 1 and atom n)
So output 2 if you want to play the atom on gap 2.

If the atom is meant to be played on an atom:

Output the atom you want to play it on, so 2 if you want to play the atom on atom 2.

If the atom is a -:

Output the atom you want to play it on, followed by a space, followed by a y/n choice of turning the atom into a + later, so 2, "y" if you want to play the atom on atom 2, and you want to turn it into a +. Note: this requires 2 inputs, instead of 1.

Example outputs:
(Atom in play is a +)
2   (you want to play the + in gap 2 - between atom 2 and 3)
(Atom in play is a -)
3 y  (you want to play the - on atom 3, and you want to change it to a +)
2 n  (you want to play the - on atom 2, and you don't want to change it)

To make the bot work, you have to go to the Popen bit (at around the end of the code), and replace it with whatever makes your program run as a Pythonic list (so if your program is derp.java, replace ["python", "bot.py"] with ["java", "derp.java"]).

Answer-specific Specs:

Place the entire code of your bot into the answer. If it doesn't fit, it doesn't count.
Each user is allowed to have more than 1 bot, however, they should all be in separate answer posts.
Also, give your bot a name.

Scoring:

The bot with the highest score wins.

Your bot will be tested for 20 games, and the final score is the average of the 20 games.

The tie-breaker will be the time of the upload of the answer.
So your answer will be formatted like this:
{language}, {bot name}
Score: {score}

Good luck!

How does the generated + for a - atom work ? If you chose y will you be guaranteed to get a + on the next move ?

@TonHospel Yes, that's right.

I suggest changing your bot driver so it can handle any standalone program that takes input on STDIN and gives a result on STDOUT. That should give language independence and most languages used on this site can easily do that. Of course this means defining a strict I/O format, e.g. input_atom\natom0 atom1 .... atomn\n for STDIN

@TonHospel Is it okay if I'm asking the bot for an optional input (So, the bot could experience 1 or 2 inputs per turn, depending on the atom)?

Sure, you can make up any protocol you like, but I would avoid it. As soon as you go beyond the trivial input then output you start to have to worry about buffering and deadlock in the communication protocol. Nor do I see the need. Is it for the for the - y case ? Simply call the bot twice then

To be clear, I'm suggesting the standalone bot gets called on every turn, NOT that it is kept running while input and output keep happening. I don't see a need to keep history or even current score in the bot. However the bot should get the move number as input too (to know the placing atom range and when it will change)

Scoring +. The text says You earn 2 * matched atom points for every atom you match, but the code says score += (temp_list_end[0] * 2) + 1 which is 1 more. Which is it ?

The code seems to be able to put + in the element list, but this is nowhere found in the textual description

I love this game! I have it on my phone, and it can be addicting. I gotta say though, it took a while to figure it out completely without a tutorial. Does your implementation use the same scoring method that the game does?

Let us continue this discussion in chat.

Could the code include built-in graphics, or does it have to have an ASCII output?

@JHM It has to be ASCII, I'm afraid.

Ah, I see you made the program able to call external bots. However, you also need to pass the current move number and score on STDIN otherwise the bot cannot predict the chances of each atom happening in the future

@Qwerp-Derp You're using 750 and 1500 as the score requirement for dark pluses and neutrinos, but you don't use Atomas's method of Scoring. It looks like getting to that score may be more difficult than you wanted using your controller. I'm not sure.

Idk if people will spend time creating a solution if the controller isn't improved. I like the question, but not the implementation.

@TonHospel Included.

@mbomb007 I fixed the implementation a bit - there shouldn't be any bugs anymore. If there's anything else I can fix, please tell me.

IMHO, the scoring should be changed. http://atomas.wikia.com/wiki/Score

@mbomb007 Fixed...

The challenge is good, it's just that the work required to create a good answer is pretty high, at least according to my standards. My highscore IRL is Np 93; 129K.

Why the atom_range is not initialized at the init() function?

@mdahmoune It's been half a year since I wrote that code. From what I recall, atom_range is global, and it would be a pain to initialise it at init() (cause global hell).

@mdahmoune 1. Yes, atom_range is supposed to grow over time, spawning elements can change. And for the bot thing, I agree that more variables will help, but the bot honestly doesn't need those elements. Sorry for replying so late.

for atom_range what I try to say, is that when we execute the init() function the second, third,... time, the atom_range is not reset to [1, 3]

@mdahmoune Yeah, good point. I'm on mobile now, though, will fix up the code in the question tomorrow morning. In the meantime, you can edit the controller.

I believe there is a problem with regular_process because it does not add the atom parameter when calling specials_call(atom, user_input), in place it add to the board a random atom.

I built a draft bot that achieve 1500 as score, but the controller crashes just after... I think it du to the "C" atom...

@mdahmoune Can you give me a GitHub Gist to your code? I might have a look at the issue.

Yes of course, just give me the time to clean it..

I think also that your controller does not handle the case where the board is like ... 1 + 2 ... and the bot put 1 between + and 2, the controller does not merge the two 1...

Real behavior controller eg showing the above problem:|1/1 3 3 2 2 2|3/1 3 3 2 2 2 12|3/1 3 3 2 2 2 12 11|+/1 3 3 2 2 2 12 11 13|2/1 4 2 2 2 12 11 13|12/1 4 2 2 2 12 11 13 11|13/1 4 2 2 2 12 11 13 11 13|+/1 4 2 2 2 12 11 13 11 13 11|+/1 4 3 2 12 11 13 11 13 11|1/1 + 4 3 2 12 11 13 11 13 11|11/1 + 11 4 3 2 12 11 13 11 13 11|+/1 12 + 11 4 3 2 12 11 13 11 13 11|+/1 + 12 + 11 4 3 2 12 11 13 11 13 11|1/1 + + 12 + 11 4 3 2 12 11 13 11 13 11|11/1 + 12 + 12 + 11 4 3 2 12 11 13 11 13 11|4/1 + 12 + 12 + 11 4 3 2 12 11 13 11 13 11 13|12/1 + 12 + 12 + 11 4 3 2 12 11 13 11 13 11 13 12

sometime when the draft bot achieves 750 point, the controller crashes, I think we need to cast user_input into int in function named clone_process().

I made a version of Atomas you can play via text input. It'll take you forever to finish a game, though. https://ideone.com/U7ZUnD

Python, draftBot, Score = 889
import random
def h(b):
    s=0
    for x in b:
        try:
            s+=int(x)
        except:
            s+=0
    return s
def d(i):g=i.split("/");a=g[0];b=g[1].split(" ");return(a,b)
def p(a,_,j):
    v=[]
    for x in _:
        try:
            v.append(int(x))
        except:
            v.append(0)
    try:
        v=v[:j+1]+[int(a)]+v[j+1:]
    except:
        v=v[:j+1]+[a]+v[j+1:]
    r1=[[]];b=[x for x in v];m=range(len(b)+1)
    for k in m:
        for i in m:
            for j in range(i):
                c = b[j:i + 1]
                if len(c)%2==0 and c==c[::-1] and 0 not in c:r1.append(c)
        b.insert(0, b.pop())
    q1=max(r1,key=len)
    r2=[[]];b=[x for x in v];m=range(len(b)+1)
    for k in m:
        for i in m:
            for j in range(i):
                c = b[j:i + 1]
                if len(c)>2 and len(c)%2==1 and c==c[::-1] and "+" in c and 0 not in c:r2.append(c)
        b.insert(0, b.pop())
    q2=max(r2,key=h)
    with open('f.log', 'a') as f:f.write('pal '+str(_)+' : '+str(q1)+' : '+str(q2)+'\n')
    if q2!=[]:return 100+h(q2)
    else:return len(q1)
i=raw_input()
(a,b)=d(i)
if a in ['C','B']:print('0')
elif a=='-':print("0 y" if random.randint(0, 1) == 1 else "0 n")
else:q,j=max((p(a,b,j),j)for j in range(len(b)));print(str(j))

I found that the controller:

crashes when score exceeds 1500;
does not properly merge atoms in same cases.

Python, RandomBot, Score = 7.95
Nothing too fancy, just a random bot.
import random

game_input = raw_input().split("/")
current_atom = game_input[0]
board = game_input[1].split(" ")

if current_atom != "-":
    print(random.randint(0, len(board) - 1))
else:
    random_choice = " y" if random.randint(0, 1) == 1 else " n"
    print(str(random.randint(0, len(board) - 1)) + random_choice)

Python, BadPlayer, Score = 21.45
import random

try:
    raw_input
except:
    raw_input = input

game_input = raw_input().split("/")
current_atom = game_input[0]
board = game_input[1].split(" ")

def get_chain(board, base):
    chain = []
    board = board[:]
    try:
        while board[base] == board[base + 1]:
            chain = [board[base]] + chain + [board[base + 1]]
            del board[base]
            del board[base]
            base -= 1
    except IndexError:
        pass
    return chain

def biggest_chain(board):
    chains = []
    base = 0
    i = 0
    while i < len(board) - 1:
        chains.append([i, get_chain(board, i)])
        i += 1
    return sorted(chains, key=lambda x: len(x[1]) / 2)[-1]

def not_in_chain():
    a, b = biggest_chain(board)
    if len(b) == 0:
        print(random.randint(0, len(board) - 1))
    elif random.randint(0, 1) == 0:
        print(random.randint(a + len(b)/2, len(board) - 1))
    else:
        try:
            print(random.randint(0, a - len(b)/2 - 1))
        except:
            print(random.randint(a + len(b)/2, len(board) - 1))

if current_atom in "+B":
    a, b = biggest_chain(board)
    if len(b) == 0:
        print(0)
    else:
        print(a)
elif current_atom == "C":
    not_in_chain()
elif current_atom == "-":
    a, b = biggest_chain(board)
    if len(b) == 0:
        print(str(random.randint(0, len(board) - 1)) + " n")
    elif random.randint(0, 1) == 0:
        print(str(random.randint(a + len(b)/2, len(board) - 1)) + " n")
    else:
        try:
            print(str(random.randint(0, a - len(b)/2 - 1)) + " n")
        except:
            print(str(random.randint(0, len(board) - 1)) + " n")
else:
    not_in_chain()

Just a very bad bot that often make the controller crash

How does it make the controller crash? And if it does, it is a problem with the controller, or your bot?

@mbomb007 I don't recall why it crash, but the crashes were in the controller

This bot should work without any bugs, just alter the code a bit to accommodate for the updated "stdin" thing.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Terminating, Purely Periodic, or Eventually Periodic?
Introduction
A decimal is terminating if it has a finite number of decimal digits. For example, 0.4 (2/5) is terminating because it has one decimal digit.
A decimal is purely periodic if it has an infinite number of decimal digits and has no decimal digits before its repetent (the part of the decimal that repeats.) For example, 0.142857142857142… (1/7) is purely periodic because it has a repetend 142857, which starts repeating immediately after the decimal point.
A decimal is eventually periodic if it has an infinite number of decimal digits and has a finite number of decimal digits before its repetent (the part of the decimal that repeats.) For example, 0.166666666666666… (1/6) is eventually periodic because its repetend 6 starts repeating after a 1.
Your task
Write a program or function that, when given numbers p and q (integers, 0 <= p < q <= 100), will determine if the decimal representation of p/q is terminating, purely periodic, or eventually periodic.
You must output a if it's Terminating (i.e. 0.1), b if it's Purely Periodic (i.e. 0.333...), or c if it's Eventually Periodic (i.e. 0.166...), where a, b, and c are any distinct, constant strings of your choice.
Test cases
0/1 => Terminating
0/2 => Terminating
1/2 => Terminating
0/3 => Terminating
1/3 => Purely Periodic
2/3 => Purely Periodic
0/4 => Terminating
1/4 => Terminating
2/4 => Terminating
3/4 => Terminating
0/5 => Terminating
1/5 => Terminating
2/5 => Terminating
3/5 => Terminating
4/5 => Terminating
0/6 => Terminating
1/6 => Eventually Periodic
2/6 => Purely Periodic
3/6 => Terminating
4/6 => Purely Periodic
5/6 => Eventually Periodic
0/7 => Terminating
1/7 => Purely Periodic
2/7 => Purely Periodic
3/7 => Purely Periodic
4/7 => Purely Periodic
5/7 => Purely Periodic
6/7 => Purely Periodic
0/8 => Terminating
1/8 => Terminating
2/8 => Terminating
3/8 => Terminating
4/8 => Terminating
5/8 => Terminating
6/8 => Terminating
7/8 => Terminating
0/9 => Terminating
1/9 => Purely Periodic
2/9 => Purely Periodic
3/9 => Purely Periodic
4/9 => Purely Periodic
5/9 => Purely Periodic
6/9 => Purely Periodic
7/9 => Purely Periodic
8/9 => Purely Periodic
0/10 => Terminating
1/10 => Terminating
2/10 => Terminating
3/10 => Terminating
4/10 => Terminating
5/10 => Terminating
6/10 => Terminating
7/10 => Terminating
8/10 => Terminating
9/10 => Terminating
0/11 => Terminating
1/11 => Purely Periodic
2/11 => Purely Periodic
3/11 => Purely Periodic
4/11 => Purely Periodic
5/11 => Purely Periodic
6/11 => Purely Periodic
7/11 => Purely Periodic
8/11 => Purely Periodic
9/11 => Purely Periodic
10/11 => Purely Periodic
0/12 => Terminating
1/12 => Eventually Periodic
2/12 => Eventually Periodic
3/12 => Terminating
4/12 => Purely Periodic
5/12 => Eventually Periodic
6/12 => Terminating
7/12 => Eventually Periodic
8/12 => Purely Periodic
9/12 => Terminating
10/12 => Eventually Periodic
11/12 => Eventually Periodic
0/13 => Terminating
1/13 => Purely Periodic
2/13 => Purely Periodic
3/13 => Purely Periodic
4/13 => Purely Periodic
5/13 => Purely Periodic
6/13 => Purely Periodic
7/13 => Purely Periodic
8/13 => Purely Periodic
9/13 => Purely Periodic
10/13 => Purely Periodic
11/13 => Purely Periodic
12/13 => Purely Periodic
0/14 => Terminating
1/14 => Eventually Periodic
2/14 => Purely Periodic
3/14 => Eventually Periodic
4/14 => Purely Periodic
5/14 => Eventually Periodic
6/14 => Purely Periodic
7/14 => Terminating
8/14 => Purely Periodic
9/14 => Eventually Periodic
10/14 => Purely Periodic
11/14 => Eventually Periodic
12/14 => Purely Periodic
13/14 => Eventually Periodic
0/15 => Terminating
1/15 => Eventually Periodic
2/15 => Eventually Periodic
3/15 => Terminating
4/15 => Eventually Periodic
5/15 => Purely Periodic
6/15 => Terminating
7/15 => Eventually Periodic
8/15 => Eventually Periodic
9/15 => Terminating
10/15 => Purely Periodic
11/15 => Eventually Periodic
12/15 => Terminating
13/15 => Eventually Periodic
14/15 => Eventually Periodic

You can find all test cases here.
You are allowed to choose your own 3 values for the output, but it must be clear as to which one it is.
Remember, this is code-golf, so the code with the smallest number of bytes wins.
Hints
Terminating:

 The prime factorization of a terminating decimal's denominator in simplest form consists only of 2s and 5s.

Purely Periodic:

 The prime factorization of a purely periodic decimal's denominator in simplest form does not include any 2s or 5s.

Eventually Periodic:

 The prime factorization of an eventually periodic decimal's denominator in simplest form includes at least one 2 or 5, but also includes other numbers.

Leaderboards
Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.
To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:
# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:
# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:
# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:
# [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=95926,OVERRIDE_USER=12537;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="
"+e.body.replace(OVERRIDE_REG,"")+"
")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
 <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">

Leaderboard

	Author	Language	Size

Winners by Language

Language	User	Score

{{PLACE}}	{{NAME}}	{{LANGUAGE}}	{{SIZE}}	Link

{{LANGUAGE}}	{{NAME}}	{{SIZE}}	Link

@ETHproductions Updated.

Almost duplicate

If I thought it was actually a duplicate, I would have cast a close vote. There's a reason that I used the word "almost".

given a fraction in the form p/q Given how? Can we take numerator and denominator as separate function arguments?

@Dennis Yes, they are separate function arguments

Can we output a non-constant value meeting a specific condition, such as anything falsy for terminating, 1 for purely periodic, and anything greater than 1 for eventually periodic?

@ETHproductions Everything in one group has to output the same thing

What if we get pi (or phi) as our argument???

@EriktheGolfer You don't. You get two integers.

@OliverNi I mean, like a super-approximate fraction, such as 22/7 for π. Can we assume that it's terminating or eventually periodic?

@EriktheGolfer What? Every fraction is either terminating or periodic. 22/7 is purely periodic.

@OliverNi Oh, right. My fault :P

1/13=0.076923076923... In Your definition "A decimal is eventually periodic if it has an infinite number of decimal digits and has a finite number of decimal digits before its repetent (the part of the decimal that repeats.) " would be "eventually periodic" not purery periodic has you show in the test cases...

No, 1/13 is purely periodic because the repetent is '076923'. The 0 repeats with the repetent.

@OliverNi FYI, your hyperlink in the bounty was backwards. It should be [Text Description](URL), in case you didn't know why it didn't work.

That's what i did. It doesn't format in bounties...

Jelly, 10 bytes
:gÆfḍ⁵ṢQ¬Ḅ

Accepts denominator and numerator (in that order) as arguments. Returns 0 for terminating, 1 for purely periodic, and 2 for eventually periodic. Try it online! or verify all test cases.
How it works
:gÆfḍ⁵ṢQ¬Ḅ  Main link. Arguments: d (denominator), n (numerator)

 g          Compute the GCD of d and n.
:           Divide d by the GCD, yielding the denominator of the simplified form.
  Æf        Yield all prime factors of the previous result.
    ḍ⁵      Test 10 for divisibility by each prime factor.
            This yields 1 for 2 and 5, 0 for all other primes.
      Ṣ     Sort the resulting Booleans.
       Q    Unique; deduplicate the sorted Booleans.
        ¬   Logical NOT; replace 0 with 1 and vice versa to yield one of the
            following arrays.
              [    ]  <- no prime factors (denominator 1)
              [   0]  <- only 2 and 5
              [1   ]  <- neither 2 nor 5
              [1, 0]  <- mixed
         Ḅ  Unbinary; convert from base 2 to integer.
            This maps [] and [0] to 0, [1] to 1, and [1, 0] to 2.

JavaScript (ES6), 70 .. 68 53 bytes
f=(a,b,s=[],x)=>a?(s[a]^=a)?f(a*10%b,b,s,x||a):x==a:0

Returns 0 for terminating, true for purely periodic and false for eventually periodic.
How it works
What we're doing here is actually simulating a division by hand:

a?...:0 - If the numerator is zero, we stop here and return 0. The sequence is terminating.
(s[a]^=a)?...:x==a - If we've already encountered this numerator before, it means that the sequence is periodic and is going to repeat forever. We stop here and return either true if a is equal to the first value x of the sequence (purely periodic) or false if it's not (eventually periodic).
f(a*10%b,b,s,x||a) - Else, we multiply the numerator a by 10. We compute the remainder of the division by the denominator b. And we repeat the process by using this remainder as the new numerator. (We also pass a as the first value of the sequence if it's not already stored in x.)

Example

Blue: numerator = 1
Green: denominator = 7
Red: multiplications by 10
Black: remainders
Gray: quotient digits (we don't really care about them here, and the above code is not computing them at all)

Python, 62 61 59 bytes
f=lambda n,d,r=[0,0]:(r[:3]+r).count(n)or f(10*n%d,d,r+[n])

Prints 1 for eventually periodic, 2 for purely periodic, and 4 for terminating.
Verify all test cases on repl.it.

Fascinating! What does *r do?

It unpacks the tuple r. f(1, *(2, 3), 4) is equivalent to f(1, 2, 3, 4).

So this would be 56 bytes in JS: f=(n,d,...r)=>n in r?~(n>0?n==r[0]:2):f(10*n%d,d,...r,n)

My bad, 63 bytes (I forgot that in serves a very different purpose in JS than in Python): f=(n,d,...r)=>~r.indexOf(r)?~(n>0?n==r[0]:2):f(10*n%d,d,...r,n)

@ETHproductions Neat. I guess f=(n,d,...r)=>~(i=r.indexOf(n))?n&&!i:f(10*n%d,d,...r,n) would work as well.

Perl, 49 46 45 bytes
Includes +3 for -p
Based on Dennis's elegant idea but implemented in a perlish way
Give input numbers on STDIN
terminating.pl <<< "2 26"

termninating.pl:
#!/usr/bin/perl -p
/ /;1until$a{$_=$_*10%$' or$`}++;$_=$a{$`}

Prints a 2 if terminating. 1 if periodic and nothing if eventually periodic

All of the numbers in a certain group have to give the same value.

@OliverNi They do now

JavaScript (ES6), 91 88 85 79 75 74 78 bytes
f=(n,d,g=(a,b)=>b?g(b,a%b):a,t=g(d/=c=g(n,d),10))=>n*~-d?t-1?f(n/c,d/t)/0:1:+f

Outputs NaN for terminating, 1 for purely periodic, and Infinity for eventually periodic.
Test snippet

f=(n,d,g=(a,b)=>b?g(b,a%b):a,t=g(d/=c=g(n,d),10))=>n*~-d?t-1?f(n/c,d/t)/0:1:+f

l=(n,d)=>console.log(n+"/"+d+":",f(n,d))

for(i=1;i<10;i++)for(j=0;j<i;j++)l(j,i);

Explanation
First, we divide both n and d by gcd(d,n), to reduce the fraction to its simplest form. This lets us avoid situations like 2/6 where the result would otherwise be calculated as purely periodic. We also define variable t as gcd(d,10); this will be used later.
The first check is whether n is 0 or d is 1. If n*(d-1) is 0, we return +f, or NaN: the fraction is terminating.
The next check is whether t is 1. If so, we return 1: the fraction is purely periodic.
If t is not 1, we divide d by t, run the whole function again, and divide by 0. If n/(d/t) is terminating, this returns NaN/0 = NaN: the fraction is terminating. Otherwise, it returns 1/0 = Infinity: the fraction is eventually periodic.

Where is the reduction to the simplest form ?

@TonHospel Fixed.

@Arnauld I'm not sure what you mean. It returns Infinity for all of those values.

@Arnauld Aw, man, I thought I could get away with never adjusting n... Thanks for pointing that out.

Batch, 247 bytes
@set/af=%1,g=%2
:g
@if not %f%==0 set/ah=g,g=f,f=h%%g&goto g
@set/ae=d=%2/g
:l
@set/ag=-~!(d%%2)*(!(d%%5)*4+1)
@if not %g%==1 set/ad/=g&goto l
@if %d%==1 (echo Terminating)else if %d%==%e% (echo Purely Periodic)else echo Eventually Periodic

Uses my fast gcd10 trick from Fraction to exact decimal. Obviously I could save a bunch of bytes by using a custom output format.

Why don't you just do @if %d%==1 (echo T)else if %d%==%e% (echo P)else echo E to save 42 bytes?

Obviously I could save a bunch of bytes by using a custom output format.

@ETHproductions I think he doesn't want to, as Oliver has noted with a quote.

Mathematica, 41 bytes
Ordering@{d=Denominator@#,GCD[d,10^d],1}&

Outputs {3,1,2} if the input has a terminating decimal expansion, {2,3,1} if the input has a purely periodic decimal expansion, and {3,2,1} if the input has an eventually periodic decimal expansion.
Based on the sneaky trick: if d is the denominator of a fraction in lowest terms, then the greatest common divisor of d and 10^d equals d if d has only 2s and 5s in its prime factorization; equals 1 if d has neither 2s nor 5s in its prime factorization; and equals some integer in between if d has 2s/5s and other primes.
The Ordering function just reports where the smallest, next smallest, and largest elements of the triple are, with ties broken left-to-right.
Flaw: returns the variant output {1,2,3} instead of {3,1,2} if the input is 0.
Mathematica, 46 bytes, perverse
b[a][[Log[d=Denominator@#,GCD[d,10^d]]]][[1]]&

Returns a[[1]] if the input has a terminating decimal expansion, b[[1]] if the input has a purely periodic decimal expansion, and b[a] if the input has an eventually periodic decimal expansion. Throws an error in all cases!
As above, we want to know whether that greatest common divisor equals 1, d, or somewhere in between. The base-d logarithm of that gcd equals 0, 1, or something in between.
Now we start torturing Mathematica. b[a][[n]] denotes the nth part of the expression b[a]. So b[a][[1]] returns a; b[a][[0]] returns b; and b[a][[x]], where x is a number between 0 and 1, makes Mathematica throw the error "Part::pkspec1: The expression x cannot be used as a part specification." and returns b[a][[x]] unevaluated.
This already distinguishes the three cases appropriately, except that the output for the eventually periodic case is b[a][[x]], which is non-constant because x is the actual logarithm of something. So then we apply [[1]] to the outputs already described. Because of how Mathematica internally represents b[a][[x]], the result of b[a][[x]][[1]] is simply b[a]. On the other hand, applying [[1]] to a results in a different error "Part::partd: Part specification a[[1]] is longer than depth of object." and returns a[[1]] unevaluated (and similarly for b).
Flaw: lies about the input 0, returning b[a] instead of a[[1]].

Actually, 15 bytes
This is based on Dennis' Jelly answer. 0 is terminating, 1 is purely periodic, and 2 is eventually periodic. Golfing suggestions welcome. Try it online!
▼Ny9u♀%SR♂b╔2@¿

Ungolfing
      Implicit input [a, b].
▼     Divide a and b by gcd(a,b).
Ny    Get the unique prime divisors of the reduced denominator.
9u    Push 10.
♀%    10 mod every member of uniq_p_d.
SR    Sort the mods and reverse.
♂b    Logical buffer. Converts every (10 % p != 0) to 1, and everything else to 0.
        Meaning if 2 or 5 divided b, they are now 0, and every other prime is now 1.
╔     Uniquify the list.
        If terminating, return [0].
        If purely periodic, return [1].
        If eventually periodic, return [1, 0].
        Else, (if b was 1), return [].
2@¿   Convert from binary to decimal. Return 0, 1, or 2.
      Implicit return.

C 173 Bytes
Takes two integers from stdin, prints 1 for purely periodic, -1 for eventually periodic, and 0 for terminating.
int r;main(_,n,d){_-1?_-2?d-1?d%2&&d%5?r=1:d%2?main(3,n,d/5):main(3,n,d/2),r=r?-1:0:r=0:d?main(2,d,n%d):r=n:scanf("%d %d",&n,&d),main(2,n,d),main(3,n/r,d/r),printf("%d",r);}

Ungolfed:
// returns 1 for periodic, 0 for terminating, <0 for eventually periodic
int periodic(int num, int den) { // 3
    if (den == 1) return 0;
    if (den % 2 && den % 5) // pure periodic
        return 1;
    if (den % 2) return periodic(num,den/5) ? -1 : 0;
    return periodic(num,den/2) ? -1 : 0;
}

int gcd(int num, int den) { // 2
    if (den)
        return gcd(den,num%den);
    return num;
}

int main(n,d) // 1
{
    scanf("%d %d",&n,&d);
    printf("%d",periodic(n/gcd(n,d),d/gcd(n,d)));
    return 0;
}

Half-golfed:
int r;main(_,n,d){
    _-1?
    _-2?
    // periodic
    d-1?
        d%2&&d%5?
            r=1:
                d%2?
                    main(3,n,d/5): //periodic
                    main(3,n,d/2), //periodic
                        r=r?-1:0:
                r=0
    // gcd
    :d?main(2,d,n%d):r=n // gcd
    // main
    :scanf("%d %d",&n,&d),
     main(2,n,d), // gcd
     main(3,n/r,d/r), // periodic
     printf("%d",r);
}

165 bytes

05AB1E, 16 11 bytes
Saved 5 bytes thanks to @Adnan!
¿²r/fTrÖbÙJ

Prints 0 for Purely Periodic, 1 for Terminating, and 10 for Eventually Periodic.
Explanation:
                 # Implicit input
                 # Implicit input
  ¿              # Take GCD of numbers
   ²             # Push top value from input register
    r            # Reverse stack order
     /           # Divide (denominator by GCD)
      f          # Find unique prime factors
       TrÖ       # Test 10 for divisibility
          b      # Convert (True -> 1, False -> 0)
           Ù     # Deduplicate array
            J    # Join chars in array
                 # Implicit print

Input is taken as p newline q.
Try it online!

Nice to see you using 05AB1E :). Osabie also uses implicit input which allows us to remove the first two I's. Furthermore, a constant predefined to 10 is T. Same for 2B, which is b :).

You can also use the input registers, which gives us ¿²r/fTrÖbÙJ as the final code :).

PHP, 126 Bytes
$d=$argv[2];$a[]=$n=$argv[1];while($n%$d&&!$t){$n*=10;$t=in_array($n%=$d,$a);$a[]=$n;}if($a[1]&&$t)$t+=$a[0]!=end($a);echo+$t;

Prints 0 for terminated and 1 for purely periodic
2 for eventually.
Let me explain if a numerator is twice in the array here starts the periodic session
if it is terminated the echo end($a); value is 0
If you not trust me put $t=count($a)>$d?2:0; in the loop
To make it more clear please add
print_r($a); or var_dump($a); or json_encode($a); after the loop
you can see one numerator twice or a zero at the end of the array
if a numerator is twice count the items between the two items and you can get the length of the periodic
and you can see the position by the first numerator where the periodic begins
So after that we can find the position and the length of the periodic sequence with if($t){echo $p=array_search(end($a),$a);echo $l=count($a)-$p-1;}
Visualize the periodic
$d=$argv[2];
$a[]=$n=$argv[1]; #array numerator
$r[]=$n/$d^0; #array result of the division
$r[]=".";
while($n%$d&&!$t){
    $n*=10;
    $n-=$d*$r[]=$n/$d^0;
    $t=in_array($n%=$d,$a); #stop if numerator is twice
    $a[]=$n;
}
if($a[1]&&$t)$t+=$a[0]!=end($a); #periodic term starts directly?
if($t){
    echo $p=array_search(end($a),$a)."\n"; #output the beginning position of the periodic term
    echo $l=count($a)-$p-1; #output the length of the periodic term
    echo "\n";
    echo str_repeat(" ",2+$p).str_repeat("_",$l-1)."\n"; #visualize the periodic term
    #echo join(array_slice($r,0,1+$p)).join(array_slice($r,1+$p))."\n";# if you want only the periodic term
    echo join($r); #result if the division
}
echo+$t; # 0 terminated 1+2 periodic 2 periodic start not directly

Output visualize the periodic term
1/18
   _
0.05

1/12
    _
0.083

1/13
  ______
0.076923

1/14
   ______
0.0714285

An other way with 130 Bytes
$r=bcdiv(($z=$argv)[1],$z[2],400);for($p=2;$i++<200;)if(substr($r,2,$i)==substr($r,2+$i,$i))$p=1;echo strlen(rtrim($r,0))<50?0:$p;

Expanded Version
$r=bcdiv(($z=$argv)[1],$z[2],400); # 100 is the maximal denominator
# we need a string length with the double value of the sum the length from 1 until the denominator
for($p=2;$i++<200;)if(substr($r,2,$i)==substr($r,2+$i,$i))$p=1;
# all results begin with 0.
#take two substrings with the same length after that and comparize both.
#if we found 2 same substrings we have a periodic which starts at the first decimal place
echo strlen(rtrim($r,0))<50?0:$p;
# if we can trim the length of the result we have a terminated result

See also Fraction to exact decimal.

@Neil you mean I should modify the code to answer the other question?

Well, I was just thinking the other question doesn't have a PHP answer; perhaps you would like to provide one.

@RosLuP  For the example 3/53 this array will be create [3,30,35,32,2,20,41,39,19,31,45,26,48,3]

3 / 103 =0.0291262135922330097087378640776699029126213592233009708 and so in the same period can appear the same digit (for example the digit 7 between 00...00 above ) But if the array you speak about is not the one of digit but the array of the {d=10*(d%b)} where the digit is d/c than I think it is ok there is only one value d_i to each period...

@RosLuP okay for your example 3 /103 3%103 gives 3 put this in the array now you multiple with 10. 30%103 gives 30 this is the next value in the array 300%103 gives 94 and so on which results in this output [3,30,94,13,27,64,22,14,37,61,95,23,24,34,31,1,10,100,73,9,90,76,39,81,89,66,42,8,80,79,69,72,102,93,3]

above i would write for a/b d=a, {d=10*(d%b)} and the digit is d/b; for the remain ok for me should be ok for the array of {d}... 3,30, etc... i remember that the period would be a divisor of 102=103-1=p-1 in this case, if b is composite and has one some prime p_i it would be a divisor of p_i-1 [but possibly remeber wrong etc]

@RosLuP the array for 1/647 is one of the worst cases. It contains 647 items. foreach denominator d the worst case that can exists is that the count of the items is d

@JörgHülsermann in http://www.wolframalpha.com/input/?i=1%2F647 if one type 1/647 it result period 646 [646 is a divisor of 647-1 where 647 is a prime number]... yes the worst case i think; but for say the true number a/b with a and b > 100 it seems are out the range of this code golf question...

@Neil I have add an answer to the other question. Not forgotten. Mnay other things to do

Mathematica, 44 bytes
If[ListQ@Last@#,Length@#==1]&@@RealDigits@#&

Returns Null for Terminating, True for purely periodic, and False for eventually periodic.
Explanation
RealDigits

Find the decimal expansion of N. (repeated digits are surrounded by an extra head List {}).
ListQ@Last@#

Check whether the last element of the decimal expansion is a List.
Length@#==1

If the above condition is True, check whether the entire decimal expansion consists of one thing. (A List counts as one entity). (returns True or False)
(If the condition is False, then a Null is returned because there is no third argument for If)

Pyth, 31 27 bytes
AQ={P/HiGH?l@H=j25T?l-HT1Z2

Input
4,12

You can try it here. Prints 1 for eventually periodic, 2 for purely periodic, and 0 for terminating. This is my first time answering in codegolf. Any suggestions are welcome.
Explanation
AQ                                              // 1st element to G and 2nd element to H
    ={P                                         // Assign unique prime factors to H
        /H                                      // Simplify denominator
            iGH                                 // Find GCD
                ?l                              // Check length of filtered H
                    @H                          // Filter H by Y
                        =j25T                   // Assign a set [2,5] to T
                                ?l-HT           // Check length of H - T
                                        1Z2     // Print result

Note that [2,3] filtered by [2,5] = [2] but [2,3,5] - [2,5] = [3].

PARI/GP, 64 bytes
f(x,y)=if(setminus(factor(y=y/gcd(x,y))[,1]~,[2,5]),gcd(y,10)>1)

Outputs nothing for terminating, 0 for purely and 1 for eventually periodic.
Not very fancy, I hoped for something better when I started.


text:
Fill in the grid randomly
Given positive integer n < 10, create a 2 dimensional matrix where each location is filled with its x and y index (starting from the top left).
For example:
Input: 2
00 10
10 11

Input: 3
00 10 20
01 11 21
02 12 22

Once the grid is created, randomly fill each index. This can be with an 'x' or any other way to denote a spot has been filled.
You determine which location to fill by randomly generating indices to fill the matrix. You can only fill n^2 times so you cannot fill as many times as you want until the matrix is completely filled. At the end the matrix must be filled so you must do some work to make sure that you check the random numbers that you use to fill to make sure that spot is not already filled.
Refresh or print after each fill in order to show the progression of the filling iterations.
Example for filling:
Input: 2
00 10
01 11

00 is randomly chosen:
XX 10
01 11

01 is randomly chosen:
XX 10
XX 11

00 is randomly chosen, but since it's already been chosen a re-roll chooses 10:
XX XX
XX 11

11 is randomly chosen:
XX XX
XX XX

Do not print out the random numbers as visually I should be able to see which index was selected. By this I mean do not print "11 is randomly chosen:". It is here for exploratory sake.
Since this is code-golf The shortest code wins.
Have fun and happy golfing!

I don't understand what is so complicated about the instructions which are very clear. "create a 2 dimensional matrix where each location is filled with it's xy index (starting from the top left)" (Not a printable string). "Refresh or print after each fill in order to show the progression of the filling iterations." must show the progression. Why be overly specific when it just narrows how creative users can be with their solutions?

Is n>= 10 possible ? (you have to start to know about the maximum length to properly fill in leading 0's then). The filling for that case is one index at a time, not 1 digit at a time, right ?

@TimmyD I agree that this should have spent more time in the Sandbox simply because that is what the sandbox is for but for me the instructions are pretty clear about what is required. Not a bad challenge IMHO.

@TonHospel Good point. I will edit to ensure n < 10

What's the bonus? And "GUI and black squares" could use some clarification.

"Do not print out the random numbers as visually I should be able to see which index was selected." What does that mean?

@EasterlyIrk In my example I print out each iteration of the matrix being filled. I displayed the numbers that were randomly chosen for reference. They should not be outputted in your solution. i.i "00 is randomly chosen:" should not be displayed.

That could use some clarification then.

This looks much better. I would still take out the references to "The shortest code wins with a bonus if some GUI was used instead of ASCII". It's still undefined.

@carusocomputing nothing, should have been omitted.

@DLosc lets stick with xy so that its more clear what each location is.

What do you mean by 'refresh' in "Refresh or print after each fill in order to show the progression of the filling iterations."

@corvus_192 However you want to display the different iterations of the filling in the of grid. So if you fill in 1, 1. You would display the grid with 1,1 filled. Then if the next is 2, 3 then you would fill 2, 3 and display the new matrix with 1, 1 and 2, 3 filled.

Can we output the indices 1-based instead of 0-based? So for input 2 the indices would be 11,21 12 22 instead of 00,10 01,11. Also, is pretty-printing mandatory, or would an output like [["00","10"],["01","11"]] be allowed as well?

05AB1E, 29 bytes
<ÝDâJU[X¹ä»,XÐÙg#Jþ2ô.R„  :)U

Try it online!
Space chosen as the char for the removed numbers (as it looks nice), but it could be replaced with any char without affecting byte-count.
Explanation
                                # implicit input n
<ÝDâ                            # cartesian product of [0..n-1] and [0..n-1]
    JU                          # join pairs and store in X
      [     XÐÙg#               # loop until there's only spaces left in X
       X¹ä                      # split X into n pieces
          »,                    # join rows by space and columns by newlines and print
                 Jþ             # join X to string and remove all non-digits
                   2ô.R         # split in pieces of 2 and pick a pair at random
                       „  :)    # replace this pair with 2 spaces
                            U   # and store in X

It looks awesome but as I test it, it seems like it doesn't fill every square?

@jacksonecac: As I understood it, I should randomly fill n^2 times, with the possibility of not all squares getting filled if the same index is chosen at random more than one time. If that's wrong I'll have to redo this later (have to run now)

"You determine which location to fill by randomly generating indices to fill the matrix. You can only fill n^2 times so you cannot fill as many times as you want until the matrix is completely filled." So it must be filled. I will clarify more in the description.

@jacksonecac Thanks for the clarification. I've updated the answer accordingly :)

Perfect! Nice job man!

Pip, 41 40 38 36 bytes
35 bytes of code, +1 for the -S flag.
Pm:J_MM ZCGa{ST:mmR:asX2}M$ALmSK{r}

Takes input from cmdline argument. Replaces with space (any other character is possible for +1 byte). Outputs successive iterations separated by a single newline (which is legal but can make it a bit hard to read). Try it online!
All kinds of dirty tricks in this one. Shorter version has fewer dirty tricks. :^( Explanation:
Pm:J_MM ZCGa{ST:mmR:asX2}M$ALmSK{r}
                                     -S flag means nested lists are delimited first
                                       by newlines then by spaces when stringified/printed
           a                         1st cmdline arg
         CG                          Coordinate Grid, a list of lists of coord pairs
        Z                            Zip (transposes so it's x,y instead of row,col)
   J_                                Function that takes a list and joins all items
     MM                              MapMap: map this function to each sublist
                                       This joins a coord pair [1;0] into a string "10"
 Pm:                                 Assign the result to m and print it

                          $ALm       Fold m on Append List: appends all sublists of m
                                       together, making a single list of coord pairs
                              SK     Sort with the following function as key:
                                {r}  Return a random number
                                     We now have a randomly-ordered list of all the
                                       coord pairs from m

            {           }M           Map this function to that list:
             ST:m                    Convert m to string in-place
                 mR:                 Replace (in-place)...
                    a                  the argument (a coord pair)...
                     sX2               ... with two spaces
                                     The map operation returns a list of strings, one for
                                       each step of the process, which are autoprinted
                                       (separated by newlines)

Nice Job! That works perfectly

Actually, for n>=10 the randomization isn't working correctly, but it still hits the brief.  For numbers larger than 10 it only removes where index_i==index_j. Any idea behind the reason why that would be?

@carusocomputing Not entirely sure, but it's probably something to do with how the indices are chosen in the (mi@##Pmi@0) part. I put in several byte-reducing hacks that depend on the indices being single digits.

##, got it. Nice use of assumptions. Thanks for the explanation haha.

Groovy (202 Bytes)
{a->b=new String[a][a];while(b.flatten().flatten().contains(null)){b[(int)(Math.random()*a)][(int)(Math.random()*a)]="XX";b.eachWithIndex{e,i->e.eachWithIndex{f,j->print f?"XX ":"${i}${j} "}println()}}}

That specific output format really messed up my byte count, but meh.
Try it out: https://groovyconsole.appspot.com/edit/5171951567896576
(+9 bytes for a prettier print)
Ungolfed:
y={a->
    b=new String[a][a];
    while(b.flatten().flatten().contains(null)) {
        b[(int)(Math.random()*a)][(int)(Math.random()*a)]="XX";
        b.eachWithIndex{
            e,i->
            e.eachWithIndex{
                f,j->
                print f ? "XX ": "${i}${j} "
            }
            println()
        }
    }
}
y(4)

Output Example:
00 01 02 XX
10 11 12 13
20 21 22 23
30 31 32 33
00 01 02 XX
XX 11 12 13
20 21 22 23
30 31 32 33
XX 01 02 XX
XX 11 12 13
20 21 22 23
30 31 32 33
XX 01 XX XX
XX 11 12 13
20 21 22 23
30 31 32 33
XX 01 XX XX
XX 11 12 XX
20 21 22 23
30 31 32 33
XX 01 XX XX
XX 11 12 XX
XX 21 22 23
30 31 32 33
XX 01 XX XX
XX 11 XX XX
XX 21 22 23
30 31 32 33
XX 01 XX XX
XX XX XX XX
XX 21 22 23
30 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
30 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
30 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 23
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 XX
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 XX
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 XX
XX 31 32 33
XX XX XX XX
XX XX XX XX
XX 21 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX 31 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX 32 XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX 22 XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX XX XX
XX XX XX XX

the matrix should be NxN so a perfect square.

@jacksonecac It is, it's a 0-indexed 4x4 square. The square itself is just newline separated, as well as each iteration is newline separated, so the output kinda runs together.

If you want delimiters between the iterations, specify it in the brief.

Here, try it with the newline added inbetween iterations: https://groovyconsole.appspot.com/edit/5171951567896576

I apologize I jumped to conclusions. Let me parse this out :D

Nice job! thats awesome man

Judging from the output, this answer sometimes fills in a spot that's already been filled in, contrary to OP's intentions: "check the random numbers... to make sure that spot is not already filled."

R, 84 81 74 bytes
Now uses one-indexing rather than zero-indexing. Got rid of 7 bytes thanks to @Billywob.
N=scan()
m=outer(1:N,1:N,paste0)
for(i in sample(N^2)){m[i]="XX";print(m)}

Example output for N=3
     [,1] [,2] [,3]
[1,] "11" "12" "XX"
[2,] "21" "22" "23"
[3,] "31" "32" "33"
     [,1] [,2] [,3]
[1,] "11" "12" "XX"
[2,] "21" "22" "23"
[3,] "31" "XX" "33"
     [,1] [,2] [,3]
[1,] "11" "12" "XX"
[2,] "XX" "22" "23"
[3,] "31" "XX" "33"
     [,1] [,2] [,3]
[1,] "11" "XX" "XX"
[2,] "XX" "22" "23"
[3,] "31" "XX" "33"
     [,1] [,2] [,3]
[1,] "XX" "XX" "XX"
[2,] "XX" "22" "23"
[3,] "31" "XX" "33"
     [,1] [,2] [,3]
[1,] "XX" "XX" "XX"
[2,] "XX" "22" "23"
[3,] "XX" "XX" "33"
     [,1] [,2] [,3]
[1,] "XX" "XX" "XX"
[2,] "XX" "XX" "23"
[3,] "XX" "XX" "33"
     [,1] [,2] [,3]
[1,] "XX" "XX" "XX"
[2,] "XX" "XX" "XX"
[3,] "XX" "XX" "33"
     [,1] [,2] [,3]
[1,] "XX" "XX" "XX"
[2,] "XX" "XX" "XX"
[3,] "XX" "XX" "XX"

Nice Job! Go for it. Save those bytes!

You can save a few bytes using direct substitution instead of replace: for(i in sample(N^2)){m[i]="XX";print(m)}

@Billywob Thanks, I've edited the code to incorporate your suggestion. Great catch!

AWK, 229 bytes
func p(a){for(k=1;k<=m;k++){if(k==a)gsub("[0-9]","X",M[k])
printf"%s",M[k]}}{n=$1;m=n*n
k=1
for(i=0;i<n;i++)for(j=0;j<n;j++){s=k%n==0?k==m?"\n\n":"\n":" "
M[k++]=i j s}p()
for(;z<m;z++){do{y=int(rand()*m+1)}while(M[y]~"X")p(y)}}

I added a few bytes to give the output a space between each matrix.
Note: to make it more 'random' between runs, a call to srand() could be added for 7 additional bytes.
Usage and output after storing above code in FILE:
    awk -f FILE <<< 2

00 01
10 11

XX 01
10 11

XX XX
10 11

XX XX
10 XX

XX XX
XX XX

PHP, 172 Bytes
for(;$x<$s=($a=$argv[1])*$a;)$r[]=$x%$a.($x++/$a^0);echo($c=chunk_split)(join(" ",$r),$a*3);for(;$q<$s;){if($r[$z=rand(0,$s-1)]<X)++$q&$r[$z]=XX;echo$c(join(" ",$r),$a*3);}

Breakdown
for(;$x<$s=($a=$argv[1])*$a;)$r[]=$x%$a.($x++/$a^0); #make the array
echo($c=chunk_split)(join(" ",$r),$a*3); # Output array
for(;$q<$s;)
{
  if($r[$z=rand(0,$s-1)]<X)++$q&$r[$z]=XX; #fill position if it is not XX and raise increment
  echo$c(join(" ",$r),$a*3); #Output array
}

Python 2, 190 bytes
from random import *
R=range(input())
G=[(x,y)for x in R for y in R]
def f():print"\n".join(" ".join(["XX","%d%d"%(x,y)][(x,y) in G]for x in R)for y in R)
f()
while G:G.remove(choice(G));f()

APL (Dyalog Unicode), 30 bytes
↑{'×'@⍵⊢x}¨,\⊂¨y[?⍨≢y←,x←⍳2/⎕]

Try it online!
Uses ⎕IO←0 (0-indexing)
Uses the × symbol for replacement, in a grid of co-ordinate pairs.
Explanation
↑{'×'@⍵⊢x}¨,\⊂¨y[?⍨≢y←,x←⍳2/⎕]
                            ⎕  get the input n
                         ⍳2/   create an n×n coordinate grid
                       x←      store in x
                    y←,        convert to a list, and store in y
                 ?⍨≢           get indexes for shuffling the list
               y[            ] and get a random permutation of y
             ⊂¨                wrap each list
           ,\                  and get it's array prefixes
 {       }¨                    for each prefix:
  '×'@⍵⊢x                      place an '×' at those coordinates in the grid x
↑                              align all the grids into a matrix

05AB1E, 18 (or 17 or 19?) bytes
L<ãíJD.rĆvDIô,yðº:

Try it online.
The program above outputs each matrix on a separated line. If these matrices have to be pretty-printed, a » can be added before the ,: try it online. (Using the exact output format as the challenge description is 22 bytes: try it online.)
If we're allowed to output with 1-based indexing instead of 0-based, the < can be dropped for -1 byte: try it online.
Explanation:
L                   # Push a list in the range [1, (implicit) input]
 <                  # Optional: decrease each by 1 to change the range to [0, input)
  ã                 # Create all possible pairs of this list
   í                # Reverse each pair
    J               # Join each pair together to a single 2-digit string
     D              # Duplicate this list
      .r            # Pop and shuffle this copy
        Ć           # Enclose, appending it's own head
                    # (this is so the final iteration will print the empty matrix)
         v          # Loop `y` over each index in the shuffled list:
          D         #  Triplicate the unshuffled matrix
           Iô       #  Pop one copy, and split it into parts equal to the input
             »      #  Optional: join each inner list by spaces, and then each string by newlines
              ,     #  Pop and print this matrix with trailing newline
               y    #  Push the current random index
                ðº  #  Push a space, and mirror it to two spaces: "  "
                  : #  Replace the index in the list with these double spaces

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/