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.

Source: codewars | Difficulty: EASY
Tags: Fundamentals

Data structures

Game theory

Starter code: def bingo(card, numbers):
	

Solutions:
def bingo(card, numbers):
	(rc, cc, dc) = ([0] * 5, [0] * 5, [1] * 2)
	rc[2] = cc[2] = 1
	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
				if x + y == 4:
					dc[1] += 1
	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:]]
	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:
				game[row][col] = True
				break
	lines = game
	lines += [[row[col] for row in game] for col in range(5)]
	lines += [[game[i][i] for i in range(5)]]
	lines += [[game[i][4 - i] for i in range(5)]]
	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 = []
	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 = []
	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 = []
	dd = []
	for i in range(5):
		s = f'{c[i]}{card[i][i]}'
		if s != 'NFREE SPACE':
			dd.append(s)
	r.append(dd)
	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):
		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