Vasya has a pack of 54 cards (52 standard cards and 2 distinct jokers). That is all he has at the moment. Not to die from boredom, Vasya plays Solitaire with them.

Vasya lays out nm cards as a rectangle n × m. If there are jokers among them, then Vasya should change them with some of the rest of 54 - nm cards (which are not layed out) so that there were no jokers left. Vasya can pick the cards to replace the jokers arbitrarily. Remember, that each card presents in pack exactly once (i. e. in a single copy). Vasya tries to perform the replacements so that the solitaire was solved.

Vasya thinks that the solitaire is solved if after the jokers are replaced, there exist two non-overlapping squares 3 × 3, inside each of which all the cards either have the same suit, or pairwise different ranks.

Determine by the initial position whether the solitaire can be solved or not. If it can be solved, show the way in which it is possible.

Input

The first line contains integers n and m (3 ≤ n, m ≤ 17, n × m ≤ 52). Next n lines contain m words each. Each word consists of two letters. The jokers are defined as "J1" and "J2" correspondingly. For the rest of the cards, the first letter stands for the rank and the second one — for the suit. The possible ranks are: "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K" and "A". The possible suits are: "C", "D", "H" and "S". All the cards are different.

Output

If the Solitaire can be solved, print on the first line "Solution exists." without the quotes. On the second line print in what way the jokers can be replaced. Three variants are possible:

  * "There are no jokers.", if there are no jokers in the input data.
  * "Replace Jx with y.", if there is one joker. x is its number, and y is the card it should be replaced with.
  * "Replace J1 with x and J2 with y.", if both jokers are present in the input data. x and y here represent distinct cards with which one should replace the first and the second jokers correspondingly.



On the third line print the coordinates of the upper left corner of the first square 3 × 3 in the format "Put the first square to (r, c).", where r and c are the row and the column correspondingly. In the same manner print on the fourth line the coordinates of the second square 3 × 3 in the format "Put the second square to (r, c).".

If there are several solutions to that problem, print any of them.

If there are no solutions, print of the single line "No solution." without the quotes.

See the samples to understand the output format better.

Examples

Input

4 6
2S 3S 4S 7S 8S AS
5H 6H 7H 5S TC AC
8H 9H TH 7C 8C 9C
2D 2C 3C 4C 5C 6C


Output

No solution.

Input

4 6
2S 3S 4S 7S 8S AS
5H 6H 7H J1 TC AC
8H 9H TH 7C 8C 9C
2D 2C 3C 4C 5C 6C


Output

Solution exists.
Replace J1 with 2H.
Put the first square to (1, 1).
Put the second square to (2, 4).


Input

4 6
2S 3S 4S 7S 8S AS
5H 6H 7H QC TC AC
8H 9H TH 7C 8C 9C
2D 2C 3C 4C 5C 6C


Output

Solution exists.
There are no jokers.
Put the first square to (1, 1).
Put the second square to (2, 4).

Note

The pretests cover all the possible output formats.

Source: codeforces | Difficulty: HARD
Tags: Implementation

Complete search


Solutions:
ranks = '23456789TJQKA'
suits = 'CDHS'
(n, m) = [int(i) for i in input().split()]
b = [input().split() for _ in range(n)]
p = [r + s for r in ranks for s in suits]
(j1, j2) = (False, False)
for r in b:
	for c in r:
		if c == 'J1':
			j1 = True
		elif c == 'J2':
			j2 = True
		else:
			p.remove(c)

def valid(n, m):
	r = set()
	s = set()
	for ni in range(n, n + 3):
		for mi in range(m, m + 3):
			c = b[ni][mi]
			if c == 'J1':
				c = j1v
			if c == 'J2':
				c = j2v
			r.add(c[0])
			s.add(c[1])
	return len(r) == 9 or len(s) == 1

def solve():
	global j1v, j2v, n0, m0, n1, m1
	for j1v in p:
		for j2v in p:
			if j1v == j2v:
				continue
			for n0 in range(n - 2):
				for m0 in range(m - 2):
					if not valid(n0, m0):
						continue
					for n1 in range(n - 2):
						for m1 in range(m - 2):
							if n0 + 2 < n1 or n1 + 2 < n0 or m0 + 2 < m1 or (m1 + 2 < m0):
								if valid(n1, m1):
									return True
	return False
if solve():
	print('Solution exists.')
	if j1 and j2:
		print('Replace J1 with {} and J2 with {}.'.format(j1v, j2v))
	elif j1:
		print('Replace J1 with {}.'.format(j1v))
	elif j2:
		print('Replace J2 with {}.'.format(j2v))
	else:
		print('There are no jokers.')
	print('Put the first square to ({}, {}).'.format(n0 + 1, m0 + 1))
	print('Put the second square to ({}, {}).'.format(n1 + 1, m1 + 1))
