#include <bits/stdc++.h>
using namespace std;
string A = "23456789TJQKA";
string B = "CDHS";
vector<string> cards;
int n, m;
vector<vector<string> > grid;
map<string, pair<int, int> > exist;
bool overlap(int x1, int y1, int x2, int y2) {
  if (x1 + 3 <= x2) return false;
  if (x2 + 3 <= x1) return false;
  if (y1 + 3 <= y2) return false;
  if (y2 + 3 <= y1) return false;
  return true;
}
bool different(int x, int y) {
  bool diff = 1;
  vector<bool> ok(1000, 0);
  for (int i = x; i < x + 3 && diff; i++) {
    for (int j = y; j < y + 3 && diff; j++) {
      if (grid[i][j] == "J1" || grid[i][j] == "J2") continue;
      if (ok[grid[i][j][0]])
        diff = 0;
      else
        ok[grid[i][j][0]] = 1;
    }
  }
  return diff;
}
string getSquare(int x, int y, int xx, int yy) {
  vector<bool> ok(1000, 0);
  for (int i = x; i < x + 3; i++) {
    for (int j = y; j < y + 3; j++) {
      if (grid[i][j] == "J1" || grid[i][j] == "J2") continue;
      ok[grid[i][j][0]] = 1;
    }
  }
  for (auto s : cards) {
    if (exist.find(s) != exist.end()) continue;
    if (ok[s[0]]) continue;
    exist[s] = {xx, yy};
    grid[xx][yy] = s;
    return s;
  }
  return "";
}
string getRandom(int xx, int yy) {
  for (auto s : cards)
    if (exist.find(s) == exist.end()) {
      exist[s] = {xx, yy};
      grid[xx][yy] = s;
      return s;
    }
  return "";
}
int main() {
  ios::sync_with_stdio(false);
  for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 13; j++) {
      string s;
      s.push_back(A[j]);
      s.push_back(B[i]);
      cards.push_back(s);
    }
  }
  cin >> n >> m;
  grid.resize(n);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      string s;
      cin >> s;
      grid[i].push_back(s);
      exist[s] = {i, j};
    }
  }
  for (int i = 0; i + 2 < n; i++) {
    for (int j = 0; j + 2 < m; j++) {
      if (!different(i, j)) continue;
      for (int k = 0; k + 2 < n; k++) {
        for (int t = 0; t + 2 < m; t++) {
          if (overlap(i, j, k, t)) continue;
          if (!different(k, t)) continue;
          if (exist.find("J1") == exist.end() &&
              exist.find("J2") == exist.end()) {
            puts("Solution exists.");
            puts("There are no jokers.");
            printf("Put the first square to (%d, %d).\n", i + 1, j + 1);
            printf("Put the second square to (%d, %d).\n", k + 1, t + 1);
            return 0;
          }
          if (exist.find("J1") != exist.end() &&
              exist.find("J2") != exist.end()) {
            auto axis1 = exist["J1"];
            auto axis2 = exist["J2"];
            string s1, s2;
            int c1 = 0, c2 = 0;
            if ((axis1.first >= i && axis1.first <= i + 2) &&
                (axis1.second >= j && axis1.second <= j + 2)) {
              s1 = getSquare(i, j, axis1.first, axis1.second);
              if (s1.empty()) c1 = -1;
            }
            if ((axis1.first >= k && axis1.first <= k + 2) &&
                (axis1.second >= t && axis1.second <= t + 2)) {
              s1 = getSquare(k, t, axis1.first, axis1.second);
              if (s1.empty()) c1 = -1;
            }
            if ((axis2.first >= i && axis2.first <= i + 2) &&
                (axis2.second >= j && axis2.second <= j + 2)) {
              s2 = getSquare(i, j, axis2.first, axis2.second);
              if (s2.empty()) c2 = -1;
            }
            if ((axis2.first >= k && axis2.first <= k + 2) &&
                (axis2.second >= t && axis2.second <= t + 2)) {
              s2 = getSquare(k, t, axis2.first, axis2.second);
              if (s2.empty()) c2 = -1;
            }
            if (!c1 && s1.empty()) {
              s1 = getRandom(axis1.first, axis1.second);
            }
            if (!c2 && s2.empty()) {
              s2 = getRandom(axis2.first, axis2.second);
            }
            if (s1.empty() || s2.empty()) {
              puts("No solution.");
              return 0;
            }
            puts("Solution exists.");
            printf("Replace J1 with %s and J2 with %s.\n", s1.c_str(),
                   s2.c_str());
            printf("Put the first square to (%d, %d).\n", i + 1, j + 1);
            printf("Put the second square to (%d, %d).\n", k + 1, t + 1);
            return 0;
          }
          if (exist.find("J1") != exist.end() ||
              exist.find("J2") != exist.end()) {
            pair<int, int> axis;
            if (exist.find("J1") != exist.end())
              axis = exist["J1"];
            else
              axis = exist["J2"];
            string s;
            int c = 0;
            if ((axis.first >= i && axis.first <= i + 2) &&
                (axis.second >= j && axis.second <= j + 2)) {
              s = getSquare(i, j, axis.first, axis.second);
              if (s.empty()) c = -1;
            }
            if ((axis.first >= k && axis.first <= k + 2) &&
                (axis.second >= t && axis.second <= t + 2)) {
              s = getSquare(k, t, axis.first, axis.second);
              if (s.empty()) c = -1;
            }
            if (!c && s.empty()) {
              s = getRandom(axis.first, axis.second);
            }
            if (s.empty()) {
              puts("No solution.");
              return 0;
            }
            puts("Solution exists.");
            if (exist.find("J1") != exist.end())
              printf("Replace J1 with %s.\n", s.c_str());
            else
              printf("Replace J2 with %s.\n", s.c_str());
            printf("Put the first square to (%d, %d).\n", i + 1, j + 1);
            printf("Put the second square to (%d, %d).\n", k + 1, t + 1);
            return 0;
          }
        }
      }
    }
  }
  puts("No solution.");
  return 0;
}
