Rotation invariant fingerprinting












14














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 $mtimes 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 & 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 $5times 1$ bar:



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


A $2times 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]]









share|improve this question






















  • Related.
    – BMO
    Dec 16 at 17:20










  • If I always output "" (the empty string), have I satisfied all the requirements?
    – Daniel Wagner
    Dec 17 at 12:13










  • @DanielWagner: "[..] for any two polyominos from two distinct classes [the fingerprints] must differ" - so no, that would be invalid.
    – BMO
    Dec 17 at 14:59










  • Is outputting all possible rotations of an array, consistently sorted valid? Example
    – Shaggy
    Dec 17 at 17:12








  • 1




    @Shaggy: Yes, that would meet all the criteria.
    – BMO
    Dec 17 at 17:15
















14














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 $mtimes 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 & 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 $5times 1$ bar:



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


A $2times 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]]









share|improve this question






















  • Related.
    – BMO
    Dec 16 at 17:20










  • If I always output "" (the empty string), have I satisfied all the requirements?
    – Daniel Wagner
    Dec 17 at 12:13










  • @DanielWagner: "[..] for any two polyominos from two distinct classes [the fingerprints] must differ" - so no, that would be invalid.
    – BMO
    Dec 17 at 14:59










  • Is outputting all possible rotations of an array, consistently sorted valid? Example
    – Shaggy
    Dec 17 at 17:12








  • 1




    @Shaggy: Yes, that would meet all the criteria.
    – BMO
    Dec 17 at 17:15














14












14








14







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 $mtimes 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 & 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 $5times 1$ bar:



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


A $2times 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]]









share|improve this question













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 $mtimes 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 & 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 $5times 1$ bar:



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


A $2times 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]]






code-golf array-manipulation hashing polyomino






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 16 at 17:20









BMO

11.3k22185




11.3k22185












  • Related.
    – BMO
    Dec 16 at 17:20










  • If I always output "" (the empty string), have I satisfied all the requirements?
    – Daniel Wagner
    Dec 17 at 12:13










  • @DanielWagner: "[..] for any two polyominos from two distinct classes [the fingerprints] must differ" - so no, that would be invalid.
    – BMO
    Dec 17 at 14:59










  • Is outputting all possible rotations of an array, consistently sorted valid? Example
    – Shaggy
    Dec 17 at 17:12








  • 1




    @Shaggy: Yes, that would meet all the criteria.
    – BMO
    Dec 17 at 17:15


















  • Related.
    – BMO
    Dec 16 at 17:20










  • If I always output "" (the empty string), have I satisfied all the requirements?
    – Daniel Wagner
    Dec 17 at 12:13










  • @DanielWagner: "[..] for any two polyominos from two distinct classes [the fingerprints] must differ" - so no, that would be invalid.
    – BMO
    Dec 17 at 14:59










  • Is outputting all possible rotations of an array, consistently sorted valid? Example
    – Shaggy
    Dec 17 at 17:12








  • 1




    @Shaggy: Yes, that would meet all the criteria.
    – BMO
    Dec 17 at 17:15
















Related.
– BMO
Dec 16 at 17:20




Related.
– BMO
Dec 16 at 17:20












If I always output "" (the empty string), have I satisfied all the requirements?
– Daniel Wagner
Dec 17 at 12:13




If I always output "" (the empty string), have I satisfied all the requirements?
– Daniel Wagner
Dec 17 at 12:13












@DanielWagner: "[..] for any two polyominos from two distinct classes [the fingerprints] must differ" - so no, that would be invalid.
– BMO
Dec 17 at 14:59




@DanielWagner: "[..] for any two polyominos from two distinct classes [the fingerprints] must differ" - so no, that would be invalid.
– BMO
Dec 17 at 14:59












Is outputting all possible rotations of an array, consistently sorted valid? Example
– Shaggy
Dec 17 at 17:12






Is outputting all possible rotations of an array, consistently sorted valid? Example
– Shaggy
Dec 17 at 17:12






1




1




@Shaggy: Yes, that would meet all the criteria.
– BMO
Dec 17 at 17:15




@Shaggy: Yes, that would meet all the criteria.
– BMO
Dec 17 at 17:15










8 Answers
8






active

oldest

votes


















7















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.)






