Given a random bingo card and an array of called numbers, determine if you have a bingo!

*Parameters*: `card` and `numbers` arrays.

*Example input*:
```
card = [
  ['B', 'I', 'N', 'G', 'O'],
  [1, 16, 31, 46, 61],
  [3, 18, 33, 48, 63],
  [5, 20, 'FREE SPACE', 50, 65],
  [7, 22, 37, 52, 67],
  [9, 24, 39, 54, 69]
]

numbers = ['B1', 'I16', 'N31', 'G46', 'O61']
```

*Output*: ```true``` if you have a bingo, ```false``` if you do not.

You have a bingo if you have a complete row, column, or diagonal - each consisting of 5 numbers, or 4 numbers and the FREE SPACE.

### Constraints:
Each column includes 5 random numbers within a range (inclusive):  
`'B':  1 - 15`  
`'I': 16 - 30`  
`'N': 31 - 45`  
`'G': 46 - 60`  
`'O': 61 - 75`  

### Notes:
* All numbers will be within the above ranges.
* `FREE SPACE` will not be included in the numbers array but always counts towards a bingo.
* The first array of the card is the column headers.
* `numbers` array will include only tiles present in the card, without duplicates.

___

## Examples:
```
card:
------------------------------
| B  | I  |   N    | G  | O  |
==============================
| 2  | 17 |   32   | 47 | 74 |
------------------------------
| 14 | 25 |   44   | 48 | 62 |
------------------------------
| 5  | 22 | 'FREE' | 49 | 67 |
------------------------------
| 10 | 23 |   45   | 59 | 73 |
------------------------------
| 1  | 30 |   33   | 58 | 70 |
------------------------------

numbers: ['N32', 'N45', 'B7', 'O75', 'N33', 'N41, 'I18', 'N44']

// return true - you have bingo at ['N32', 'N44', 'FREE', 'N45', 'N33']
```

