#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <malloc.h>
#define SIZE	8		/* 問題サイズ */
#define BLACK	1		/* 黒マス確定 */
#define GRAY	2		/* 未確定マス */
#define WHITE	3		/* 白マス確定 */
#define	CHECK	4		/* チェック用 */

/* 関数の宣言 */
void output (int table[SIZE][SIZE]);
void copyTable (int to[SIZE][SIZE], int from[SIZE][SIZE]);
void push (int table[SIZE][SIZE]);
int pop (int table[SIZE][SIZE]);
int toBlack (int table[SIZE][SIZE], int x, int y);
int toWhite (int table[SIZE][SIZE], int x, int y);
void check (int table[SIZE][SIZE], int x, int y);
int devided (int table[SIZE][SIZE]);
int solve (int table[SIZE][SIZE]);
int search (void);
void input (void);

/* 問題 */
int problem[SIZE][SIZE];

/* スタック構造体 */
struct stack {
  int       table[SIZE][SIZE];
  struct    stack *next;
};

/* スタックトップ */
struct stack *top;

/* 解の数 */
int ans_num;

/* 表示 */
void output (int table[SIZE][SIZE])
{
  int i, j;
  for (i = 0; i < SIZE; i++) {
    for (j = 0; j < SIZE; j++) {
      switch (table[i][j]) {
      case BLACK:
        printf(" *");
        break;
      case GRAY:
        printf("#%c", (char)problem[i][j]);
        break;
      case WHITE:
        printf(" %c", (char)problem[i][j]);
        break;
      default:
        break;
      }
    }
    printf("\n");
  }
  printf("\n");
}

/* テーブルをコピー */
void copyTable (int to[SIZE][SIZE], int from[SIZE][SIZE])
{
  int i, j;
  for (i = 0; i < SIZE; i++) {
    for (j = 0; j < SIZE; j++) {
      if (from == NULL) to[i][j] = GRAY;
      else  to[i][j] = from[i][j];
    }
  }
}

/* スタックにプッシュ */
void push (int table[SIZE][SIZE])
{
  struct stack *stk = (struct stack *)malloc(sizeof(struct stack));
  copyTable(stk->table, table);
  stk->next = top;
  top = stk;
}

/* スタックからポップ，スタックが空ならを1返す */
int pop (int table[SIZE][SIZE])
{
  struct stack *tmp;
  /* スタックが空なら1を返す */
  if (top == NULL) return 1;
  copyTable(table, top->table);
  tmp = top;
  top = tmp->next;
  free(tmp);
  return 0;
}

/* 黒マスにする，矛盾があると1を返す*/
int toBlack (int table[SIZE][SIZE], int x, int y)
{
  /* 白マスだったら矛盾 */
  if (table[x][y] == WHITE) return 1;
  /* 黒マスだったら何もしない */
  if (table[x][y] == BLACK) return 0;
  /* 黒マスにする */
  table[x][y] = BLACK;
  /* 上下左右のマスを白にする */
  if (toWhite(table, x-1, y) == 1) return 1;
  if (toWhite(table, x+1, y) == 1) return 1;
  if (toWhite(table, x, y-1) == 1) return 1;
  if (toWhite(table, x, y+1) == 1) return 1;
  return 0;
}

/* 白マスにする，矛盾があると1を返す */
int toWhite (int table[SIZE][SIZE], int x, int y)
{
  int i;
  /* テーブル外なら何もしない */
  if (x < 0 || y < 0 || x >= SIZE || y >= SIZE) return 0;
  /* 黒マスだったら矛盾 */
  if (table[x][y] == BLACK) return 1;
  /* 白マスだったら何もしない */
  if (table[x][y] == WHITE) return 0;
  /* 白マスにする */
  table[x][y] = WHITE;
  /* 同じ行・列にある同じ数字は黒マスに */
  for (i = 0; i < SIZE; i++) {
    if (i != x && problem[i][y] == problem[x][y] 
             && toBlack(table, i, y) == 1) return 1;
    if (i != y && problem[x][i] == problem[x][y] 
             && toBlack(table, x, i) == 1) return 1;
  }
  return 0;
}

/* 黒マス以外を再帰的に上下左右にチェックしていく */
void check (int table[SIZE][SIZE], int x, int y)
{
  if (x >= 0 && x < SIZE && y >= 0 && y < SIZE 
        && (table[x][y] == WHITE || table[x][y] == GRAY)) {
    table[x][y] = CHECK;
    check(table, x-1, y);
    check(table, x+1, y);
    check(table, x, y-1);
    check(table, x, y+1);
  }
}

/* 分断されているかどうかを調べる，分断していたら1を返す */
int devided (int table[SIZE][SIZE])
{
  int i, j;
  int checkTable[SIZE][SIZE];
  copyTable(checkTable, table);
  if (checkTable[0][0] == BLACK) check(checkTable, 0, 1);
  else check(checkTable, 0, 0);
  for (i = 0; i < SIZE; i++) {
    for (j = 0; j < SIZE; j++) {
      if (checkTable[i][j] == WHITE || checkTable[i][j] == GRAY) return 1;
    }
  }
  return 0;
}