else:
	print('No solution.')


suits = ['C', 'D', 'H', 'S', 'W']
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']

def parse(c):
	if c == 'J1':
		return 52
	if c == 'J2':
		return 53
	return 13 * suits.index(c[1]) + ranks.index(c[0])

def summarize(cards):
	s = [0] * 4
	r = [0] * 13
	(j1, j2) = (False, False)
	for i in cards:
		if i < 52:
			s[i // 13] += 1
			r[i % 13] += 1
		elif i == 52:
			j1 = True
		else:
			j2 = True
	return (s, r, j1, j2)
(n, m) = map(int, input().split())
board = [[parse(c) for c in input().split()] for _ in range(n)]
pack = set(range(54))
for r in board:
	pack -= set(r)
(ps, pr, pj1, pj2) = summarize(pack)
jc = [[0] * (m - 2) for _ in range(n - 2)]
ji = [[False] * (m - 2) for _ in range(n - 2)]
valid = [[False] * (m - 2) for _ in range(n - 2)]
subs = [[None] * (m - 2) for _ in range(n - 2)]
for ni in range(n - 2):
	for mi in range(m - 2):
		(ss, sr, sj1, sj2) = summarize((board[ni + nj][mi + mj] for nj in range(3) for mj in range(3)))
		if not sj1 and (not sj2):
			if max(ss) == 9 or max(sr) == 1:
				valid[ni][mi] = True
		elif sj1 and sj2:
			jc[ni][mi] = 2
			if max(ss) == 7:
				ssi = ss.index(7)
				for pi in pack:
					if pi // 13 != ssi:
						continue
					for pj in pack:
						if pj == pi:
							continue
						if pj // 13 != ssi:
							continue
						subs[ni][mi] = [pi, pj]
						valid[ni][mi] = True
			if max(sr) == 1:
				for pi in pack:
					if sr[pi % 13] == 1:
						continue
					for pj in pack:
						if pj % 13 == pi % 13:
							continue
						if sr[pj % 13] == 1:
							continue
						subs[ni][mi] = [pi, pj]
						valid[ni][mi] = True
		else:
			jc[ni][mi] = 1
			ji[ni][mi] = 0 if sj1 else 1
			pc = set()
			if max(ss) == 8:
				ssi = ss.index(8)
				for p in pack:
					if p // 13 == ssi:
						pc.add(p)
			if max(sr) == 1:
				for p in pack:
					if sr[p % 13] == 0:
						pc.add(p)
			if len(pc) > 0:
				valid[ni][mi] = True
				subs[ni][mi] = pc

def solve():
	for ni0 in range(n - 2):
		for mi0 in range(m - 2):
			if not valid[ni0][mi0]:
				continue
			for ni1 in range(n - 2):
				for mi1 in range(m - 2):
					if not valid[ni1][mi1]:
						continue
					if (ni1 >= ni0 and ni1 <= ni0 + 2 or (ni0 >= ni1 and ni0 <= ni1 + 2)) and (mi1 >= mi0 and mi1 <= mi0 + 2 or (mi0 >= mi1 and mi0 <= mi1 + 2)):
						continue
					ja = [None, None]
					if jc[ni0][mi0] == 0 and jc[ni1][mi1] == 0:
						return (True, (0, 0), ja, ((ni0, mi0), (ni1, mi1)))
					elif jc[ni0][mi0] == 1 and jc[ni1][mi1] == 1:
						s0 = list(subs[ni0][mi0])
						s1 = list(subs[ni1][mi1])
						if len(s1) == 1 and s1[0] in s0:
							s0.remove(s1[0])
						if len(s0) == 0:
							continue
						ja[ji[ni0][mi0]] = s0[0]
						if s0[0] in s1:
							s1.remove(s0[0])
						ja[ji[ni1][mi1]] = s1[0]
						return (True, (1, 1), ja, ((ni0, mi0), (ni1, mi1)))
					elif jc[ni0][mi0] == 2:
						ja = subs[ni0][mi0]
					elif jc[ni1][mi1] == 2:
						ja = subs[ni1][mi1]
					elif jc[ni0][mi0] == 1:
						ja[ji[ni0][mi0]] = list(subs[ni0][mi0])[0]
					else:
						ja[ji[ni1][mi1]] = list(subs[ni1][mi1])[0]
					return (True, (jc[ni0][mi0], jc[ni1][mi1]), ja, ((ni0, mi0), (ni1, mi1)))
	return (False, 0, [None, None], None)
(v, jc, j, c) = solve()
if 52 in pack:
	pack.remove(52)
if 53 in pack:
	pack.remove(53)
if j[0] is not None:
	pack.remove(j[0])
if j[1] is not None:
	pack.remove(j[1])
if not pj1 and j[0] is None:
	j[0] = pack.pop()
if not pj2 and j[1] is None:
	j[1] = pack.pop()
for i in range(2):
	if j[i] is not None:
		j[i] = ranks[j[i] % 13] + suits[j[i] // 13]
if not v:
	print('No solution.')
else:
	print('Solution exists.')
	if pj1 and pj2:
		print('There are no jokers.')
	elif not pj1 and (not pj2):
		print('Replace J1 with {} and J2 with {}.'.format(j[0], j[1]))
	elif not pj1:
		print('Replace J1 with {}.'.format(j[0]))
	else:
		print('Replace J2 with {}.'.format(j[1]))
	print('Put the first square to ({}, {}).'.format(c[0][0] + 1, c[0][1] + 1))
	print('Put the second square to ({}, {}).'.format(c[1][0] + 1, c[1][1] + 1))


(n, m) = map(int, input().split())
num = '23456789TJQKA'
col = 'CDHS'
all = []
for i in num:
	for j in col:
		all.append(i + j)
my = [[] for x in range(n)]
j1 = 0
j2 = 0
for i in range(n):
	my[i] = input().split()
	for j in range(m):
		if my[i][j][1] == '1':
			j1 = (i, j)
		elif my[i][j][1] == '2':
			j2 = (i, j)
		else:
			all.remove(my[i][j])

def i_seg(a, b, c, d):
	return a <= d and b >= c

def i_sq(a, b):
	return i_seg(a[0], a[2], b[0], b[2]) and i_seg(a[1], a[3], b[1], b[3])

def suit(cards, x, y):
	col = set()
	num = set()
	for i in range(x, x + 3):
		for j in range(y, y + 3):
			col.add(cards[i][j][1])
			num.add(cards[i][j][0])
	return len(col) == 1 or len(num) == 9

def ok(cards, n, m):
	for a in range(n - 2):
		for b in range(m - 2):
			if suit(cards, a, b):
				for c in range(n - 2):
					for d in range(m - 2):
						if not i_sq((a, b, a + 2, b + 2), (c, d, c + 2, d + 2)) and suit(cards, c, d):
							return (a, b, c, d)
	return 0
for i in all:
	for j in all:
		if i != j:
			new = my
			if j1 != 0:
				new[j1[0]][j1[1]] = i
			if j2 != 0:
				new[j2[0]][j2[1]] = j
			q = ok(new, n, m)
			if q:
				print('Solution exists.')
				if j1 == 0 and j2 == 0:
					print('There are no jokers.')
				elif j1 != 0 and j2 != 0:
					print('Replace J1 with %s and J2 with %s.' % (i, j))
				elif j1 != 0:
					print('Replace J1 with %s.' % i)
				else:
					print('Replace J2 with %s.' % j)
				print('Put the first square to (%d, %d).' % (q[0] + 1, q[1] + 1))
				print('Put the second square to (%d, %d).' % (q[2] + 1, q[3] + 1))
				quit()
print('No solution.')


from sys import stdin
import math
from copy import deepcopy

def find_jokers(grid, n, m):
	jokers = []
	for i in range(n):
		for j in range(m):
			if grid[i][j] == 'J1' and len(jokers) > 0:
				jokers.insert(0, [i, j])
			elif grid[i][j] == 'J1' or grid[i][j] == 'J2':
				jokers.append([i, j])
	return jokers

def get_remain(grid, n, m):
	total = set()
	for typ in ['D', 'S', 'H', 'C']:
		for rank in ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']:
			total.add(rank + typ)
	grid_set = set()
	for i in range(n):
		for j in range(m):
			grid_set.add(grid[i][j])
	r = total.difference(grid_set)
	r = list(r)
	return r

def replace(cgrid, x, y, item):
	cgrid[x][y] = item

def first_condition(grid, x, y):
	suit = set()
	for i in range(x, x + 3):
		for j in range(y, y + 3):
			suit.add(grid[i][j][1])
	if len(suit) == 1:
		return True
	else:
		return False

def second_condition(grid, x, y):
	rank = set()
	for i in range(x, x + 3):
		for j in range(y, y + 3):
			rank.add(grid[i][j][0])
	if len(rank) == 9:
		return True
	else:
		return False

def check_mark(mark, x, y):
	for i in range(x, x + 3):
		for j in range(y, y + 3):
			if mark[i][j] == True:
				return False
	else:
		return True

def make_mark(mark, x, y):
	for i in range(x, x + 3):
		for j in range(y, y + 3):
			mark[i][j] = True

def check(grid, n, m):
	count = 0
	mark = [[False for x in range(m)] for y in range(n)]
	for i in range(n):
		if i + 3 <= n:
			for j in range(m):
				if j + 3 <= m:
					if check_mark(mark, i, j):
						if first_condition(grid, i, j) or second_condition(grid, i, j):
							count += 1
							make_mark(mark, i, j)
	if count >= 2:
		return True
	else:
		return False

def get_ans(grid, n, m):
	ans = []
	mark = [[False for x in range(m)] for y in range(n)]
	for i in range(n):
		if i + 3 <= n:
			for j in range(m):
				if j + 3 <= m:
					if check_mark(mark, i, j):
						if first_condition(grid, i, j) or second_condition(grid, i, j):
							ans.append([i, j])
							make_mark(mark, i, j)
	return ans
(n, m) = list(map(int, stdin.readline().split()))
grid = []
for _ in range(n):
	grid.append(list(stdin.readline().split()))
jokers = find_jokers(grid, n, m)
remaining = get_remain(grid, n, m)
if len(jokers) == 2:
	for i in range(len(remaining) - 1):
		for j in range(i + 1, len(remaining)):
			cgrid = deepcopy(grid)
			(fx, fy) = jokers[0]
			(sx, sy) = jokers[1]
			replace(cgrid, fx, fy, remaining[i])
			replace(cgrid, sx, sy, remaining[j])
			if check(cgrid, n, m):
				print('Solution exists.')
				print('Replace J1 with ' + str(remaining[i]) + ' and J2 with ' + str(remaining[j]) + '.')
				ans = get_ans(cgrid, n, m)
				print('Put the first square to ' + '(' + str(ans[0][0] + 1) + ', ' + str(ans[0][1] + 1) + ').')
				print('Put the second square to ' + '(' + str(ans[1][0] + 1) + ', ' + str(ans[1][1] + 1) + ').')
				exit()
			else:
				cgrid = deepcopy(grid)
				replace(cgrid, sx, sy, remaining[i])
				replace(cgrid, fx, fy, remaining[j])
				if check(cgrid, n, m):
					print('Solution exists.')
					print('Replace J1 with ' + str(remaining[j]) + ' and J2 with ' + str(remaining[i]) + '.')
					ans = get_ans(cgrid, n, m)
					print('Put the first square to ' + '(' + str(ans[0][0] + 1) + ', ' + str(ans[0][1] + 1) + ').')
					print('Put the second square to ' + '(' + str(ans[1][0] + 1) + ', ' + str(ans[1][1] + 1) + ').')
					exit()
				else:
					pass
elif len(jokers) == 1:
	for i in range(len(remaining)):
		cgrid = deepcopy(grid)
		(fx, fy) = jokers[0]
		replace(cgrid, fx, fy, remaining[i])
		if check(cgrid, n, m):
			print('Solution exists.')
			print('Replace ' + str(grid[fx][fy]) + ' with ' + str(remaining[i]) + '.')
			ans = get_ans(cgrid, n, m)
			print('Put the first square to ' + '(' + str(ans[0][0] + 1) + ', ' + str(ans[0][1] + 1) + ').')
			print('Put the second square to ' + '(' + str(ans[1][0] + 1) + ', ' + str(ans[1][1] + 1) + ').')
			exit()
		else:
			continue
elif check(grid, n, m):
	print('Solution exists.')
	print('There are no jokers.')
	ans = get_ans(grid, n, m)
	print('Put the first square to ' + '(' + str(ans[0][0] + 1) + ', ' + str(ans[0][1] + 1) + ').')
	print('Put the second square to ' + '(' + str(ans[1][0] + 1) + ', ' + str(ans[1][1] + 1) + ').')
	exit()
else:
	pass
print('No solution.')


allCards = [value + suit for value in ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A'] for suit in ['C', 'D', 'H', 'S']]
(n, m) = map(lambda x: int(x), input().split(' '))
cards = []
for i in range(n):
	cards.append(input().split(' '))
availableCards = allCards
for arr in cards:
	for card in arr:
		if card != 'J1' and card != 'J2':
			availableCards.remove(card)

def joker2(i: int, j: int) -> [bool, bool, bool, set]:
	usedValues = set()
	didFoundJoker1 = False
	didFoundJoker2 = False
	for i1 in range(i, i + 3):
		for j1 in range(j, j + 3):
			if cards[i1][j1] == 'J1':
				didFoundJoker1 = True
			elif cards[i1][j1] == 'J2':
				didFoundJoker2 = True
			elif cards[i1][j1][0] not in usedValues:
				usedValues.add(cards[i1][j1][0])
			else:
				return [False, False, False, set()]
	res = set()
	for card in availableCards:
		if card[0] not in usedValues:
			res.add(card)
	isTrue = True
	if didFoundJoker1 or didFoundJoker2:
		isTrue = False
		for card in res:
			if isTrue:
				break
			for i1 in range(i, i + 3):
				if isTrue:
					break
				for j1 in range(j, j + 3):
					if cards[i1][j1] not in ['J1', 'J2'] and cards[i1][j1][0] != card[0]:
						isTrue = True
						break
	return [isTrue, didFoundJoker1, didFoundJoker2, res]
(ansi1, ansj1, ansi2, ansj2) = (0, 0, 0, 0)
replaceJoker1 = None
replaceJoker2 = None

def joker1(i: int, j: int) -> bool:
	global replaceJoker1
	global replaceJoker2
	global ansi1, ansj1, ansi2, ansj2
	if not (i + 2 < n and j + 2 < m):
		return False
	(didFound1, didFindJoker1, didFindJoker2, strings) = joker2(i, j)
	if not didFound1:
		return False
	for i1 in range(n):
		for j1 in range(m):
			if (i1 > i + 2 or j1 > j + 2) and i1 + 2 < n and (j1 + 2 < m):
				(didFound2, didFindJoker21, didFindJoker22, strings2) = joker2(i1, j1)
				if (didFindJoker1 or didFindJoker2) and (didFindJoker21 or didFindJoker22):
					xor = strings2 ^ strings
					x1 = xor & strings
					x2 = xor & strings2
					if x1 and x2:
						if didFindJoker1 and didFindJoker22:
							replaceJoker1 = x1.pop()
							replaceJoker2 = x2.pop()
						else:
							replaceJoker1 = x2.pop()
							replaceJoker2 = x1.pop()
						(ansi1, ansj1, ansi2, ansj2) = (i, j, i1, j1)
						return True
				elif didFindJoker21 and didFindJoker22:
					if len(strings2) >= 2:
						replaceJoker1 = strings2.pop()
						replaceJoker2 = strings2.pop()
						(ansi1, ansj1, ansi2, ansj2) = (i, j, i1, j1)
						return True
				elif didFound2 and didFindJoker1 and didFindJoker2:
					stringsx = list(strings)
					(ansi1, ansj1, ansi2, ansj2) = (i, j, i1, j1)
					for i in range(len(stringsx)):
						for j in range(i + 1, len(stringsx)):
							if stringsx[i][0] != stringsx[j][0]:
								replaceJoker1 = stringsx[i]
								replaceJoker2 = stringsx[j]
								return True
					continue
				elif didFound2 and didFindJoker21 and didFindJoker22:
					stringsx = list(strings2)
					(ansi1, ansj1, ansi2, ansj2) = (i, j, i1, j1)
					for i in range(len(stringsx)):
						for j in range(i + 1, len(stringsx)):
							if stringsx[i][0] != stringsx[j][0]:
								replaceJoker1 = stringsx[i]
								replaceJoker2 = stringsx[j]
								return True
					continue
				elif didFound2:
					if didFindJoker1:
						if not strings:
							continue
						replaceJoker1 = strings.pop()
					if didFindJoker2:
						if not strings:
							continue
						replaceJoker2 = strings.pop()
					if didFindJoker21:
						if not strings2:
							continue
						replaceJoker1 = strings2.pop()
					if didFindJoker22:
						if not strings2:
							continue
						replaceJoker2 = strings2.pop()
					(ansi1, ansj1, ansi2, ansj2) = (i, j, i1, j1)
					return True
	return False
didFound = False
for i in range(n):
	if didFound:
		break
	for j in range(m):
		res = joker1(i, j)
		if res:
			print('Solution exists.')
			(j1f, j2f) = (False, False)
			for c in cards:
				for card in c:
					if card == 'J1':
						j1f = True
					elif card == 'J2':
						j2f = True
			if j1f and (not replaceJoker1):
				replaceJoker1 = availableCards.pop()
				while availableCards and replaceJoker1 == replaceJoker2:
					replaceJoker1 = availableCards.pop()
			if j2f and (not replaceJoker2):
				replaceJoker2 = availableCards.pop()
			if replaceJoker2 and replaceJoker1:
				print(f'Replace J1 with {replaceJoker1} and J2 with {replaceJoker2}.')
			elif replaceJoker1:
				print(f'Replace J1 with {replaceJoker1}.')
			elif replaceJoker2:
				print(f'Replace J2 with {replaceJoker2}.')
			else:
				print('There are no jokers.')
			print(f'Put the first square to ({ansi1 + 1}, {ansj1 + 1}).')
			print(f'Put the second square to ({ansi2 + 1}, {ansj2 + 1}).')
			didFound = True
			break
if not didFound:
	print('No solution.')


(n, m) = map(int, input().split())
dignities = '23456789TJQKA'
colors = 'CDHS'
all_cards = []
for i in dignities:
	for j in colors:
		all_cards.append(i + j)
my_cards = [[] for x in range(n)]
joker1 = 0
joker2 = 0
for i in range(n):
	my_cards[i] = input().split()
	for j in range(m):
		if my_cards[i][j][1] == '1':
			joker1 = (i, j)
		elif my_cards[i][j][1] == '2':
			joker2 = (i, j)
		else:
			all_cards.remove(my_cards[i][j])

def intersect_segments(a, b, c, d):
	if a > b:
		(a, b) = (b, a)
	if c > d:
		(c, d) = (d, c)
	return a <= d and b >= c

def intersect_squares(a, b):
	return intersect_segments(a[0], a[2], b[0], b[2]) and intersect_segments(a[1], a[3], b[1], b[3])

def suitable(cards, x, y):
	colors = set()
	dignities = set()
	for i in range(x, x + 3):
		for j in range(y, y + 3):
			colors.add(cards[i][j][1])
			dignities.add(cards[i][j][0])
	return len(colors) == 1 or len(dignities) == 9

def ok(cards, n, m):
	for a in range(n - 2):
		for b in range(m - 2):
			if suitable(cards, a, b):
				for c in range(n - 2):
					for d in range(m - 2):
						if not intersect_squares((a, b, a + 2, b + 2), (c, d, c + 2, d + 2)) and suitable(cards, c, d):
							return (a, b, c, d)
	return 0
for i in all_cards:
	for j in all_cards:
		if i != j:
			new_cards = my_cards
			if joker1 != 0:
				new_cards[joker1[0]][joker1[1]] = i
			if joker2 != 0:
				new_cards[joker2[0]][joker2[1]] = j
			if ok(new_cards, n, m):
				print('Solution exists.')
				if joker1 == 0 and joker2 == 0:
					print('There are no jokers.')
				elif joker1 != 0 and joker2 != 0:
					print('Replace J1 with %s and J2 with %s.' % (i, j))
				elif joker1 != 0:
					print('Replace J1 with %s.' % i)
				else:
					print('Replace J2 with %s.' % j)
				tmp = ok(new_cards, n, m)
				print('Put the first square to (%d, %d).' % (tmp[0] + 1, tmp[1] + 1))
				print('Put the second square to (%d, %d).' % (tmp[2] + 1, tmp[3] + 1))
				quit()
print('No solution.')


(n, m) = map(int, input().split())
dignities = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']
colors = ['C', 'D', 'H', 'S']
all_cards = []
for i in dignities:
	for j in colors:
		all_cards.append(i + j)
my_cards = [[] for x in range(n)]
joker1 = 0
joker2 = 0
for i in range(n):
	my_cards[i] = input().split()
	for j in range(m):
		if my_cards[i][j][1] == '1':
			joker1 = (i, j)
		elif my_cards[i][j][1] == '2':
			joker2 = (i, j)
		else:
			all_cards.remove(my_cards[i][j])

def intersect_segments(a, b, c, d):
	if a > b:
		(a, b) = (b, a)
	if c > d:
		(c, d) = (d, c)
	return a <= d and b >= c

def intersect_squares(a, b):
	return intersect_segments(a[0], a[2], b[0], b[2]) and intersect_segments(a[1], a[3], b[1], b[3])

def suitable(cards, x, y):
	colors = set()
	dignities = set()
	for i in range(x, x + 3):
		for j in range(y, y + 3):
			colors.add(cards[i][j][1])
			dignities.add(cards[i][j][0])
	return len(colors) == 1 or len(dignities) == 9

def ok(cards, n, m):
	for a in range(n - 2):
		for b in range(m - 2):
			if suitable(cards, a, b):
				for c in range(n - 2):
					for d in range(m - 2):
						if not intersect_squares((a, b, a + 2, b + 2), (c, d, c + 2, d + 2)) and suitable(cards, c, d):
							return (a, b, c, d)
	return 0
for i in all_cards:
	for j in all_cards:
		if i != j:
			new_cards = my_cards
			if joker1 != 0:
				new_cards[joker1[0]][joker1[1]] = i
			if joker2 != 0:
				new_cards[joker2[0]][joker2[1]] = j
			if ok(new_cards, n, m):
				print('Solution exists.')
				if joker1 == 0 and joker2 == 0:
					print('There are no jokers.')
				elif joker1 != 0 and joker2 != 0:
					print('Replace J1 with %s and J2 with %s.' % (i, j))
				elif joker1 != 0:
					print('Replace J1 with %s.' % i)
				else:
					print('Replace J2 with %s.' % j)
				tmp = ok(new_cards, n, m)
				print('Put the first square to (%d, %d).' % (tmp[0] + 1, tmp[1] + 1))
				print('Put the second square to (%d, %d).' % (tmp[2] + 1, tmp[3] + 1))
				quit()
print('No solution.')


def get_cards():
	(n, m) = map(int, input().split())
	lis = [[]] * n
	for i in range(n):
		lis[i] = list(map(str, input().split()))
	return (n, m, lis)

def find_remains(cards):
	remains = []
	ranks = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']
	suits = ['C', 'D', 'H', 'S']
	for r in ranks:
		for s in suits:
			remains.append(r + s)
	remains += ['J1', 'J2']
	for i in range(cards[0]):
		for j in range(cards[1]):
			remains.remove(cards[2][i][j])
	return remains

def condition_1(ranks):
	r = set(ranks)
	if len(r) < len(ranks):
		return 1
	else:
		return 0

def condition_2(suits):
	r = set(suits)
	if len(r) == 1:
		return 0
	else:
		return 1

def find_solution(cards):
	lis = cards[2]
	positions = []
	result = 1
	position = []
	for i in range(cards[0] - 2):
		for j in range(cards[1] - 2):
			positions.append((i, j))
	for p in positions:
		positions_2 = positions[:]
		if result == 0:
			break
		i = p[0]
		j = p[1]
		nine_1 = [lis[i][j], lis[i][j + 1], lis[i][j + 2], lis[i + 1][j], lis[i + 1][j + 1], lis[i + 1][j + 2], lis[i + 2][j], lis[i + 2][j + 1], lis[i + 2][j + 2]]
		nine_1_p = []
		for a in range(-2, 3):
			for b in range(-2, 3):
				nine_1_p.append((i + a, j + b))
		for c in nine_1_p:
			if c in positions_2:
				positions_2.remove(c)
		for q in positions_2:
			if result == 0:
				break
			i = q[0]
			j = q[1]
			nine_2 = [lis[i][j], lis[i][j + 1], lis[i][j + 2], lis[i + 1][j], lis[i + 1][j + 1], lis[i + 1][j + 2], lis[i + 2][j], lis[i + 2][j + 1], lis[i + 2][j + 2]]
			(ranks_1, ranks_2) = ([], [])
			(suits_1, suits_2) = ([], [])
			for card in nine_1:
				ranks_1.append(card[0])
				suits_1.append(card[1])
			result_1_1 = condition_1(ranks_1)
			result_1_2 = condition_2(suits_1)
			for card in nine_2:
				ranks_2.append(card[0])
				suits_2.append(card[1])
			result_2_1 = condition_1(ranks_2)
			result_2_2 = condition_2(suits_2)
			if result_1_1 * result_1_2 == 0 and result_2_1 * result_2_2 == 0:
				result = 0
				position = [p, q]
	result = [result, position]
	return result

def find_Jocker(cards):
	n = cards[0]
	m = cards[1]
	(J1, J2) = (0, 0)
	for i in range(n):
		for j in range(m):
			if cards[2][i][j] == 'J1':
				J1 = (i, j)
			if cards[2][i][j] == 'J2':
				J2 = (i, j)
	positions = (J1, J2)
	return positions
cards = get_cards()
if cards[0] < 3 or cards[1] < 3:
	result = [1]
elif cards[0] < 6 and cards[1] < 6:
	result = [1]
else:
	remains = find_remains(cards)
	jocker = find_Jocker(cards)
	changed = [0, 0]
	if jocker[0] == 0 and jocker[1] == 0:
		result = find_solution(cards)
	elif jocker[0] != 0 and jocker[1] == 0:
		remains.remove('J2')
		for remain in remains:
			cards[2][jocker[0][0]][jocker[0][1]] = remain
			result = find_solution(cards)
			if result[0] == 0:
				changed = [remain, 0]
				break
	elif jocker[1] != 0 and jocker[0] == 0:
		remains.remove('J1')
		for remain in remains:
			cards[2][jocker[1][0]][jocker[1][1]] = remain
			result = find_solution(cards)
			if result[0] == 0:
				changed = [0, remain]
				break
	else:
		remains_2 = remains[:]
		for remain_1 in remains:
			cards[2][jocker[1][0]][jocker[1][1]] = remain_1
			remains_2.remove(remain_1)
			for remain_2 in remains_2:
				cards[2][jocker[0][0]][jocker[0][1]] = remain_2
				result = find_solution(cards)
				if result[0] == 0:
					changed[0] = remain_2
					break
			remains_2 = remains[:]
			if result[0] == 0:
				changed[1] = remain_1
				break
if result[0] == 1:
	print('No solution.')
if result[0] == 0:
	print('Solution exists.')
	if changed[0] != 0 and changed[1] != 0:
		print('Replace J1 with ' + changed[0] + ' and J2 with ' + changed[1] + '.')
	elif changed[0] != 0:
		print('Replace J1 with ' + changed[0] + '.')
	elif changed[1] != 0:
		print('Replace J2 with ' + changed[1] + '.')
	else:
		print('There are no jokers.')
	print('Put the first square to (' + str(result[1][0][0] + 1) + ', ' + str(result[1][0][1] + 1) + ').')
	print('Put the second square to (' + str(result[1][1][0] + 1) + ', ' + str(result[1][1][1] + 1) + ').')


import itertools

class Solitaire:

	def __init__(self):
		(self.n, self.m) = map(int, input().split())
		self.table = [input().split() for i in range(self.n)]
		ranks = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']
		suits = ['C', 'D', 'H', 'S']
		deck = set(('%s%s' % card for card in itertools.product(ranks, suits)))
		self.J1_position = None
		self.J2_position = None
		for (r, c) in itertools.product(range(self.n), range(self.m)):
			card = self.table[r][c]
			deck.discard(card)
			if card == 'J1':
				self.J1_position = (r, c)
			elif card == 'J2':
				self.J2_position = (r, c)
		self.unused_cards = list(deck)
		self.unused_cards.sort()

	def is_solved_square(self, r, c):
		cards = [self.table[r + ro][c + co] for (ro, co) in itertools.product(range(3), range(3))]
		suits = set((card[1] for card in cards))
		ranks = set((card[0] for card in cards))
		solved = len(suits) == 1 or len(ranks) == 9
		return solved

	def is_solved(self):
		all_positions = itertools.product(range(self.n - 2), range(self.m - 2))
		all_solved_squares = [(r, c) for (r, c) in all_positions if self.is_solved_square(r, c)]
		for ((r1, c1), (r2, c2)) in itertools.combinations(all_solved_squares, 2):
			if abs(r1 - r2) >= 3 or abs(c1 - c2) >= 3:
				return ((r1, c1), (r2, c2))
		return None

	def replace_card(self, position, card):
		(r, c) = position
		self.table[r][c] = card

	def print_solution(self, joker_line, solution):
		if solution == None:
			print('No solution.')
		else:
			((r1, c1), (r2, c2)) = solution
			print('Solution exists.')
			print(joker_line)
			print('Put the first square to (%d, %d).' % (r1 + 1, c1 + 1))
			print('Put the second square to (%d, %d).' % (r2 + 1, c2 + 1))
		exit()

	def solve(self):
		if self.J1_position != None and self.J2_position != None:
			for (replacement1, replacement2) in itertools.permutations(self.unused_cards, 2):
				self.replace_card(self.J1_position, replacement1)
				self.replace_card(self.J2_position, replacement2)
				solution = self.is_solved()
				if solution:
					self.print_solution('Replace J1 with %s and J2 with %s.' % (replacement1, replacement2), solution)
		elif self.J1_position != None:
			for replacement in self.unused_cards:
				self.replace_card(self.J1_position, replacement)
				solution = self.is_solved()
				if solution:
					self.print_solution('Replace J1 with %s.' % replacement, solution)
		elif self.J2_position != None:
			for replacement in self.unused_cards:
				self.replace_card(self.J2_position, replacement)
				solution = self.is_solved()
				if solution:
					self.print_solution('Replace J2 with %s.' % replacement, solution)
		else:
			solution = self.is_solved()
			self.print_solution('There are no jokers.', solution)
		self.print_solution('', None)
Solitaire().solve()