[Question]
  [
On a [toroidal square grid](https://www.google.com/search?q=toroidal+grid&sxsrf=ALeKk00zPr0KXqKlqJnTbEU7iskw6hvZ8Q:1588277096042&source=lnms&tbm=isch&sa=X&ved=2ahUKEwis5vSg-ZDpAhWCDOwKHWwhAi8Q_AUoAXoECAsQAw&biw=1920&bih=979#imgrc=DNpOW7cXm2Nv9M) (you can wrap around) where each cell indicates one direction (`^` `>` `v` `<`) if we pick a cell and start to walk following these directions, we will eventually get stuck in a loop.  
We may end up in a different loop, depending on our starting cell.
Not all the cells we encounter constitute our terminal loop: these are said to be *tributary* to that loop.
# Task
Given a square grid configuration, count for each loop \$L\_i\$:
* How many cells is it made up with? \$n\_i\$
* How many *tributary* cells does it have? \$t\_i\$
# Input
You choose the **set** of 4 printable characters or integers you'll use as directions.
* A square matrix having **set** elements as entries (can be a string)
# Output
* List of \$(n\_i,t\_i)\$ for each \$L\_i\$
The pairs can be in any order.
# Example
***input*** `urdrurllruuuulrududllurdu`
[![grid with colored regions](https://i.stack.imgur.com/Ca6OG.png)](https://i.stack.imgur.com/Ca6OG.png)  
*-vivid color: loop  
-pale color: tributary  
In this configuration there are 3 loops (orange, blue, green) of lengths (2, 2, 6) with (0, 10, 5) tributary cells.*
***output*** `6 5 2 10 2 0`
```
Alternative inputs:
    1232124421111421313441231
    [[^,>,v,>,^],[>,<,<,>,^],[^,^,^,<,>],[^,v,^,v,<],[<,^,>,v,^]]
Valid outputs:
    2 10 2 0 6 5
    (2, 10), (6, 5), (2, 0)
Non valid outputs:
    10 2 2 0 6 5
    (0, 2), (10, 2), (6, 5)
```
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so the shortest code wins.
  
[Answer]
# Java 10, ~~374~~ ~~371~~ 364 bytes
```
import java.util.*;m->{var L=new HashSet<Set>();int l=m.length,R=l*l,r,c,d;for(Set S;R-->0;S.add(r==R/l&c==R%l?-1:-2),L.add(S))for(S=new TreeSet(),r=R/l,c=R%l;S.add(r*l+c);r=(r-(d-d%3*d)/2+l)%l,c=(c-(d<2?1-2*d:0)+l)%l)d=m[r][c];for(Set z:L){if(z.remove(-1)){c=0;for(Set q:L)if(q.remove(-2)){if(q.containsAll(z))c++;q.add(-2);}System.out.println(z.size()+","+c);}}}
```
-10 bytes thanks to *@ceilingcat*.
Uses a matrix of integers `0,1,2,3` for `<,>,v,^` respectively.
[Try it online.](https://tio.run/##fVLRbtowFH3vV1whMdnECSE8jRCqvm1S11XQN8Sk1DElzEnAMZkgyrfTaxNotTFkObGPz7n3@lyv4yp218nvY5ptCqVhjXtvp1Pp9ULo98EZfAVdgF4JeN1r4fJil@s7LuOyhB9xmtd3AGmuhVrGXMCT2QJURZoAJ4jPF/MFZDREuLnDT6ljnXJ4ghyiY@ZO6ipW8Bjl4g98i8vVTOgxzgmhIYpBRpknRf6mV2wayZ5kinGWhMtCEWTBLJy67sQPZ16cJERF0bQvv3D8deW9Oxi5AWWP9mhGqdXYPC9KCFQTypQRMG745xg96XAaqogolyRu0h32EtoPHEm7hkg4ouPgfuAGvWTkU4vTJMrmajHni0thh9EjrdMlOXhKZEUliDugtOaRf2FskYGE7YUQUKvYerzINfpaPkhJDpRyxwm3tjakhM1sX2qRecVOexuFFskck5TpQRDqdFjHFN80zTE0Xm92rxK9bi23PckwMplpVL5hX2J6apcWpSbGmrZhdT1kAxbgHDasHjAfx2k9ZGbgzq4DZqaPa5@dFMOmsb2@FhPPrcq/zTmzbFyTO2j5n9@PvYyVf7yx012uGNT5nm92egQd5@NxPygV70svEWLzUpwMIRlt67oW41kJrfeu3YsEg7XcjcWfDUyyG/qfO30qouXkHr/Fv37jz8n@vrh5WRYDBaMLesGhQlTRFvw3J@mMJ9WvjsdXsXrQpDp78f/qTH1mNsd3)
**Explanation:**
```
import java.util.*;        // Required import for Set, HashSet, and TreeSet
m->{                       // Method with integer-matrix parameter and no return-type
  var L=new HashSet<Set>();//  Create a Set of Sets `L`, starting empty
  int l=m.length,          //  Set `l` to the dimensions of the input-matrix
      R=l*l,               //  Index integer `R` to loop over the cells
      r,c,                 //  Temp-integers `r,c` for the row and column
      d;                   //  Temp-integer `d` for the direction
  for(Set S;               //  Temp Set `S`, starting uninitialized
      R-->0                //  Loop `R` in the range (`l*l`, 0] over all cells:
      ;                    //     After every iteration:
       S.add(r==R/l&c==R%l?//      If `r,c` is still cell `R`:
              -1           //       Add -1 to Set `S`
             :             //      Else:
              -2),         //       Add -2 instead
       L.add(S))           //      And then add `S` to Set `L`
      for(S=new TreeSet(), //    Set `S` to a new empty sorted-Set
          r=R/l,c=R%l;     //    Set `r,c` to cell `R`
          S.add(r*l+c)     //    Add `r,c` as cell-index to Set `S` every iteration
                           //    and continue looping as long as it wasn't in `S` yet:
          ;                //      After every iteration:
           r=(r-(d-d%3*d)/2//       If `d` is 3:
                           //        Go to the cell above
                           //       Else-if `d` is 2:
                           //        Go to the cell below
              +l)%l        //       Adjust row wraparounds when we're out of bounds
           c=(c-(d<2?1-2*d:0)
                           //       Else-if `d` is 0:
                           //        Go to the cell left
                           //       Else-if `d` is 1:
                           //        Go to the cell right
             +l)%l         //       Adjust column wraparounds when we're out of bounds
        d=m[r][c];         //     Set `d` to the current direction of cell `r,c`
  // After we've determined all paths per cell:
  for(Set z:L){            //  Loop `z` over each path of Set `L`:
    if(z.remove(-1)){      //   Remove a -1 (if present),
                           //   and if it indeed contained a -1 (infinite path):
      c=0;                 //    Use `c` as counter, starting at 0
      for(Set q:L)         //    Inner loop `q` over each path of Set `L`:
        if(q.remove(-2)){  //     Remove a -2 (if present),
                           //     and if it indeed contained a -2 (tributary path):
          if(q.containsAll(z))
                           //      If `q` contains all values of `z`:
            c++;           //       Increase the counter by 1
          q.add(-2);}      //      Add -2 back to `q` for the next iteration of loop `z`
      System.out.println(  //    Print with trailing newline:
        z.size()           //     The size of path `z`
        +","+c);}}}        //     and the counter (comma-separated)
```
[Answer]
# [K (ngn/k)](https://codeberg.org/ngn/k), ~~99~~ 81 bytes
thanks @bstrat for -18 bytes!
```
{l,'(#'.c)-l:#'!c:={x@<x:(x?a@*|x)_x}'{?x,a@x}/'a::s/s!'(+(,/-:\=2)@,/x)+!s:2##x}
```
[Try it online!](https://ngn.codeberg.page/k#eJwdyrEKwyAQgOE9b6EOp42pkPHaoA9SKBLJdJNycGB999pO3z/8F3byYA3cT7cRGlAnHl3SU9BKzOn2EfeWAT2Kz0lGgIzYQlNgV+vDhq9jd8kHcatquBsjY1kuXSqTjgGt5jpbP3Ql+svMVH8WLjSlObB2XzqsJ2k=)
down,right,up,left in the input are encoded as 0 1 2 3
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~44~~ 41 [bytes](https://github.com/DennisMitchell/jelly/wiki/Code-page)
-3 as the grid is guaranteed to be square.
```
ŒṪœịı*ÆiƊ+⁸ʋƬ⁺⁹ɗ€⁸%LḞQ€LÞḢṢƲ€¹ƙ$Ẉ€µḟṂLṭṂ)
```
A monadic Link accepting a list of lists of integers which yields a list of lists of integers (each being a `[loop_size, tributary_count]` - i.e. \$(n\_i, t\_i)\$).
The directions in the input are:
```
^  2
>  1
V  4
<  3
```
**[Try it online!](https://tio.run/##y0rNyan8///opIc7Vx2d/HB395GNWofbMo91aT9q3HGq@9iaR427HjXuPDn9UROQuUPV5@GOeYFAts/heQ93LHq4c9GxTUDeoZ3HZqo83NUBYm59uGP@w51NPg93rgVSmv///4@ONtJRMNRRMAGTRrFcOtFA2hiMYAJAFRAEEoMKmIAFgKQxSMAYzIMYA9QSCwA "Jelly – Try It Online")**
### How?
```
ŒṪœịı*ÆiƊ+⁸ʋƬ⁺⁹ɗ€⁸%L...  - Link: list, X
ŒṪ                       - truthy multi-dimensional indices -> [[1,1],[1,2],...,[h,w]]
                €        - for each:
               ɗ         -   last three links as a dyadic chain:
              ⁹          -     use chain's right argument as right argument
            Ƭ            -     collect up until no change occurs with:
           ʋ             -       last four links as a dyadic chain:
  œị                     -         multi-dimensional index into X
        Ɗ                -         last three links as a monadic chain:
    ı                    -           square root of -1
     *                   -           exponentiate
      Æi                 -           [real part, imaginary part] -> move deltas
          ⁸              -         chain's left argument -> the current position
         +               -         add together -> the new position
             ⁺           -     repeat the Ƭ-collection, use the entire result
                   L     - length of X
                  %      - modulo -> making all results have the same domain
```
```
...ḞQ€LÞḢṢƲ€¹ƙ$Ẉ€µḟṂLṭṂ) - ...continued
   Ḟ                     - floor (we had a mix of ints and floats, but ƙ uses
                                  Python's repr, this makes them all ints again)
    Q€                   - deduplicate each
              $          - last two links as a monadic chain:
            ¹ƙ           - group by:
           €             -   for each
          Ʋ              -     last four links as a monadic chain:
       Þ                 -       sort by...
      L                  -       length
        Ḣ                -       head
         Ṣ               -       sorted
               Ẉ€        - length of each of each
                 µ     ) - for each:
                   Ṃ     -   minimum -> loop length
                  ḟ      -   filter discard (keeping only tributary lengths)
                    L    -   length -> number of tributaries
                      Ṃ  -   minimum -> loop length
                     ṭ   -   tack -> [loop length, number of tributaries]
```
[Answer]
# [Python 2](https://docs.python.org/2/), ~~250 247~~ 235 bytes
*Thanks Arnauld for pointing out that the grid is guaranteed to be square, saving 12 bytes!*
```
G=input()
n=len(G)
N={}
T={}
t=0
exec"j=t%n;i=t/n;A=[]\nwhile(i,j)not in A:A=[(i,j)]+A;d=G[i][j];i+=d/3-1;j+=d%3-1;i%=n;j%=n\nk=A.index((i,j))+1;x=min(A[:k]);N[x]=k;T[x]=T.get(x,[])+A[k:];t+=1;"*n*n
for x in N:print N[x],len(set(T[x]))
```
[Try it online!](https://tio.run/##NY8xb8MgEIV3/woUyRLENCm1qkhGNzB58@SNMNWkwU7PVkJUqqq/3QXSSqd3j497J1i@/HnGl3VtweFy95QVCBeLtGVFB98/RZ/Ew3Nhg33bjOBLlA78HqUCbY74eXYXSx0fGc6eOCSqiRcZmErJAVrtjB6NdBUM@/pJyDGaMhlXAsoxyhEnUDuHgw00J1klZIAPh1TpZjJMdjoYmGSfWr97t54Grg2rlJ4aI30FQm62uMXiNF9JSM/omuXq0JOU5OlDtxhKecbWVWvBySsnh6zCcKJjr3P9gzjxqMT@wCGDqHUCdT491ghjfgE "Python 2 – Try It Online")
Takes input as a 2D list from `STDIN`, where up, right, down, left are encoded as the integers `1, 5, 7, 3` respectively.
For each cell in the grid, the program follows the directions starting from that cell until a loop is found. The loop length is stored in the dictionary `N`, and the list of tributary cells is stored in the dictionary `T`. The keys for both dictionaries are the min indices of each loop.
[Answer]
# [JavaScript (Node.js)](https://nodejs.org), 196 bytes if width=height
```
m=>m[Q='flatMap'](U=(y,I)=>y[Q]((x,j)=>U[T=[...m+0,Y=m.length,i=I][Q](_=>0+[j=(c=m[i][j]-2,j+Y-~c%2)%Y,i=(i+Y+c%2)%Y])[k=0,Q](S=c=>(S[c]=-~S[c])==2&&++k&&c).sort()]?(++U[T][0],[]):[U[T]=[1-k,k]]))
```
[Try it online!](https://tio.run/##PY4/a8NADMX3fIoscXScfJydrSB3ztAhpBmMEMVc7dT/Q2xKs@Sru3eYlsdD@gk9oab4LiZ3r29zPIyf5VLR0lPW84n2VVfMb8VtL3AheOBRUfbgkwD8YOP7C78TG2N6bTGn3nTlcJ2/sKajhK0PyqzmhsBRz7VwI3GKjc7jp9ulapf7Rah1rlcSxS1Z9LkzOcrgzE4ofoaiiNIo0rqNIqfMNN5nUPIKWvsHhK0gi3rhAMRJ3GIrotTixmEau9J04xUq4M12ywmmePBOBAOmaL3@McEgP/jDAwbbFS2u6UQ24fov "JavaScript (Node.js) – Try It Online")
# [JavaScript (Node.js)](https://nodejs.org), 205 bytes
```
m=>m[Q='flatMap'](U=(y,I)=>y[Q]((x,j)=>U[T=[...m+0,Y=m[W='length'],X=m[W],i=I][Q](_=>0+[j=(c=m[i][j]-2,j+Y-~c%2)%Y,i=(i+Y+c%2)%Y]).sort().filter(S=c=>(S[c]=-~S[c])==2)]?(++U[T][1],[]):[U[T]=[k=T[W],1-k]]))
```
[Try it online!](https://tio.run/##PY5Ni4NADIbv/RW9FDNMHNTeFuKee@ihtGVXQlhkql2tH0WlbC/96@4Mskt4SZ6QN0mdP/LRDtV9Crv@UswlzS2lLR8oKJt82uf3QOBM8MSdovTJBwH4wdrVZz4RG2NaHWFGLX9Q0BTddfoOBD89C1a0E@/4ojTSXBNY16@EawkTrHUWvuwmUZvMDUKlM72QKDP2wwTKlFUzFQMcyVIKR7ZC4csnRZQoeQet3RPCsSCLemMPxDc6@dtxeBNRarZ9N/ZNYZr@CiXwar3mGBPcOjmfxwQjF/8Yow/X@MMtekULRri4Y1n57b8 "JavaScript (Node.js) – Try It Online")
Ungolfed version 
```
m=>m.flatMap(
  U=(y,I)=>y.flatMap(
    (x,j)=>
      U[
        T=[...m+0,Y=m.length,X=y.length,i=I].map(_=>(
          c=m[i][j],c%2?(i=(i+Y-2+c)%Y):(j=(j+X-1+c)%X),
          i*X+j
        )).sort().filter((c,k,S)=>S[k-1]!=c&S[k+1]==c)
      ]?(++U[T][1],[]):[U[T]=[k=T.length,1-k]]
  )
)
```
[Try it online!](https://tio.run/##TY9Na8MwDIbv/RXeoUOaFROnt4LScw87pYUUY0Zwk875aEobxvrrM2f9oAjB@7zoFVJd/BQXd/anITr2@3KseOw47VTVFsNncYKZEFuGK62R0@urKwT8Uh3cfx2mzF0IsWGjlOpkTDvuVFseD8M35Xx9SM9rq7qw5otTeKaEcNwZb01tyc2TFXgGL3dRIh3Od7iEmqGWeaQnzpFegv4jl/WTEdWlPw@AqvLtUJ4BHDWUhVMzk1ETafvG7j0zjdSW2eE9aFcg5dZsrNGWjMWlmYBNw5vH4TpqrA3jOMPR9cdL35aq7Q9QwfS80ZTQInTIT5hQHOqJmqYKxgMXNHV8w5huaW1nFnH8Aw "JavaScript (Node.js) – Try It Online")
[Answer]
# [J](http://jsoftware.com/), 78 bytes
```
[:(#~1<{."1)@((=([,-~)&(+/)0=|)"{~~.)@,](]*.[{"p..0|:((,-)=0 1)|.])^:_ p:@i.@$
```
[Try it online!](https://tio.run/##hY@xCsIwFEX3fMWjFpOn6TPVLVoICk7i4FpiB2uxErAUMpSW/nosODiJwz3LgQP3GSLiFWQaOEhQoKclBIfL6RhyLWZjuuspStEIkYlcJiPOxXKFKhsw6seR0Egr7ILyPmqI1KCFkAlmClIcyOJVF9BoU5OJw3lPsAHNv9FfTdn9TdYUd5whY/fb4wUV8LL1jkNNkG@pWIO1nzPMt5NhrXMTvfeuZb70pWNuEp5heAM "J – Try It Online")
### How it works
We map each index to the corresponding prime `p:@i.@$`:
```
 2  3  5  7 11
13 17 19 23 29
31 37 41 43 47
53 59 61 67 71
73 79 83 89 97
```
Then shift this board by the 4 directions `((,-)=0 1)|.])`, and calculate the least common multiple between the tile `x` and the direction `x` is heading `]*.[{"p..0|:`. We do this until the board does not change anymore `(…)^:_`:
```
461677248802 62985        20995    3162172937  3162172937
         221   221         4199 2109169348979 91703015173
        6851  8177       172159       7402837      321997
      363103  4661     10501699    3162172937  3162172937
230838624401  4661 262460353771    3162172937  3162172937
```
For each unique `~.` number we can then count how often it occures and how many other tiles it divides: `= …&(1#.,) 0=|`. We need the first number and the difference for the result: `([,-~)`:
```
…
6  5
2 10
1  5
…
2  0
1  0
```
We then take only the ones where the first column is greater than 1 `(#~1<{."1)`:
```
6  5
2 10
2  0
```
[Answer]
# [R](https://cran.r-project.org/) ~~435 414 395~~ 390 bytes
Entering the excursion map as a matrix, e.g.
```
n=3;M=matrix(sample(1:4,n^2,rep=T),n)
```
where 1,2,3,4 stand for `down`, `up`, `right`, and `left`, the following heavy-going code produces rows of lengths and tributaries for the different loops
```
j=cbind;l=sum;a=apply
m=l(!!M);n=m^.5
g=function(A,r=M[A])A+c((r<2)*(1-n*(A[,1]==n))-(r==2)*(1-n*(A[,1]<2)),(r==3)*(1-n*(A[,2]==n))-(r>3)*(1-n*(A[,2]<2)))
I=c()
for(i in d<-1:n)I=rbind(I,j(i*d/d,d))
for(t in b<-1:m)I=g(I)
p=function(i)i[,1]+n*i[,2]-n-1
K=matrix(0,m,m)
for(t in b)K[b+m*p(I<-g(I))]=1
s=o=a(u<-unique(K),1,l)
for(k in 1:l(!!s))s[k]=l(!a(!!sweep(K,2,u[k,],'-'),1,l))
j(o,s-o)
```
[Try it online!](https://tio.run/##VZDNboNADITv@xTJKTbxtt2kvQRciSNC3HpDRCJAok3YhS6gtk9Ps4r6k6NH39jjcbPlbZixKUenP2EoTd82oHbPZPcbck3Pb0gWRe@0HSHD@czVQds6bHmYTFhy2fftlzDcwnKZYWjZ7B9exImPk61G3VmIyXGWxwXG6wrARRsMQEkbQJyTKpgtogTHfK9fMSQvb//Jm1/89V72NIqEK0Bx7BzohbaLOpJqZzFh5wNDQmfQQf1YU403avTUwVPmSp0gub75l1uj9kHWNtD@hLRSifSnpycyZP5vwTQ/rE3QQxJJvwkLVmLgjkuYIjlZ/T41kCIpam@2i7epna9tQBzyS@ErLP340TQ9pLShKb9QQSu5uvlQnKGjQXYo5ll8Aw "R – Try It Online")
Some comments
```
m=l(!!M);n=m^.5 #m=n^2
#moving all points in the square by the corresponding moves in M
g=function(A,r=M[A])A+cbind((r<2)*(1-n*(A[,1]==n))-(r==2)*(1-n*(A[,1]<2)),(r==3)*(1-n*(A[,2]==n))-(r>3)*(1-n*(A[,2]<2)))
#matrix of the (i,j) coordinates for all points in the square
I=c()#NULL
for(i in 1:n)I=rbind(I,cbind(rep(i,n),1:n))
#move long enough to remove transient points
for(t in b<-1:m)I=g(I)
#turns 2D coordinates into a single integer 
p=function(i)i[,1]+n*i[,2]-n-1
K=matrix(0,m,m) #matrix of visited coordinates
for(t in b)K[b+m*p(I<-g(I))]=1
#loop length (o) and associated number of transients (s)
s=o=apply(u<-unique(K),1,sum)
#sum over all loops (length(o))
for(k in 1:sum(!!s))s[k]=sum(!a(!!sweep(K,2,u[k,],'-'),1,sum))
cbind(o,s-o)
```
Now, I spent too much time on this code already but I fear the parts
```
I=c()
for(i in 1:n)I=rbind(I,cbind(rep(i,n),1:n))
```
creating the matrix of all starting coordinates and
```
p=function(i)i[,1]+n*i[,2]-n-1
```
switching from the coordinates to a single index could be further code-golfed!
[Answer]
# [Scala](https://www.scala-lang.org/), 415 bytes
415 bytes, maybe more. It can be golfed much more.
Port of [@Kevin Cruijssen' Java 10 answer](https://codegolf.stackexchange.com/a/204701/110802) in Scala.
---
Golfed version. [Try it online!](https://tio.run/##jVJRT9swEH7PrzhFBdklMWn6VtVIaC9jYhui2xNiyHMMDXOc4rhBNMpvL7YTSlpNG5Fj@e6@7zvfnSvOJNvmxarUBh5Zzcja5JI0n1m1XAgTwQ8thD/YrQ16YOVYhJdSCm7yUpEvlvmpVLXQRuiK3AX2K38/2ih8ZbmCJggAjGa5gW/WAPtl4h44KmZwrjV7uen2C2Vub/EMfqrcWFTraDWToGaWR0GJ54/zLb7ZOvIldby@ohv3exjCgYtKWhAp1INZevOayrEM7kuN8nmcwFrZdsA1bmqmQdP8VAbuxGl@JD1@4cX7Lnlhq5uVzYKwLEN6LE94lyejBdIYWUtTpGOUxdnRdJzh0/REYivGKeIxyu9RNk/xJE7HGQhZCUiwj7fPy1wKNJTFgUVr6i51fMypuxLu4vEEe25vpTi49KcFbn1pm3lsHdXCjRE3VmVDtCjKWjhmVyuniYc@HUKfdtAU9w5eKmOnXJ1LiTYY8xM6CZ7eUrdtsNK5MlKhKhw1G1LlG9FGIx7a0NZNsn2btBtpYYUQ0w/V22AXxrIfhkP14zeiMsgj@n0awSSC1O9THHVsZI3Erz2vxXbLBYbe1Hvtnuy8iXd10lNsm/7X7C4@FEr@iTwED/N1N047/q4tXuY/j93ne@/1hVqtzQxGTUEKtkJ3pPjT9RKFUYjxwOwShxH0C9vRhHhPLrzSwpiX2Nsim8Eu7txXzouKA8r3tfE36KGK8EPIXol7Uh@o1L5OQBrmMRS4d70ra19zDfQMwvlZ/SskfMn0uUH1oPLuMt3za4PtKw)
```
val L=new HashSet[Set[Int]]()
val l=m.length
val R=l*l
for(i<-0 until R){var r=i/l
var c=i%l
val S=new TreeSet[Int]()
do{S.add(r*l+c)
val d=m(r)(c)
r=(r-(d-d%3*d)/2+l)%l
c=(c-(if(d<2)1-2*d else 0)+l)%l}while(S.add(r*l+c))
if(r==i/l&&c==i%l)S.add(-1)else S.add(-2)
L.add(S)}
for(z<-L.asScala){if(z.remove(-1)){var c=0
for(q<-L.asScala){if(q.remove(-2)){if(q.containsAll(z))c+=1
q.add(-2)}}
println(s"${z.size},$c")}}
```
Ungolfed version. [Try it online!](https://tio.run/##jVRdb5swFH3nV1yhrrJXwgh5i9pK1V7WqduqZnuquoqBk9AZkxqHqon47dn1BwSSbWpETHzuOcf3Xtup0oQnu11erEqp4Cmpk3Ctch5uPyXVcsZUAN8lY@YHDo3niJWWhWnJOUtVXorwMyo/lqJmUjFZhY@eV/56whh8SXIBW88DUDLJFXzFCeAnY3NISTGFKymT13s7Xgv18ECn8EPkClmNltUJBzFF3QUI9vJ2PfIt01rcOL2r615/DZ3QHosjqwg5Ewu17MF3CHN4D9xh7jUvJZAczkcQwVpg2@COdotqpQSJyhw@dEqLpgZ9N0A5zFyKruMmvS47rLjseQPMwiTLiNRZwRmktBfSZpmuhEhKBhGdDmpGQDIcMkxhggYZxQxjdOF0kBSYREmq@flca84hpjDGeaxlwHjFIKLHygZeljlnQA6z3CejDTEd1x44PdWLubZQV91oTO0abhrv5TcGmbWAOSrdnmz0niCjmulz2t8TveomlKwoa6bt6aCn7d5EPcwYPv/TsDV97kxjehhvGWkpFF6H6opzskFWCmcXMD6gPh@Vauv7@@@VzIXiglT@yXYTVvmGNcFJ6u/Fjdd/N@2t0tenwFxIIhdVe4lmCt0WRxdIsUoRw3DjJIBxALEZJzSwaoKTyDwDFLn20YE@GhsUx6hDIwNZ6wl1Z@VodR3vG0X/ZR6S@@vZjGOr79pibN7yx7Lv/bVYrdUUTrZFWCQr8hgWv20viR/4lPamdmE/APdQnzZut1o7/1YypV5HZs6yKXRxDd9qlBQHkm9rZTJwVBGmh5RBiQOrN1Rq7oDUd6DYn@3WWZqaa7i4BP/8sv7ph@kykVeK1L3Kae/4Nd5u9wc)
```
import java.util.{HashSet, TreeSet, Set}
import scala.collection.JavaConverters._
object Main {
  trait N {
    def c(m: Array[Array[Int]]): Unit
  }
  val n: N = new N {
    def c(m: Array[Array[Int]]): Unit = {
      val L = new HashSet[Set[Int]]()
      val l = m.length
      val R = l * l
      
      for (i <- 0 until R) {
        var r = i / l
        var c = i % l
        val S = new TreeSet[Int]()
        do {
          S.add(r * l + c)
          val d = m(r)(c)
          r = (r - (d - d % 3 * d) / 2 + l) % l
          c = (c - (if (d < 2) 1 - 2 * d else 0) + l) % l
        } while (S.add(r * l + c))
        if (r == i / l && c == i % l) S.add(-1) else S.add(-2)
        L.add(S)
      }
      for (z <- L.asScala) {
        if (z.remove(-1)) {
          var c = 0
          for (q <- L.asScala) {
            if (q.remove(-2)) {
              if (q.containsAll(z)) c += 1
              q.add(-2)
            }
          }
          println(s"${z.size},$c")
        }
      }
    }
  }
  def main(args: Array[String]): Unit = {
    test(Array(Array(3, 1, 2, 1, 3), Array(1, 0, 0, 1, 3), Array(3, 3, 3, 0, 1), Array(3, 2, 3, 2, 0), Array(0, 3, 1, 2, 3)))
    test(Array(Array(1, 2), Array(3, 0)))
    test(Array(Array(1, 2, 2), Array(3, 0, 0), Array(1, 0, 2)))
  }
  def test(m: Array[Array[Int]]): Unit = {
    println(s"Input: ${m.map(_.mkString(",")).mkString("Array(", ", ", ")")}")
    println("Pretty-printed: ")
    prettyPrint(m)
    println("Output: ")
    n.c(m)
    println()
  }
  def prettyPrint(m: Array[Array[Int]]): Unit = {
    for (r <- m) {
      println(r.map(v => "<>v^".charAt(v)).mkString)
    }
  }
}
```
]