#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:64000000")
char Colors[4] = {'H', 'D', 'S', 'C'};
char Ranks[13] = {'2', '3', '4', '5', '6', '7', '8',
                  '9', 'T', 'J', 'Q', 'K', 'A'};
struct card {
  char Rank;
  char Color;
  void read() {
    string s;
    cin >> s;
    Rank = s[0];
    Color = s[1];
  }
  void make(char c1, char c2) {
    Rank = c1;
    Color = c2;
  }
  int isJoker() { return (Rank == 'J' && (Color == '1' || Color == '2')); }
  string toString() {
    string res = "";
    res += Rank;
    res += Color;
    return res;
  }
  bool operator<(const card &b) const {
    if (Rank < b.Rank) return true;
    if (Rank > b.Rank) return false;
    if (Color < b.Color) return true;
    return false;
  }
};
int n, m;
int jx1, jy1, jx2, jy2;
card a[1 << 5][1 << 5];
set<card> G;
int was[4][13];
inline void init() {
  cin >> n >> m;
  jx1 = jx2 = jy1 = jy2 = 30;
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < m; ++j) {
      a[i][j].read();
      G.insert(a[i][j]);
      if (!a[i][j].isJoker()) continue;
      if (a[i][j].Color == '1')
        jx1 = i, jy1 = j;
      else
        jx2 = i, jy2 = j;
    }
  memset(was, 0, sizeof was);
  for (int i = 0; i < 4; ++i)
    for (int j = 0; j < 13; ++j) {
      card tmp;
      tmp.make(Ranks[j], Colors[i]);
      if (G.count(tmp)) was[i][j] = 1;
    }
}
inline int intersect(int x1, int _dsfdsfkn, int x2, int y2) {
  return (x1 + 3 > x2 && _dsfdsfkn + 3 > y2);
}
inline void ans(int x1, int _dsfdsfkn, int x2, int y2) {
  puts("Solution exists.");
  if (jx1 != 30 && jx2 != 30) {
    cout << "Replace J1 with " << a[jx1][jy1].Rank << a[jx1][jy1].Color
         << " and J2 with " << a[jx2][jy2].Rank << a[jx2][jy2].Color << "."
         << endl;
  } else {
    if (jx1 != 30) {
      cout << "Replace J1 with " << a[jx1][jy1].Rank << a[jx1][jy1].Color << "."
           << endl;
    }
    if (jx2 != 30) {
      cout << "Replace J2 with " << a[jx2][jy2].Rank << a[jx2][jy2].Color << "."
           << endl;
    }
    if (jx1 == 30 && jx2 == 30) puts("There are no jokers.");
  }
  cout << "Put the first square to (" << x1 + 1 << ", " << _dsfdsfkn + 1 << ")."
       << endl;
  cout << "Put the second square to (" << x2 + 1 << ", " << y2 + 1 << ")."
       << endl;
  exit(0);
}
set<char> temp;
inline int good(int x, int y) {
  temp.clear();
  int nx = x + 3;
  int ny = y + 3;
  int ok1 = 1;
  int ok2 = 1;
  for (int i = x; i < nx; ++i)
    for (int j = y; j < ny; ++j) {
      if (a[i][j].Color != a[x][y].Color) ok1 = 0;
      if (temp.count(a[i][j].Rank)) ok2 = 0;
      temp.insert(a[i][j].Rank);
    }
  return (ok1 || ok2);
}
inline void check() {
  for (int x1 = 0; x1 + 2 < n; ++x1)
    for (int _dsfdsfkn = 0; _dsfdsfkn + 2 < m; ++_dsfdsfkn)
      for (int x2 = 0; x2 + 2 < n; ++x2)
        for (int y2 = 0; y2 + 2 < m; ++y2) {
          if (intersect(x1, _dsfdsfkn, x2, y2)) continue;
          if (good(x1, _dsfdsfkn) && good(x2, y2)) ans(x1, _dsfdsfkn, x2, y2);
        }
}
int main() {
  init();
  for (int i1 = 0; i1 < 4; ++i1)
    for (int j1 = 0; j1 < 13; ++j1) {
      if (was[i1][j1]) continue;
      card tmp;
      tmp.make(Ranks[j1], Colors[i1]);
      was[i1][j1] = 1;
      a[jx1][jy1] = tmp;
      for (int i2 = 0; i2 < 4; ++i2)
        for (int j2 = 0; j2 < 13; ++j2) {
          if (was[i2][j2]) continue;
          was[i2][j2] = 1;
          tmp.make(Ranks[j2], Colors[i2]);
          a[jx2][jy2] = tmp;
          check();
          was[i2][j2] = 0;
        }
      was[i1][j1] = 0;
    }
  puts("No solution.");
  return 0;
}