/* 様々な定石を使って解いていく，矛盾があると1を返す */
int solve (int table[SIZE][SIZE])
{
  if (devided(table) == 1) return 1;
  return 0;
}

/* スタックから状態をポップして問題を解く，探索が終了すると1を返す */
int search (void)
{
  int i, j;
  int table1[SIZE][SIZE];
  int table2[SIZE][SIZE];
  /* スタックからポップする，スタックが空なら1を返す */
  if (pop(table1) == 1) return 1;
  /* 黒によって分断されているかどうか調べる，分断されていれば0を返す */
  if (devided(table1) == 1) return 0;
  /* 白用と黒用にテーブルをコピーする */
  copyTable(table2, table1);
  /* 未確定のマスを黒や白にしてプッシュ */
  for (i = 0; i < SIZE; i++) {
    for (j = 0; j < SIZE; j++) {
      if (table1[i][j] == GRAY) {
    /* 黒にして矛盾がなければ，プッシュ */
    if (toBlack(table1, i, j) == 0) push(table1);
    /* 白にして矛盾がなければ，プッシュ */
    if (toWhite(table2, i, j) == 0) push(table2);
    /* 次へ */
    return 0;
      }
    }
  }
  /* 未確定のマスがないので正解として出力 */
  printf("正解その%d\n", ++ans_num);
  output(table1);
  return 0;
}

/* 定石 */
int tactics (void)
{
  int i, j, k;
  int table[SIZE][SIZE];
  /* 最初は全部未確定でプッシュ */
  push(NULL);
  /* スタックからポップする，スタックが空なら1を返す */
  if (pop(table) == 1) {
    fprintf(stderr, "スタックエラー\n");
    exit(1);
  }
  /* 同じ数字に挟まれたマスは白 */
  for (i = 0; i < SIZE-2; i++) {
    for (j = 0; j < SIZE-2; j++) {
      if (problem[i][j] == problem[i][j+2]) {
    if (toWhite(table, i, j+1) == 1) return 1;
      }
      if (problem[i][j] == problem[i+2][j]) {
    if (toWhite(table, i+1, j) == 1) return 1;
      }
    }
  }
  /* タテまたはヨコに同じ数字が２つ並んでいたら，同じタテまたはヨコの列にある同じ数字は黒 */
  for (i = 0; i < SIZE-1; i++) {
    for (j = 0; j < SIZE-1; j++) {
      if (problem[i][j] == problem[i][j+1]) {
    for (k = 0; k < SIZE; k++) {
      if (k != j && k != j+1 && problem[i][j] == problem[i][k]) {
        if (toBlack(table, i, k) == 1) return 1;
      }
    }
      }
      if (problem[i][j] == problem[i+1][j]) {
    for (k = 0; k < SIZE; k++) {
	  if (k != i && k != i+1 && problem[i][j] == problem[k][j]) {
        if (toBlack(table, k, j) == 1) return 1;
      }
    }
      }
    }
  }
  /* 角に並んだ同じ数字があると角から２番目のマスは白 */
  if (problem[0][0] == problem[0][1] && toWhite(table, 1, 0) == 1) return 1;
  if (problem[0][0] == problem[1][0] && toWhite(table, 0, 1) == 1) return 1;
  if (problem[0][SIZE-1] == problem[0][SIZE-2] 
         && toWhite(table, 1, SIZE-1) == 1) return 1;
  if (problem[0][SIZE-1] == problem[1][SIZE-1] 
         && toWhite(table, 0, SIZE-2) == 1) return 1;
  if (problem[SIZE-1][0] == problem[SIZE-2][0] 
         && toWhite(table, SIZE-1, 1) == 1) return 1;
  if (problem[SIZE-1][0] == problem[SIZE-1][1] 
         && toWhite(table, SIZE-2, 0) == 1) return 1;
  if (problem[SIZE-1][SIZE-1] == problem[SIZE-1][SIZE-2] 
         && toWhite(table, SIZE-2, SIZE-1) == 1) return 1;
  if (problem[SIZE-1][SIZE-1] == problem[SIZE-2][SIZE-1] 
         && toWhite(table, SIZE-1, SIZE-2) == 1) return 1;
  /* テーブルをプッシュして終わり */
  push(table);
  return 0;
}

/* 問題入力 */
void input (void)
{
  int i, j;
  /* 問題を読み込む */
  i = j = 0;
  while (1) {
    int c = fgetc(stdin);
    if (c == EOF) {
      fprintf(stderr, "ファイル形式が間違っています\n");
      exit(1);
    }
    if (isalnum(c)) {
      problem[i][j] = c;
      j++;
      if (j == SIZE) {
           j = 0;
           i++;
      }
      if (i == SIZE) break;
    }
  }
}

/* メイン関数 */
main ()
{
  /* 初期化 */
  ans_num = 0;
  top = NULL;
  /* 問題の読み込み */
  input();
  /* 定石を利用して解く */
  if (tactics() == 1) {
    printf("答えなし\n");
    return 0;
  }
  /* スタックが空になるまで探索する */
  while (search() == 0);
  /* 解の個数を表示 */
  if (ans_num) printf("答えが%d個見つかりました\n", ans_num);
  else printf("答えが見つかりませんでした\n");
  return 0;
}
