• + 0 comments

    from collections import defaultdict import os

    MAX_ROWS = 20 MAX_COLS = 8

    def set_bit(num, count): return num | (1 << count)

    def get_bit(num, i): return (num & (1 << i)) != 0

    def clear_bit(num, i): mask = ~(1 << i) return num & mask

    class Tile2: def init(self, row1, col1, row2, col2, row3, col3, row4, col4): self.rows = [row1, row2, row3, row4] self.cols = [col1, col2, col3, col4]

    def can_fit(self, arr, row, column):
        for i in range(4):
            if row + self.rows[i] < 0 or row + self.rows[i] >= MAX_ROWS or column + self.cols[i] < 0 or column + self.cols[i] >= MAX_COLS:
                return False
            if get_bit(arr[row + self.rows[i]], column + self.cols[i]):
                return False
    
        for i in range(4):
            arr[row + self.rows[i]] = set_bit(arr[row + self.rows[i]], column + self.cols[i])
    
        return True
    
    def remove_tile(self, arr, row, column):
        for i in range(4):
            arr[row + self.rows[i]] = clear_bit(arr[row + self.rows[i]], column + self.cols[i])
    

    TILES = [ Tile2(0, 0, 1, 0, 2, 0, 2, 1), Tile2(0, 0, 1, 0, 1, -1, 1, -2), Tile2(0, 0, 0, 1, 1, 1, 2, 1), Tile2(0, 0, 1, 0, 0, 1, 0, 2), Tile2(0, 0, 1, 0, 2, 0, 2, -1), Tile2(0, 0, 0, 1, 0, 2, 1, 2), Tile2(0, 0, 0, 1, 1, 0, 2, 0), Tile2(0, 0, 1, 0, 1, 1, 1, 2) ]

    def get_hash(arr): return ''.join(format(num, '02x') for num in arr)

    cache = defaultdict(int)

    def get_my_count(arr, empty_count): if empty_count % 4 != 0: return 0

    count = 0
    empty = False
    
    for i in range(MAX_ROWS):
        for j in range(MAX_COLS):
            if not get_bit(arr[i], j):
                empty = True
                for tile in TILES:
                    if tile.can_fit(arr, i, j):
                        arr_hash = get_hash(arr)
                        if arr_hash in cache:
                            combinations = cache[arr_hash]
                        else:
                            combinations = get_my_count(arr, empty_count)
                            cache[arr_hash] = combinations
                        count += combinations
                        tile.remove_tile(arr, i, j)
                return count
    
    if count == 0 and not empty:
        return 1
    
    return count
    

    def brickTiling(grid): arr = [0] * MAX_ROWS empty_count = 0 N = len(grid) M = len(grid[0])

    for n in range(N):
        for m in range(M):
            if grid[n][m] == '#':
                arr[n] = set_bit(arr[n], m)
            else:
                empty_count += 1
    
        for m in range(M, MAX_COLS):
            arr[n] = set_bit(arr[n], m)
    
    for n in range(N, MAX_ROWS):
        arr[n] = 255
    
    return get_my_count(arr, empty_count) % 1000000007
    

    if name == 'main': fptr = open(os.environ['OUTPUT_PATH'], 'w')

    t = int(input().strip())
    
    for t_itr in range(t):
        first_multiple_input = input().rstrip().split()
    
        n = int(first_multiple_input[0])
        m = int(first_multiple_input[1])
    
        grid = []
    
        for _ in range(n):
            grid_item = input()
            grid.append(grid_item)
    
        result = brickTiling(grid)
    
        fptr.write(str(result) + '\n')
    
    fptr.close()