share|improve this answer





























    4















    Python 3, 63 bytes





    def f(m):M=;exec("m=[*zip(*m[::-1])];M+=m,;"*4);return min(M)


    Try it online!



    Finds the rotation with the lexographical minimum, and prints that.



    A lambda form comes in at the same byte count:





    lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M[-4:])


    Try it online!






    share|improve this answer























    • Rewriting as a lambda can get you to 58. lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M). Works because exec always returns None.
      – nedla2004
      Dec 16 at 17:54










    • @nedla2004 That can only be run once, and then gets dodgy as M is already populated...
      – FlipTack
      Dec 16 at 17:55










    • @nedla2004 ... but accounting for the problem with M[-4:] can get you to the same byte count.
      – FlipTack
      Dec 16 at 18:10










    • I see, the test I was using was just checking inputs with the same "hash", so I never ran into that. That makes sense.
      – nedla2004
      Dec 16 at 18:11



















    2















    Jelly, 5 bytes



    ZU$ƬṂ


    Try it online!



    Full program.



    Simply generates all possible rotations and picks the lexicographical minimum.



    Note that singleton lists aren't wrapped in in the output. That doesn't matter, since the only case where singleton lists would exist in the input would be a vertical line (including the unit polyomino), which is the same as a horizontal line with the same size (where the ones aren't wrapped). The only case where the outer will not exist either is the unit polyomino.






    share|improve this answer























    • when i read the challenge i knew this would happen :)
      – ngn
      Dec 16 at 18:18



















    2















    Clean, 136 bytes



    import StdEnv,Data.List
    r=reverse;t=transpose;f=flatten
    $l=[if((a==b)==(c==d))'x''X'\a<-f l&b<-f(r(map r l))&c<-f(r(t l))&d<-f(t(r l))]


    Try it online!



    Includes test verifier.






    share|improve this answer





























      2















      K (ngn/k), 16 bytes



      {a@*<a:3{+|x}x}


      Try it online!



      min of rotations



      { } function with argument x



      {+|x} rotate, i.e. reverse (|) and transpose (+)



      3{ } apply 3 times preserving intermediate results; this returns a list of the 4 rotations



      a: assign to a



      < ascend (compute the sort-ascending permutation)



      * first



      a@ index a with that






      share|improve this answer































        1














        Japt -g, 6 bytes



        4Æ=zÃñ


        Try it



                   :Implicit input of 2d-array U
        4Æ :Map the range [0,4)
        z : Rotate U 90 degrees
        = : Reassign to U
        Ã :End map
        ñ :Sort
        :Implicit output of first element





        share|improve this answer























        • Is the -g flag necessary? Sort should mean that all initial rotations end up with the same list so that full list should work fine as the fingerprint unless I'm missing something.
          – Kamil Drakari
          Dec 17 at 15:58










        • @KamilDrakari, you could well be right - like I said, I'm not sure I fully understood the challenge. No harm leaving it in, though, it's not costing any bytes.
          – Shaggy
          Dec 17 at 17:11










        • @KamilDrakari: It is not necessary, but it's no harm either as it's not counted towards the bytecount.
          – BMO
          Dec 17 at 17:17



















        1















        J, 16 bytes



        -2 bytes thanks to Shaggy



        [:/:~|.@|:^:(<4)


        Try it online!




        J, 18 bytes



        0{[:/:~|.@|:^:(<4)


        Try it online!



        Returns the first item in the list of the lexicograpically sorted rotations of the polyomino.



        Explanation:



                    ^:(<4)  - do the verb on the left 4 times, storing all the steps
        |.@|: - tranpose and reverse
        /:~ - sort up the 4 matrices
        [: - cap the fork
        0{ - take the first matrix





        share|improve this answer























        • @Shaggy Thanks!
          – Galen Ivanov
          Dec 17 at 18:02



















        0















        05AB1E, 10 8 bytes



        3FÂø})Σ˜


        -2 bytes thanks to @Shaggy.



        Try it online or verify all test cases.



        Explanation:





        3F  }       # Loop 3 times
        Â # Bifurcate (short for Duplicate & Reverse) the top of the stack
        # (which is the input-matrix implicitly the first iteration)
        ø # Transpose: swap rows/columns
        ) # After the loop, wrap everything on the stack in a list
        Σ˜ # Sort this list of matrices by their flattened array (and output implicitly)


        NOTE: Taking the minimum with ß or W will implicitly flatten, so will output 0. And sorting with { doesn't seem to work for a list of matrices, which is why I use Σ˜ instead.






        share|improve this answer



















        • 1




          @Shaggy Thanks! :) In that case the last two bytes can be removed, since the } is done implicitly if nothing comes after it.
          – Kevin Cruijssen
          Dec 17 at 17:31






        • 1




          Today I learned something about 05AB1E! :) It's the same in Japt.
          – Shaggy
          Dec 17 at 18:35











        Your Answer





        StackExchange.ifUsing("editor", function () {
        return StackExchange.using("mathjaxEditing", function () {
        StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
        StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
        });
        });
        }, "mathjax-editing");

        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "200"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f177662%2frotation-invariant-fingerprinting%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        8 Answers
        8






        active

        oldest

        votes








        8 Answers
        8






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        7















        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.)






        share|improve this answer


























          7















          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.)






          share|improve this answer
























            7












            7








            7







            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.)






            share|improve this answer













            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.)







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Dec 16 at 19:01









            xnor

            89.7k18184439




            89.7k18184439























                4















                Python 3, 63 bytes





                def f(m):M=;exec("m=[*zip(*m[::-1])];M+=m,;"*4);return min(M)


                Try it online!



                Finds the rotation with the lexographical minimum, and prints that.



                A lambda form comes in at the same byte count:





                lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M[-4:])


                Try it online!






                share|improve this answer























                • Rewriting as a lambda can get you to 58. lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M). Works because exec always returns None.
                  – nedla2004
                  Dec 16 at 17:54










                • @nedla2004 That can only be run once, and then gets dodgy as M is already populated...
                  – FlipTack
                  Dec 16 at 17:55










                • @nedla2004 ... but accounting for the problem with M[-4:] can get you to the same byte count.
                  – FlipTack
                  Dec 16 at 18:10










                • I see, the test I was using was just checking inputs with the same "hash", so I never ran into that. That makes sense.
                  – nedla2004
                  Dec 16 at 18:11
















                4















                Python 3, 63 bytes





                def f(m):M=;exec("m=[*zip(*m[::-1])];M+=m,;"*4);return min(M)


                Try it online!



                Finds the rotation with the lexographical minimum, and prints that.



                A lambda form comes in at the same byte count:





                lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M[-4:])


                Try it online!






                share|improve this answer























                • Rewriting as a lambda can get you to 58. lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M). Works because exec always returns None.
                  – nedla2004
                  Dec 16 at 17:54










                • @nedla2004 That can only be run once, and then gets dodgy as M is already populated...
                  – FlipTack
                  Dec 16 at 17:55










                • @nedla2004 ... but accounting for the problem with M[-4:] can get you to the same byte count.
                  – FlipTack
                  Dec 16 at 18:10










                • I see, the test I was using was just checking inputs with the same "hash", so I never ran into that. That makes sense.
                  – nedla2004
                  Dec 16 at 18:11














                4












                4








                4







                Python 3, 63 bytes





                def f(m):M=;exec("m=[*zip(*m[::-1])];M+=m,;"*4);return min(M)


                Try it online!



                Finds the rotation with the lexographical minimum, and prints that.



                A lambda form comes in at the same byte count:





                lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M[-4:])


                Try it online!






                share|improve this answer















                Python 3, 63 bytes





                def f(m):M=;exec("m=[*zip(*m[::-1])];M+=m,;"*4);return min(M)


                Try it online!



                Finds the rotation with the lexographical minimum, and prints that.



                A lambda form comes in at the same byte count:





                lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M[-4:])


                Try it online!







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 16 at 18:03

























                answered Dec 16 at 17:46









                FlipTack

                9,12834089




                9,12834089












                • Rewriting as a lambda can get you to 58. lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M). Works because exec always returns None.
                  – nedla2004
                  Dec 16 at 17:54










                • @nedla2004 That can only be run once, and then gets dodgy as M is already populated...
                  – FlipTack
                  Dec 16 at 17:55










                • @nedla2004 ... but accounting for the problem with M[-4:] can get you to the same byte count.
                  – FlipTack
                  Dec 16 at 18:10










                • I see, the test I was using was just checking inputs with the same "hash", so I never ran into that. That makes sense.
                  – nedla2004
                  Dec 16 at 18:11


















                • Rewriting as a lambda can get you to 58. lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M). Works because exec always returns None.
                  – nedla2004
                  Dec 16 at 17:54










                • @nedla2004 That can only be run once, and then gets dodgy as M is already populated...
                  – FlipTack
                  Dec 16 at 17:55










                • @nedla2004 ... but accounting for the problem with M[-4:] can get you to the same byte count.
                  – FlipTack
                  Dec 16 at 18:10










                • I see, the test I was using was just checking inputs with the same "hash", so I never ran into that. That makes sense.
                  – nedla2004
                  Dec 16 at 18:11
















                Rewriting as a lambda can get you to 58. lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M). Works because exec always returns None.
                – nedla2004
                Dec 16 at 17:54




                Rewriting as a lambda can get you to 58. lambda m,M=:exec("m=[*zip(*m[::-1])];M+=m,;"*4)or min(M). Works because exec always returns None.
                – nedla2004
                Dec 16 at 17:54












                @nedla2004 That can only be run once, and then gets dodgy as M is already populated...
                – FlipTack
                Dec 16 at 17:55




                @nedla2004 That can only be run once, and then gets dodgy as M is already populated...
                – FlipTack
                Dec 16 at 17:55












                @nedla2004 ... but accounting for the problem with M[-4:] can get you to the same byte count.
                – FlipTack
                Dec 16 at 18:10




                @nedla2004 ... but accounting for the problem with M[-4:] can get you to the same byte count.
                – FlipTack
                Dec 16 at 18:10












                I see, the test I was using was just checking inputs with the same "hash", so I never ran into that. That makes sense.
                – nedla2004
                Dec 16 at 18:11




                I see, the test I was using was just checking inputs with the same "hash", so I never ran into that. That makes sense.
                – nedla2004
                Dec 16 at 18:11











                2















                Jelly, 5 bytes



                ZU$ƬṂ


                Try it online!



                Full program.



                Simply generates all possible rotations and picks the lexicographical minimum.



                Note that singleton lists aren't wrapped in in the output. That doesn't matter, since the only case where singleton lists would exist in the input would be a vertical line (including the unit polyomino), which is the same as a horizontal line with the same size (where the ones aren't wrapped). The only case where the outer will not exist either is the unit polyomino.






                share|improve this answer























                • when i read the challenge i knew this would happen :)
                  – ngn
                  Dec 16 at 18:18
















                2















                Jelly, 5 bytes



                ZU$ƬṂ


                Try it online!



                Full program.



                Simply generates all possible rotations and picks the lexicographical minimum.



                Note that singleton lists aren't wrapped in in the output. That doesn't matter, since the only case where singleton lists would exist in the input would be a vertical line (including the unit polyomino), which is the same as a horizontal line with the same size (where the ones aren't wrapped). The only case where the outer will not exist either is the unit polyomino.






                share|improve this answer























                • when i read the challenge i knew this would happen :)
                  – ngn
                  Dec 16 at 18:18














                2












                2








                2







                Jelly, 5 bytes



                ZU$ƬṂ


                Try it online!



                Full program.



                Simply generates all possible rotations and picks the lexicographical minimum.



                Note that singleton lists aren't wrapped in in the output. That doesn't matter, since the only case where singleton lists would exist in the input would be a vertical line (including the unit polyomino), which is the same as a horizontal line with the same size (where the ones aren't wrapped). The only case where the outer will not exist either is the unit polyomino.






                share|improve this answer















                Jelly, 5 bytes



                ZU$ƬṂ


                Try it online!



                Full program.



                Simply generates all possible rotations and picks the lexicographical minimum.



                Note that singleton lists aren't wrapped in in the output. That doesn't matter, since the only case where singleton lists would exist in the input would be a vertical line (including the unit polyomino), which is the same as a horizontal line with the same size (where the ones aren't wrapped). The only case where the outer will not exist either is the unit polyomino.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 16 at 17:43

























                answered Dec 16 at 17:37









                Erik the Outgolfer

                31.3k429102




                31.3k429102












                • when i read the challenge i knew this would happen :)
                  – ngn
                  Dec 16 at 18:18


















                • when i read the challenge i knew this would happen :)
                  – ngn
                  Dec 16 at 18:18
















                when i read the challenge i knew this would happen :)
                – ngn
                Dec 16 at 18:18




                when i read the challenge i knew this would happen :)
                – ngn
                Dec 16 at 18:18











                2















                Clean, 136 bytes



                import StdEnv,Data.List
                r=reverse;t=transpose;f=flatten
                $l=[if((a==b)==(c==d))'x''X'\a<-f l&b<-f(r(map r l))&c<-f(r(t l))&d<-f(t(r l))]


                Try it online!



                Includes test verifier.






                share|improve this answer


























                  2















                  Clean, 136 bytes



                  import StdEnv,Data.List
                  r=reverse;t=transpose;f=flatten
                  $l=[if((a==b)==(c==d))'x''X'\a<-f l&b<-f(r(map r l))&c<-f(r(t l))&d<-f(t(r l))]


                  Try it online!



                  Includes test verifier.






                  share|improve this answer
























                    2












                    2








                    2







                    Clean, 136 bytes



                    import StdEnv,Data.List
                    r=reverse;t=transpose;f=flatten
                    $l=[if((a==b)==(c==d))'x''X'\a<-f l&b<-f(r(map r l))&c<-f(r(t l))&d<-f(t(r l))]


                    Try it online!



                    Includes test verifier.






                    share|improve this answer













                    Clean, 136 bytes



                    import StdEnv,Data.List
                    r=reverse;t=transpose;f=flatten
                    $l=[if((a==b)==(c==d))'x''X'\a<-f l&b<-f(r(map r l))&c<-f(r(t l))&d<-f(t(r l))]


                    Try it online!



                    Includes test verifier.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Dec 16 at 21:42









                    Οurous

                    6,41811033




                    6,41811033























                        2















                        K (ngn/k), 16 bytes



                        {a@*<a:3{+|x}x}


                        Try it online!



                        min of rotations



                        { } function with argument x



                        {+|x} rotate, i.e. reverse (|) and transpose (+)



                        3{ } apply 3 times preserving intermediate results; this returns a list of the 4 rotations



                        a: assign to a



                        < ascend (compute the sort-ascending permutation)



                        * first



                        a@ index a with that






                        share|improve this answer




























                          2















                          K (ngn/k), 16 bytes



                          {a@*<a:3{+|x}x}


                          Try it online!



                          min of rotations



                          { } function with argument x



                          {+|x} rotate, i.e. reverse (|) and transpose (+)



                          3{ } apply 3 times preserving intermediate results; this returns a list of the 4 rotations



                          a: assign to a



                          < ascend (compute the sort-ascending permutation)



                          * first



                          a@ index a with that






                          share|improve this answer


























                            2












                            2








                            2







                            K (ngn/k), 16 bytes



                            {a@*<a:3{+|x}x}


                            Try it online!



                            min of rotations



                            { } function with argument x



                            {+|x} rotate, i.e. reverse (|) and transpose (+)



                            3{ } apply 3 times preserving intermediate results; this returns a list of the 4 rotations



                            a: assign to a



                            < ascend (compute the sort-ascending permutation)



                            * first



                            a@ index a with that






                            share|improve this answer















                            K (ngn/k), 16 bytes



                            {a@*<a:3{+|x}x}


                            Try it online!



                            min of rotations



                            { } function with argument x



                            {+|x} rotate, i.e. reverse (|) and transpose (+)



                            3{ } apply 3 times preserving intermediate results; this returns a list of the 4 rotations



                            a: assign to a



                            < ascend (compute the sort-ascending permutation)



                            * first



                            a@ index a with that







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Dec 17 at 13:57

























                            answered Dec 16 at 18:42









                            ngn

                            6,92112559




                            6,92112559























                                1














                                Japt -g, 6 bytes



                                4Æ=zÃñ


                                Try it



                                           :Implicit input of 2d-array U
                                4Æ :Map the range [0,4)
                                z : Rotate U 90 degrees
                                = : Reassign to U
                                Ã :End map
                                ñ :Sort
                                :Implicit output of first element





                                share|improve this answer























                                • Is the -g flag necessary? Sort should mean that all initial rotations end up with the same list so that full list should work fine as the fingerprint unless I'm missing something.
                                  – Kamil Drakari
                                  Dec 17 at 15:58










                                • @KamilDrakari, you could well be right - like I said, I'm not sure I fully understood the challenge. No harm leaving it in, though, it's not costing any bytes.
                                  – Shaggy
                                  Dec 17 at 17:11










                                • @KamilDrakari: It is not necessary, but it's no harm either as it's not counted towards the bytecount.
                                  – BMO
                                  Dec 17 at 17:17
















                                1














                                Japt -g, 6 bytes



                                4Æ=zÃñ


                                Try it



                                           :Implicit input of 2d-array U
                                4Æ :Map the range [0,4)
                                z : Rotate U 90 degrees
                                = : Reassign to U
                                Ã :End map
                                ñ :Sort
                                :Implicit output of first element





                                share|improve this answer























                                • Is the -g flag necessary? Sort should mean that all initial rotations end up with the same list so that full list should work fine as the fingerprint unless I'm missing something.
                                  – Kamil Drakari
                                  Dec 17 at 15:58










                                • @KamilDrakari, you could well be right - like I said, I'm not sure I fully understood the challenge. No harm leaving it in, though, it's not costing any bytes.
                                  – Shaggy
                                  Dec 17 at 17:11










                                • @KamilDrakari: It is not necessary, but it's no harm either as it's not counted towards the bytecount.
                                  – BMO
                                  Dec 17 at 17:17














                                1












                                1








                                1






                                Japt -g, 6 bytes



                                4Æ=zÃñ


                                Try it



                                           :Implicit input of 2d-array U
                                4Æ :Map the range [0,4)
                                z : Rotate U 90 degrees
                                = : Reassign to U
                                Ã :End map
                                ñ :Sort
                                :Implicit output of first element





                                share|improve this answer














                                Japt -g, 6 bytes



                                4Æ=zÃñ


                                Try it



                                           :Implicit input of 2d-array U
                                4Æ :Map the range [0,4)
                                z : Rotate U 90 degrees
                                = : Reassign to U
                                Ã :End map
                                ñ :Sort
                                :Implicit output of first element






                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Dec 17 at 17:19

























                                answered Dec 16 at 20:24









                                Shaggy

                                18.9k21666




                                18.9k21666












                                • Is the -g flag necessary? Sort should mean that all initial rotations end up with the same list so that full list should work fine as the fingerprint unless I'm missing something.
                                  – Kamil Drakari
                                  Dec 17 at 15:58










                                • @KamilDrakari, you could well be right - like I said, I'm not sure I fully understood the challenge. No harm leaving it in, though, it's not costing any bytes.
                                  – Shaggy
                                  Dec 17 at 17:11










                                • @KamilDrakari: It is not necessary, but it's no harm either as it's not counted towards the bytecount.
                                  – BMO
                                  Dec 17 at 17:17


















                                • Is the -g flag necessary? Sort should mean that all initial rotations end up with the same list so that full list should work fine as the fingerprint unless I'm missing something.
                                  – Kamil Drakari
                                  Dec 17 at 15:58










                                • @KamilDrakari, you could well be right - like I said, I'm not sure I fully understood the challenge. No harm leaving it in, though, it's not costing any bytes.
                                  – Shaggy
                                  Dec 17 at 17:11










                                • @KamilDrakari: It is not necessary, but it's no harm either as it's not counted towards the bytecount.
                                  – BMO
                                  Dec 17 at 17:17
















                                Is the -g flag necessary? Sort should mean that all initial rotations end up with the same list so that full list should work fine as the fingerprint unless I'm missing something.
                                – Kamil Drakari
                                Dec 17 at 15:58




                                Is the -g flag necessary? Sort should mean that all initial rotations end up with the same list so that full list should work fine as the fingerprint unless I'm missing something.
                                – Kamil Drakari
                                Dec 17 at 15:58












                                @KamilDrakari, you could well be right - like I said, I'm not sure I fully understood the challenge. No harm leaving it in, though, it's not costing any bytes.
                                – Shaggy
                                Dec 17 at 17:11




                                @KamilDrakari, you could well be right - like I said, I'm not sure I fully understood the challenge. No harm leaving it in, though, it's not costing any bytes.
                                – Shaggy
                                Dec 17 at 17:11












                                @KamilDrakari: It is not necessary, but it's no harm either as it's not counted towards the bytecount.
                                – BMO
                                Dec 17 at 17:17




                                @KamilDrakari: It is not necessary, but it's no harm either as it's not counted towards the bytecount.
                                – BMO
                                Dec 17 at 17:17











                                1















                                J, 16 bytes



                                -2 bytes thanks to Shaggy



                                [:/:~|.@|:^:(<4)


                                Try it online!




                                J, 18 bytes



                                0{[:/:~|.@|:^:(<4)


                                Try it online!



                                Returns the first item in the list of the lexicograpically sorted rotations of the polyomino.



                                Explanation:



                                            ^:(<4)  - do the verb on the left 4 times, storing all the steps
                                |.@|: - tranpose and reverse
                                /:~ - sort up the 4 matrices
                                [: - cap the fork
                                0{ - take the first matrix





                                share|improve this answer























                                • @Shaggy Thanks!
                                  – Galen Ivanov
                                  Dec 17 at 18:02
















                                1















                                J, 16 bytes



                                -2 bytes thanks to Shaggy



                                [:/:~|.@|:^:(<4)


                                Try it online!




                                J, 18 bytes



                                0{[:/:~|.@|:^:(<4)


                                Try it online!



                                Returns the first item in the list of the lexicograpically sorted rotations of the polyomino.



                                Explanation:



                                            ^:(<4)  - do the verb on the left 4 times, storing all the steps
                                |.@|: - tranpose and reverse
                                /:~ - sort up the 4 matrices
                                [: - cap the fork
                                0{ - take the first matrix





                                share|improve this answer























                                • @Shaggy Thanks!
                                  – Galen Ivanov
                                  Dec 17 at 18:02














                                1












                                1








                                1







                                J, 16 bytes



                                -2 bytes thanks to Shaggy



                                [:/:~|.@|:^:(<4)


                                Try it online!




                                J, 18 bytes



                                0{[:/:~|.@|:^:(<4)


                                Try it online!



                                Returns the first item in the list of the lexicograpically sorted rotations of the polyomino.



                                Explanation:



                                            ^:(<4)  - do the verb on the left 4 times, storing all the steps
                                |.@|: - tranpose and reverse
                                /:~ - sort up the 4 matrices
                                [: - cap the fork
                                0{ - take the first matrix





                                share|improve this answer















                                J, 16 bytes



                                -2 bytes thanks to Shaggy



                                [:/:~|.@|:^:(<4)


                                Try it online!




                                J, 18 bytes



                                0{[:/:~|.@|:^:(<4)


                                Try it online!



                                Returns the first item in the list of the lexicograpically sorted rotations of the polyomino.



                                Explanation:



                                            ^:(<4)  - do the verb on the left 4 times, storing all the steps
                                |.@|: - tranpose and reverse
                                /:~ - sort up the 4 matrices
                                [: - cap the fork
                                0{ - take the first matrix






                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Dec 17 at 18:02

























                                answered Dec 17 at 8:09









                                Galen Ivanov

                                6,29711032




                                6,29711032












                                • @Shaggy Thanks!
                                  – Galen Ivanov
                                  Dec 17 at 18:02


















                                • @Shaggy Thanks!
                                  – Galen Ivanov
                                  Dec 17 at 18:02
















                                @Shaggy Thanks!
                                – Galen Ivanov
                                Dec 17 at 18:02




                                @Shaggy Thanks!
                                – Galen Ivanov
                                Dec 17 at 18:02











                                0















                                05AB1E, 10 8 bytes



                                3FÂø})Σ˜


                                -2 bytes thanks to @Shaggy.



                                Try it online or verify all test cases.



                                Explanation:





                                3F  }       # Loop 3 times
                                Â # Bifurcate (short for Duplicate & Reverse) the top of the stack
                                # (which is the input-matrix implicitly the first iteration)
                                ø # Transpose: swap rows/columns
                                ) # After the loop, wrap everything on the stack in a list
                                Σ˜ # Sort this list of matrices by their flattened array (and output implicitly)


                                NOTE: Taking the minimum with ß or W will implicitly flatten, so will output 0. And sorting with { doesn't seem to work for a list of matrices, which is why I use Σ˜ instead.






                                share|improve this answer



















                                • 1




                                  @Shaggy Thanks! :) In that case the last two bytes can be removed, since the } is done implicitly if nothing comes after it.
                                  – Kevin Cruijssen
                                  Dec 17 at 17:31






                                • 1




                                  Today I learned something about 05AB1E! :) It's the same in Japt.
                                  – Shaggy
                                  Dec 17 at 18:35
















                                0















                                05AB1E, 10 8 bytes



                                3FÂø})Σ˜


                                -2 bytes thanks to @Shaggy.



                                Try it online or verify all test cases.



                                Explanation:





                                3F  }       # Loop 3 times
                                Â # Bifurcate (short for Duplicate & Reverse) the top of the stack
                                # (which is the input-matrix implicitly the first iteration)
                                ø # Transpose: swap rows/columns
                                ) # After the loop, wrap everything on the stack in a list
                                Σ˜ # Sort this list of matrices by their flattened array (and output implicitly)


                                NOTE: Taking the minimum with ß or W will implicitly flatten, so will output 0. And sorting with { doesn't seem to work for a list of matrices, which is why I use Σ˜ instead.






                                share|improve this answer



















                                • 1




                                  @Shaggy Thanks! :) In that case the last two bytes can be removed, since the } is done implicitly if nothing comes after it.
                                  – Kevin Cruijssen
                                  Dec 17 at 17:31






                                • 1




                                  Today I learned something about 05AB1E! :) It's the same in Japt.
                                  – Shaggy
                                  Dec 17 at 18:35














                                0












                                0








                                0







                                05AB1E, 10 8 bytes



                                3FÂø})Σ˜


                                -2 bytes thanks to @Shaggy.



                                Try it online or verify all test cases.



                                Explanation:





                                3F  }       # Loop 3 times
                                Â # Bifurcate (short for Duplicate & Reverse) the top of the stack
                                # (which is the input-matrix implicitly the first iteration)
                                ø # Transpose: swap rows/columns
                                ) # After the loop, wrap everything on the stack in a list
                                Σ˜ # Sort this list of matrices by their flattened array (and output implicitly)


                                NOTE: Taking the minimum with ß or W will implicitly flatten, so will output 0. And sorting with { doesn't seem to work for a list of matrices, which is why I use Σ˜ instead.






                                share|improve this answer















                                05AB1E, 10 8 bytes



                                3FÂø})Σ˜


                                -2 bytes thanks to @Shaggy.



                                Try it online or verify all test cases.



                                Explanation:





                                3F  }       # Loop 3 times
                                Â # Bifurcate (short for Duplicate & Reverse) the top of the stack
                                # (which is the input-matrix implicitly the first iteration)
                                ø # Transpose: swap rows/columns
                                ) # After the loop, wrap everything on the stack in a list
                                Σ˜ # Sort this list of matrices by their flattened array (and output implicitly)


                                NOTE: Taking the minimum with ß or W will implicitly flatten, so will output 0. And sorting with { doesn't seem to work for a list of matrices, which is why I use Σ˜ instead.







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Dec 17 at 17:30

























                                answered Dec 17 at 9:41









                                Kevin Cruijssen

                                35.6k554186




                                35.6k554186








                                • 1




                                  @Shaggy Thanks! :) In that case the last two bytes can be removed, since the } is done implicitly if nothing comes after it.
                                  – Kevin Cruijssen
                                  Dec 17 at 17:31






                                • 1




                                  Today I learned something about 05AB1E! :) It's the same in Japt.
                                  – Shaggy
                                  Dec 17 at 18:35














                                • 1




                                  @Shaggy Thanks! :) In that case the last two bytes can be removed, since the } is done implicitly if nothing comes after it.
                                  – Kevin Cruijssen
                                  Dec 17 at 17:31






                                • 1




                                  Today I learned something about 05AB1E! :) It's the same in Japt.
                                  – Shaggy
                                  Dec 17 at 18:35








                                1




                                1




                                @Shaggy Thanks! :) In that case the last two bytes can be removed, since the } is done implicitly if nothing comes after it.
                                – Kevin Cruijssen
                                Dec 17 at 17:31




                                @Shaggy Thanks! :) In that case the last two bytes can be removed, since the } is done implicitly if nothing comes after it.
                                – Kevin Cruijssen
                                Dec 17 at 17:31




                                1




                                1




                                Today I learned something about 05AB1E! :) It's the same in Japt.
                                – Shaggy
                                Dec 17 at 18:35




                                Today I learned something about 05AB1E! :) It's the same in Japt.
                                – Shaggy
                                Dec 17 at 18:35


















                                draft saved

                                draft discarded




















































                                If this is an answer to a challenge…




                                • …Be sure to follow the challenge specification. However, please refrain from exploiting obvious loopholes. Answers abusing any of the standard loopholes are considered invalid. If you think a specification is unclear or underspecified, comment on the question instead.


                                • …Try to optimize your score. For instance, answers to code-golf challenges should attempt to be as short as possible. You can always include a readable version of the code in addition to the competitive one.
                                  Explanations of your answer make it more interesting to read and are very much encouraged.


                                • …Include a short header which indicates the language(s) of your code and its score, as defined by the challenge.



                                More generally…




                                • …Please make sure to answer the question and provide sufficient detail.


                                • …Avoid asking for help, clarification or responding to other answers (use comments instead).






                                Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                Please pay close attention to the following guidance:


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f177662%2frotation-invariant-fingerprinting%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Сан-Квентин

                                8-я гвардейская общевойсковая армия

                                Алькесар