@Override
    public Long solve() {

        final int n = 10;
        final SquareState[] row = new SquareState[n+2];
        final Map<Row, Long> count = new HashMap<Row, Long>();
        
        for (int i = 0; i < row.length; ++i) {
            row[i] = new SquareState();
        }
        row[0].occupied = row[row.length - 1].occupied = true;
        
        findRow(row, row.length - 2, count);
        System.out.println(count.size());
       
        final TopSquareState[] squares = new TopSquareState[n];
        final PerRowSquareState[] bottomSquares = new PerRowSquareState[n];
        
        Arrays.fill(squares, new TopSquareState(true, TopDirection.DONT_CARE));
        Arrays.fill(bottomSquares, new PerRowSquareState(true, PerRowDirection.DONT_CARE));
        TopRow topRow = new TopRow(squares);
        Row bottomRow = new Row(bottomSquares);
        Map<TopRow, Long> m1 = new HashMap<TopRow, Long>();
        
        m1.put(topRow, 1L);

        for (int i = 0; i < n; ++i) {
            Map<TopRow, Long> m2 = new HashMap<TopRow, Long>();
            for (Entry<TopRow, Long> entry : m1.entrySet()) {
                for (Row r : count.keySet()) {
                    TopRow tr = entry.getKey().combine(r);
                    if (tr != null) {
                        add(m2, tr, entry.getValue().longValue());
                    }
                }
                
            }
            m1 = m2;
            System.out.println(m1.size());
        }
        Map<TopRow, Long> m2 = new HashMap<TopRow, Long>();
        for (Entry<TopRow, Long> entry : m1.entrySet()) {
            TopRow tr = entry.getKey().combine(bottomRow);
            if (tr != null) {
                add(m2, tr, entry.getValue().longValue());
            }
        }
        m1 = m2;

        return m1.get(topRow);
    }