The inspiration for this kata originates from completing the [Bingo Card](http://www.codewars.com/kata/566d5e2e57d8fae53c00000c) by FrankK.

Difficulty: introductory

Starter code:

def bingo(card, numbers):
	

Solutions:
def bingo(card, numbers):
    
    rc, cc, dc = [0]*5, [0]*5, [1]*2            # rows count, columns count, diag counts
    rc[2] = cc[2] = 1                           # preaffect 'FREE SPACE'
    s = set(numbers)
    
    for x,line in enumerate(card[1:]):
        for y,(c,n) in enumerate(zip(card[0], line)):
            tile = f'{c}{n}'
            if tile in s:
                rc[x] += 1
                cc[y] += 1
                if x == y:   dc[0] += 1         # main diag
                if x+y == 4: dc[1] += 1         # secundary diag
    return 5 in rc + cc + dc

def bingo(card, numbers):
    decode = lambda s: True if s == 'FREE SPACE' else int(s)
    game = [
        [decode(x) for x in row]
        for row in card[1:]
    ]

    # Decode each 'number' into a column and number
    for s in numbers:
        col = 'BINGO'.find(s[0])
        n = int(s[1:])
        for row in range(5):
            val = game[row][col]
            if val is not True and val == n:
                # We have that number in the column, mark it as found
                game[row][col] = True
                break

    # Extract all the straight lines through the board
    lines = game                                               # rows 
    lines += [[row[col] for row in game] for col in range(5)]  # cols
    lines += [[game[i][i] for i in range(5)]]                  # leading diagonal
    lines += [[game[i][4-i] for i in range(5)]]                # secondary diagonal
    # See if any lines are all True
    return any(all(x is True for x in line) for line in lines)

def bingo(card, numbers):
    card = card[1:]

    indexes = {
        str(x): (i, j)
        for i, row in enumerate(card)
        for j, x in enumerate(row)
    }
    board = [[0] * 5 for _ in range(5)]
    for n in numbers + [' FREE SPACE']:
        try:
            i, j = indexes[n[1:]]
            board[i][j] = 1
        except KeyError:
            pass
    return (
        any(sum(row) == 5 for row in board)
        or any(sum(row) == 5 for row in zip(*board))
        or all(board[i][i] for i in range(5))
        or all(board[i][4-i] for i in range(5))
    )

def bingo(card, numbers):
    grid = card[1:]
    draw = set(int(n[1:]) for n in numbers if n[0] != "F") | {"FREE SPACE"}
    lines = [set(l) for l in grid]
    columns = [set(c) for c in zip(*grid)]
    diagonals = [set(d[(-1)**p * i] for i, d in enumerate(grid, p)) for p in (0, 1)]
    rows = lines + columns + diagonals
    return any(row.issubset(draw) for row in rows)


def matches(set,digits):
    count = 0   
    if 'FREE SPACE' in set:
        count += 1
    for digit in digits:
        if int(digit[1:]) in set:
            count += 1           
    return count

def bingo(card, numbers):

    for set in card:
        count_row = matches(set,numbers)
        if count_row == 5:
            break
            
    for column in range(5):
        cols = []
        for row in range(1,6):
            cols.append(card[row][column])
        count_col = matches(cols, numbers)
        if count_col == 5:
            break

    diag_r = []
    diag_l = [] 
    for i in range(5):
        diag_r.append(card[i+1][i])
        diag_l.append(card[5-i][i])
    
    return count_row == 5 or count_col == 5 or matches(diag_r, numbers) == 5 or matches(diag_l, numbers) == 5

from copy import copy, deepcopy

def bingo(card, numbers):
    copy = deepcopy(card)
    def checkEqual(e, x):
        for i in range (1, len(copy)):
            if copy[i][x] == int(e[1:]):
                copy[i][x] = None

    def markBoard():
        for e in numbers:
            if e[0] == 'B':
                checkEqual(e, 0)
            if e[0] == 'I':
                checkEqual(e, 1)
            elif e[0] == 'N':
                checkEqual(e, 2)
            elif e[0] == 'G':
                checkEqual(e, 3)
            elif e[0] == 'O':
                checkEqual(e, 4)
        
    def checkVerticle():
        for i in range (1, len(copy)):
            for j in range(len(copy) - 1):
                if copy[i][j] != None and copy[i][j] != 'FREE SPACE':
                    break
            else:
                return True
        return False
    
    
    def checkLateral():
        for i in range (len(copy) - 1):
            for j in range(1, len(copy)):
                if copy[j][i] != None and copy[j][i] != 'FREE SPACE':
                    break
            else:
                return True
        return False

    
    def checkCross():
        for i in range(1, len(copy)):
            if copy[i][i-1] != None and copy[i][i-1] != 'FREE SPACE':
                break
        else:
            return True
        
        for i in range(1, len(copy)):
            if copy[-i][i-1] != None and copy[-i][i-1] != 'FREE SPACE':
                break
        else:
            return True

        return False
        
    
    markBoard()
    t = checkVerticle() or checkLateral() or checkCross()
    
    return t
    

def printBoard(card):
    for i in range(len(card)):
        for j in range(len(card) - 1):
            print(card[i][j], '\t', end='')
        print()


def bingo(card, numbers):
    card = card[1:]
    c = 'BINGO'
    r =[]
    
    #col
    col = []
    for i,v in enumerate(c):
        for j in range(5):
            s = f'{v}{card[j][i]}'
            if s != 'NFREE SPACE':
                col.append(s)
        r.append(col)
        col = []
            
    #row
    row = []
    for j in range(5):
        for i,v in enumerate(c):
            s = f'{v}{card[j][i]}'
            if s != 'NFREE SPACE':
                row.append(s)
        r.append(row)
        row = []
            
    #down diag
    dd = []
    for i in range(5):
        s = f'{c[i]}{card[i][i]}'
        if s != 'NFREE SPACE':
            dd.append(s)
    r.append(dd)
        
    #up diag
    du = []
    for i in range(4,-1,-1):
        s = f'{c[4-i]}{card[i][4-i]}'
        if s != 'NFREE SPACE':
            du.append(s)
    r.append(du)
    
    for x in r:
        if all(i in numbers for i in x):
            return 1
    return 0

def bingo(c, n):
    r=range(5)
    q=[[(x in [int(w[1:])for w in n])or x=='FREE SPACE'for x in l]for l in c[1:]]
    return any(all(x)for x in[l for l in q]+[[l[i]for l in q]for i in r]+[[q[i][i]for i in r]]+[[q[i][4-i]for i in r]])

def bingo(card, numbers):
    
    card[3][2] = 'X'
    parsed_num = [int(x[1:len(x)]) for x in numbers]
    
    for n in parsed_num:
        card = [['X' if x == n else x for x in y] for y in card]
    
    if (check_rows(card)) or (check_diag2 (card)) or (check_diag1 (card)) or (check_columns (card)) is True:
        return True
    else:
        return False 
    
def check_columns (card):
    m = 0
    templist = []
    while m<5:
        for k in range (1,6):
            templist.append(card[k][m])
        if templist == ['X','X','X','X','X']:
            return True
        else:
            templist.clear()
            m +=1
            continue
    return False
        
def check_diag1 (card):
    templist = []
    for i in range (1,6):
        templist.append(card[i][i-1])
    if templist == ['X','X','X','X','X']:
        return True
    else:
        return False

def check_diag2 (card):
    templist = []
    for i in range (0,5):
        templist.append(card[5-i][i])
    if templist == ['X','X','X','X','X']:
        return True
    else:
        return False
    
def check_rows (card):
    for i in range (1,6): #check rows
        if card[i] == ['X','X','X','X','X']:
            return True
        else:
            continue
    return False
    



def bingo(card, numbers):
    card_copy = list(card)
    card_copy.remove(card_copy[0])
    card_copy[2][2] = 0
    
    numbers = [int(x[1:]) for x in numbers]
    
    marked_card = [[0 if card_copy[row][col] == 0 else 0 if card_copy[row][col] in numbers else 1 for col in range(5)] for row in range(5)]
    
    for row in range(5):
      if sum(marked_card[row]) == 0:
        return True
    
    for col in range(5):
      if sum([marked_card[row][col] for row in range(5)]) == 0:
        return True
        
    if sum([marked_card[position][position] for position in range(5)]) == 0:
      return True
      
    if sum([marked_card[row][col] for col in range(5) for row in range(5) if (row + col) == 4]) == 0:
      return True
      
    return False