[Question]
  [
## Background
Consider a (closed) chain of rods, each of which has integer length. How many distinct hole-free [polyominoes](http://en.wikipedia.org/wiki/Polyomino) can you form with a given chain? Or in other words, how many different non-self-intersecting polygons with axis-aligned sides can you form with a given chain?
Let's look at an example. Consider a particular chain consisting of 8 rods of length 1 and 2, which we can represent as `[1, 1, 2, 2, 1, 1, 2, 2]`. Up to rotations and translations, there are only 8 possible polyominoes (we do count different reflections):
![enter image description here](https://i.stack.imgur.com/9jCYW.png)
This first rod is dark blue, and then we traverse the polygon in a *counter-clockwise* sense.
The sense of rotation doesn't affect the result in the above example. But let's consider another chain, `[3, 1, 1, 1, 2, 1, 1]`, which yields the following 3 polyominoes:
![enter image description here](https://i.stack.imgur.com/tULNG.png)
Notice that we do *not* include a reflection of the last polyomino, because it would require clockwise traversal.
If we had a more flexible chain of the same length, `[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]`, we would actually be able to form both reflections among some other polyoninoes, totalling 9:
![enter image description here](https://i.stack.imgur.com/l2sbm.png)
## The Challenge
Given a description of a chain, as an array or similar, determine the number of distinct polyominoes you can form (up to rotations and translations) by using the rods *in order* while going around the perimeter in a counter-clockwise sense.
Please write a full program and include commands to compile (if applicable) and run your code from the command line. Please also include a link to a free compiler/interpreter for your language.
Your program should read the input from STDIN. The first line will contain an integer *M*. The next *M* lines will be test cases, each of which will be a space-separated list of rod lengths. Your program should print *M* lines to STDOUT, each of which consists of a single integer - the number of distinct polyominoes that can be formed.
You must only use a single thread.
Your program must not use more than 1 GB of memory at any time. (This is not a completely strict limit, but I will monitor your executable's memory usage, and kill any process that consistently uses more than 1 GB, or spikes significantly above it.)
To prevent excessive amounts of pre-computation, your code must not be longer than 20,000 bytes, and you must not read any files.
You must also not optimise towards the specific test cases chosen (e.g. by hardcoding their results). If I suspect that you do, I reserve the right to generate new benchmark sets. The test sets are random, so your program's performance on those should be representative for its performance on arbitrary input. The only assumption you're allowed to make is that the sum of the rod lengths is even.
## Scoring
[I have provided benchmark sets](https://gist.github.com/m-ender/eabb883dcc7c0eb734c7) for chains of *N* = 10, 11, ..., 20 rods. Each test set contains 50 random chains with lengths between 1 and 4 inclusive.
Your primary score is the largest *N* for which your program completes the entire test set within 5 minutes (on my machine, under Windows 8). The tie breaker will be the actual time taken by your program on that test set.
If anyone beats the largest test set, I will keep adding larger ones.
## Test Cases
You can use the following test cases to check the correctness of your implementation.
```
Input                            Output
1 1                              0
1 1 1 1                          1
1 1 1 1 1 1                      1
1 1 1 1 1 1 1 1                  3
1 1 1 1 1 1 1 1 1 1              9
1 1 1 1 1 1 1 1 1 1 1 1          36
1 1 1 1 1 1 1 1 1 1 1 1 1 1      157
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1  758
1 1 2 2 1 1 2 2                  8
1 1 2 2 1 1 2 2 1 1              23
1 1 2 2 1 1 2 2 1 1 2 2          69
1 2 1 2 1 2 1 2                  3
1 2 1 2 1 2 1 2 1 2 1 2          37
1 2 3 2 1 2 3 2                  5
1 2 3 2 1 2 3 2 1 2 3 2          23
3 1 1 1 2 1 1                    3
1 2 3 4 5 6 7                    1
1 2 3 4 5 6 7 8                  3
1 2 3 4 5 6 7 8 9 10 11          5
2 1 5 3 3 2 3 3                  4
4 1 6 5 6 3 1 4                  2
3 5 3 5 1 4 1 1 3                5
1 4 3 2 2 5 5 4 6                4
4 1 3 2 1 2 3 3 1 4              18
1 1 1 1 1 2 3 3 2 1              24
3 1 4 1 2 2 1 1 2 4 1 2          107
2 4 2 4 2 2 3 4 2 4 2 3          114
```
You find an input file with these [over here](https://gist.github.com/mbuettner/c0f23c3d92dc5b70be8f).
## Leaderboard
```
   User          Language       Max N      Time taken (MM:SS:mmm)
1. feersum       C++ 11         19         3:07:430
2. Sp3000        Python 3       18         2:30:181
```
  
[Answer]
# C++11
Updates:
Added the first line of `c` which breaks out early if the distance is too far from the origin (which was the whole purpose of the variable `rlen`, but I forgot to write it in the first version). I changed it to use much less memory, but at the cost of time. It now solves N=20 in just under 5 minutes for me.
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <map>
#include <ctime>
#define M std::map
#define MS 999
#define l (xM*2+1)
#define KITTENS(A,B)A##B
#define CATS(A,B)KITTENS(A,B)
#define LBL CATS(LBL,__LINE__)
#define unt unsigned
#define SU sizeof(unt)
#define SUB (SU*8)
#define newa (nb^SZ||fail("blob"),nb+++blob)
#define D
struct vec {int x, y;};
unt s[MS*2];
int xM, sl[MS];
vec X[MS];
struct a;
struct a  { M<unt,unt>v;};
#define SZ ((1<<29)/sizeof(a))
a*blob;
unt nb;
int fail(const char*msg)
{
    printf("failed:%s", msg);
    exit(1);
    return 1;
}
struct
{
    unt*m;
    bool operator()(int x, int y) { return m[(x+l*y)/SUB] >> (x+l*y)%SUB & 1; }
    void one(int x, int y) { m[(x+l*y)/SUB] |= 1U << (x+l*y)%SUB; }
    void zero(int x, int y) { m[(x+l*y)/SUB] &= ~(1U << (x+l*y)%SUB); }
} g;
unt c(a*A, vec x, unt rlen, unt sn) {
    if((unt)x.y+abs(x.x) > rlen) return 0;
    if(!rlen) {
        vec *cl=X, *cr=X, *ct=X;
        for(unt i=1; i<sn; i++) {
            #define BLAH(Z,A,B,o,O) \
                if(X[i].A o Z->A || (X[i].A == Z->A && X[i].B O Z->B)) \
                   Z = X+i
            BLAH(cl,x,y,<,>);
            BLAH(cr,x,y,>,<);
            BLAH(ct,y,x,>,>);
        }
        unt syms = 1;
        #define BLA(H,Z) {bool sy=1;for(unt o=0; o<sn; o++) sy &= (int)(1|-(H))*sl[o] == sl[(Z-X+o)%sn]; syms += sy;}
        BLA(~o&1,cl)
        BLA(1,ct)
        BLA(o&1,cr)
        #ifdef D
            //printf("D");for(int i=0;i<sn;i++)printf(" %u",sl[i]);printf("\n");
            if(syms==3) fail("symm");
        #endif
        return syms;
    }
    if(!(x.x|x.y|!sn)) return 0;
    X[sn] = x;
    unt k = 0;
    for(auto it: A->v) {
        int len = it.first;
        bool ve = sn&1;
        int dx = ve?0:len, dy = ve?len:0;
        #define PPCG(O)(x.x O (ve?0:z), x.y O (ve?z:0))
        #define MACR(O) { \
            vec v2 = {x.x O dx, x.y O dy}; \
            if(v2.y<0||(!v2.y&&v2.x<0)||abs(v2.x)>xM||v2.y>xM) \
                goto LBL; \
            for(int z=1; z<=len; z++) \
                if(g PPCG(O)) \
                    goto LBL; \
            for(int z=1; z<=len; z++) \
                g.one PPCG(O); \
            sl[sn] = O len; \
            k += c(blob+it.second, v2, rlen - len, sn+1); \
            for(int z=1; z<=len; z++) \
                g.zero PPCG(O); \
            } LBL: \
    MACR(+);
    MACR(-);
    }
    return k;
}
void stuff(a *n, unt j, unt r, unt len1)
{
    unt t=0;
    for(unt i=j; i<j+r; i++) {
        t += s[i];
        if((int)t > xM || (len1 && t>len1)) break;
        if(len1 && t < len1) continue;
        int r2 = r-(i-j)-1;
        if(r2) {
            unt x;
            if(n->v.count(t))
                x = n->v[t];
            else
                n->v[t] = x = newa - blob;
            stuff(blob+x, i+1, r2, 0);
        } else n->v[t] = -1;
    }
}
int main()
{
    time_t tim = time(0);
    blob = new a[SZ];
    int n;
    scanf("%u",&n);
    while(n--) {
        nb = 0;
        unt ns=0, tl=0;
        while(scanf("%u",s+ns)) {
            tl += s[ns];
            if(++ns==MS) return 1;
            if(getchar() < 11) break;
        }
        xM = ~-tl/2;
        g.m = (unt*)calloc((xM+1)*l/SU + 1,4);
        memcpy(s+ns, s, ns*SU);
        unt ans = 0;
        for(unt len1 = 1; (int)len1 <= xM; len1++) {
            a* a0 = newa;
            for(unt i=0; i<ns; i++)
                stuff(a0, i, ns, len1);
            ans += c(a0, {}, tl, 0);
            for(unt i=0; i<nb; i++)
                blob[i].v.clear();
        }
        printf("%d\n", ans/4);
        free(g.m);
    }
    tim = time(0) - tim;
    printf("time:%d",(int)tim);
    return 0;
}
```
Compile with
```
g++ --std=c++11 -O3 feersum.cpp -o feersum.exe
```
[Answer]
# Python 3 (with [PyPy](http://pypy.org/download.html)) — N = 18
```
ANGLE_COMPLEMENTS = {"A": "C", "F": "F", "C": "A"}
MOVE_ENUMS = {"U": 0, "R": 1, "D": 2, "L": 3}
OPPOSITE_DIR = {"U": "D", "D": "U", "L": "R", "R": "L", "": ""}
def canonical(angle_str):
    return min(angle_str[i:] + angle_str[:i] for i in range(len(angle_str)))
def to_angles(moves):
    """
    Convert a string of UDLR to a string of angles where
      A -> anticlockwise turn
      C -> clockwise turn
      F -> forward
    """
    angles = []
    for i in range(1, len(moves)):
        if moves[i] == moves[i-1]:
            angles.append("F")
        elif (MOVE_ENUMS[moves[i]] - MOVE_ENUMS[moves[i-1]]) % 4 == 1:
            angles.append("C")
        else:
            angles.append("A")
    if moves[0] == moves[len(moves)-1]:
        angles.append("F")
    elif (MOVE_ENUMS[moves[0]] - MOVE_ENUMS[moves[len(moves)-1]]) % 4 == 1:
        angles.append("C")
    else:
        angles.append("A")
    return "".join(angles)
def solve(rods):
    FOUND_ANGLE_STRS = set()
    def _solve(rods, rod_sum, point=(0, 0), moves2=None, visited=None, last_dir=""):
        # Stop when point is too far from origin
        if abs(point[0]) + abs(point[1]) > rod_sum:
            return
        # No more rods, check if we have a valid solution
        if not rods:
            if point == (0, 0):
               angle_str = to_angles("".join(moves2))
               if angle_str.count("A") - angle_str.count("C") == 4:
                   FOUND_ANGLE_STRS.add(canonical(angle_str))
            return
        r = rods.pop(0)
        if not visited:
            visited = set()
            move_dirs = [((r, 0), "R")]
            moves2 = []
        else:
            move_dirs = [((r,0), "R"), ((0,r), "U"), ((-r,0), "L"), ((0,-r), "D")]
        opp_dir = OPPOSITE_DIR[last_dir]
        for move, direction in move_dirs:
            if direction == opp_dir: continue
            new_point = (move[0] + point[0], move[1] + point[1])
            added_visited = set()
            search = True
            for i in range(min(point[0],new_point[0]), max(point[0],new_point[0])+1):
                for j in range(min(point[1],new_point[1]), max(point[1],new_point[1])+1):
                    if (i, j) != point:
                        if (i, j) in visited:
                            search = False
                            for a in added_visited:
                                visited.remove(a)
                            added_visited = set()                            
                            break
                        else:
                            visited.add((i, j))
                            added_visited.add((i, j))
                if not search:
                    break
            if search:
                moves2.append(direction*r)
                _solve(rods, rod_sum-r, new_point, moves2, visited, direction)
                moves2.pop()
            for a in added_visited:
                visited.remove(a)
        rods.insert(0, r)
        return
    _solve(rods, sum(rods))
    return len(FOUND_ANGLE_STRS)
num_rods = int(input())
for i in range(num_rods):
    rods = [int(x) for x in input().split(" ")]
    print(solve(rods))
```
Run with `./pypy <filename>`.
---
This is the reference implementation I wrote when discussing the question with Martin. It wasn't made with speed in mind and is quite hacky, but it should provide a good baseline to kick things off.
N = 18 takes about 2.5 minutes on my modest laptop.
## Algorithm
Rotations are checked by converting each shape into a series of `F` for forward, `A` for anticlockwise turn and `C` for clockwise turn at each lattice point on the boundary of the shape — I call this an *angle string*. Two shapes are rotationally identical if their angle strings are cyclic permutations. Rather than always checking this by comparing two angle strings directly, when we find a new shape we convert to a canonical form before storing. When we have a new candidate, we convert to the canonical form and check if we already have this (thus exploiting hashing, rather than iterating through the whole set).
The angle string is also used to check that the shape is formed anticlockwise, by making sure that the number of `A`s exceeds the number of `C`s by 4.
Self-intersection is naïvely checked by storing every lattice point on the boundary of the shape, and seeing if a point is visited twice.
The core algorithm is simple, placing the first rod to the right, then trying all possibilities for the remaining rods. If the rods reach a point which is too far from the origin (i.e. sum of remaining rod lengths is less than the Manhattan distance of the point from the origin), then we prematurely stop searching that subtree.
## Updates (latest first)
* 6/12: Introduced canonical form, added a few micro-optimisations
* 5/12: Fixed error in algorithm explanation. Made the quadratic cyclic-permutation-checking algorithm linear using the A,B cyclic permutations iff A substring of B+B method (I have no idea why I didn't do this earlier).
]