Rotation invariant fingerprinting Imagine we have some polyomino and would like to uniquely identify them, however the polyominos can be rotated, so blindly hashing them won't give us the same fingerprint for a piece and a rotation thereof (in general).

For example if we have the L-tetromino

x
x
xx


we would like it to have the same fingerprint as any of these:

         xx
  x       x      xxx
xxx  ,    x  or  x


Note: We only allow rotations on the plane (ie. they are one-sided polyominos) and therefore the following polyomino would be a different one:

 x
 x
xx 


Challenge

The task for this challenge is to implement a fingerprinting-function/program which takes an \$m\times n\$ Boolean/\$0,1\$-valued matrix/list of lists/string/.. encoding a polyomino and returns a string - the fingerprint of a polyomino. The fingerprint must be equal for all of the possible rotations (in general 4).

Input / Output


\$m \geq 1\$ and \$n \geq 1\$ (ie. no empty polyomino)
you're guaranteed that \$m,n\$ are as small as possible (ie. all \$0\$ are trimmed to fit \$m\$ and \$n\$
you're guaranteed that the input is


simply connected
has no holes

output must be a string which is the same for each possible rotation of a polyomino


Examples

Here are some equivalence classes, for each class the fingerprint must be the same &amp; for any two polyominos from two distinct classes they must differ.

The rotations of the L-tetromino from the example:

[[1,0],[1,0],[1,1]]
[[0,0,1],[1,1,1]]
[[1,1],[0,1],[0,1]]
[[1,1,1],[1,0,0]]


The J-tetromino:

[[0,1],[0,1],[1,1]]
[[1,1,1],[0,0,1]]
[[1,1],[1,0],[1,0]]
[[1,0,0],[1,1,1]]


The unit polyomino:

[[1]]


A \$5\times 1\$ bar:

[[1,1,1,1,1]]
[[1],[1],[1],[1],[1]]


A \$2\times 2\$ corner:

[[1,1],[1,0]]
[[1,0],[1,1]]
[[0,1],[1,1]]
[[1,1],[0,1]]


W-pentomino:

[[1,0,0],[1,1,0],[0,1,1]]
[[0,0,1],[0,1,1],[1,1,0]]
[[1,1,0],[0,1,1],[0,0,1]]
[[0,1,1],[1,1,0],[1,0,0]]
Python 2, 48 bytes



f=lambda l,z=5:z and max(l,f(zip(*l)[::-1],z-1))


Try it online!

Takes the largest of the four rotations in terms of list comparison. Based on FlipTack's solution.

The code uses Python 2's ability to compare objects of different types. The base case value of 0 is harmless for max because it's smaller than any list. Also, zip produces a list of tuples while the input is a list of lists, but tuples are bigger than lists so the input list-of-lists is never a contender. This is why we rotate 5 times rather than 4, so that we get back to a tuplified version of the initial list. (Taking a list of tuples would also work, if that's an allowed form of input.)