#include <bits/stdc++.h>

using namespace std;

#define LOG(...) fprintf(stderr, __VA_ARGS__)
//#define LOG(...)
#define FOR(i, a, b) for (int i = (int)(a); i < (int)(b); ++i)
#define RFOR(i, a, b) for (int i = (int)(b - 1); i >= (int)(a); --i)
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define RREP(i, n) for (int i = (int)(n - 1); i >= 0; --i)
#define ALL(a) (a).begin(), (a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define EXIST(s, e) ((s).find(e) != (s).end())
#define SORT(c) sort(ALL(c))
#define RSORT(c) sort(RALL(c))
#define SZ(a) ((int)(a).size())
#define BIT(x, i) (((x) >> (i)) & 1)
#define SQ(x) ((x) * (x))

typedef long long ll;
typedef unsigned long long ull;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<vb> vvb;
typedef vector<vi> vvi;
typedef vector<vll> vvll;
typedef vector<char> vc;
typedef vector<vc> vvc;
typedef vector<string> vs;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

typedef vector<vvb> Block;

const int dx[] = {-1,0,1,0,-1,-1,1,1,0}, dy[] = {0,1,0,-1,1,-1,1,-1,0};

struct P {
    int n, flushed;
    Block field;
};

int H, N;

bool move_block(Block& block, int i) {
    Block b(2, vvb(2, vb(2)));
    REP(z, 2) REP(y, 2) REP(x, 2) {
        if (block[z][y][x]) {
            int sx = x + dx[i], sy = y + dy[i];
            if (0 <= sx && sx < 2 && 0 <= sy && sy < 2) {
                b[z][sy][sx] = true;
            } else {
                return false;
            }
        }
    }
    block = b;
    return true;
}

void fall_block(Block& block, Block& field) {
    int h = 14;
    for (; h >= 0; h--) {
        bool ok = true;
        REP(z, 2) REP(y, 2) REP(x, 2) {
            if (block[z][y][x] && field[h+z][y][x]) {
                ok = false;
            }
        }
        if (!ok) break;
    }
    h++;
    REP(z, 2) REP(y, 2) REP(x, 2) {
        if (block[z][y][x]) {
            field[h+z][y][x] = block[z][y][x];
        }
    }
}

bool is_filled(Block& field, int z) {
    bool ok = false;
    REP(y, 2) REP(x, 2) {
        if (field[z][y][x]) {
            ok = true;
        } else {
            return false;
        }
    }
    return ok;
}

int flush(Block& field) {
    int flushed = 0;
    for (int z = 0; z < 16;) {
        if (is_filled(field, z)) {
            flushed++;
            REP(y, 2) REP(x, 2) {
                field[z][y][x] = false;
            }
            FOR(h, z, 15) REP(y, 2) REP(x, 2) {
                swap(field[h][y][x], field[h+1][y][x]);
            }
        } else {
            z++;
        }
    }
    return flushed;
}

int main() {
    while (cin >> H >> N, H|N) {
        Block field(16, vvb(2, vb(2)));
        REP(z, H) REP(y, 2) REP(x, 2) {
            char c;
            cin >> c;
            field[z][y][x] = c == '#';
        }
        vector<Block> blocks(N, Block(2, vvb(2, vb(2))));
        REP(i, N) {
            REP(z, 2) REP(y, 2) REP(x, 2) {
                char c;
                cin >> c;
                blocks[i][z][y][x] = c == '#';
            }
            bool empty = true;
            REP(y, 2) REP(x, 2) {
                if (blocks[i][0][y][x]) {
                    empty = false;
                    break;
                }
            }
            if (empty) {
                REP(y, 2) REP(x, 2) {
                    swap(blocks[i][0][y][x], blocks[i][1][y][x]);
                }
            }
        }

        int ma = 0;
        queue<P> que;
        que.push({0, 0, field});
        while (!que.empty()) {
            P _p = que.front(); que.pop();
            if (_p.n == N) {
                ma = max(ma, _p.flushed);
                continue;
            }
            REP(i, 9) {
                P p = _p;
                Block block = blocks[p.n];
                if (move_block(block, i)) {
                    fall_block(block, p.field);
                    p.flushed += flush(p.field);
                    p.n++;
                    que.push(p);
                }
            }
        }
        cout << ma << endl;
    }
}

Measured memory_bytes: 3132