#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=16;
int ones[1 << N],map[1 << N];
int state[N][N];
char str[N][N + 1];
int bstate[N * N + 1][N][N],bstate2[N * N + 1][N][N];
char bstr[N * N + 1][N][N + 1];
int lowbit(int x)
{
return x & -x;
}
void draw(int x, int y, int c)
{
str[x][y] = c + 'A';
for(int i = 0; i < N; i ++ )
{
state[x][i] &= ~(1 << c);
state[i][y] &= ~(1 << c);
}
int mx = x / 4 * 4;
int my = y / 4 * 4;
for(int i = 0; i < 4; i ++ )
for(int j = 0; j < 4; j ++ )
state[mx + i][my + j] &= ~(1 << c);
state[x][y] = 1 << c;
}
bool remove(int cnt)
{
memcpy(state, bstate[cnt], sizeof state);
memcpy(str, bstr[cnt], sizeof str);
return false;
}
bool dfs(int cnt)
{
if(cnt == 0)
return true;
int kcnt=cnt;
memcpy(bstate[kcnt], state, sizeof state);
memcpy(bstr[kcnt], str, sizeof str);
// 对于每个空格不能填返回false 只能填一个则填
for(int i = 0; i < N; i ++ )
for(int j = 0; j < N; j ++ )
{
if(str[i][j] == '-')
{
int s = state[i][j];
if(s == 0)
return remove(kcnt);
if(ones[s] == 1)
{
draw(i, j, map[s]);
cnt--;
}
}
}
// 对于每一行/列/16宫格如果有一个字母不能填返回false,某个字母只有一种填法则填
for(int i = 0; i < N; i ++ )
{
int sor = 0;//记录(j之前)可选方案的并集
int drawn = 0;//记录所有已填的字母
int sand = (1 << N) - 1;
//记录该行所有可选方案中只出现1或0次的字母,假设全合法筛掉不合法
for(int j = 0; j < N; j ++ )
{
int s = state[i][j];
sand &= ~ (sor & s);
sor |= s;
if(str[i][j]!='-')
drawn |= state[i][j];
}
if(sor != (1 << N) - 1)
return remove(kcnt);
for(int j = sand; j; j-=lowbit(j))
{
int t = lowbit (j);
if((drawn & t) == 0)
for(int k = 0; k < N; k ++ )
if(state[i][k] & t)
{
draw(i, k, map[t]);
cnt--;
break;
}
}
}
for(int i = 0; i < N; i ++ )
{
int sor = 0;//记录(j之前)可选方案的并集
int drawn = 0;//记录所有已填的字母
int sand = (1 << N) - 1;
//记录该行所有可选方案中只出现1或0次的字母,假设全合法筛掉不合法
for(int j = 0; j < N; j ++ )
{
int s = state[j][i];
sand &= ~ (sor & s);
sor |= s;
if(str[j][i]!='-')
drawn |= state[j][i];
}
if(sor != (1 << N) - 1)
return remove(kcnt);
for(int j = sand; j; j-=lowbit(j))
{
int t = lowbit (j);
if((drawn & t) == 0)
for(int k = 0;k < N; k ++ )
if(state[k][i] & t)
{
draw(k, i, map[t]);
cnt--;
break;
}
}
}
for(int i = 0; i < N; i ++ )
{
int sor = 0;//记录(j之前)可选方案的并集
int drawn = 0;//记录所有已填的字母
int sand = (1 << N) - 1;
//记录该行所有可选方案中只出现1或0次的字母,假设全合法筛掉不合法
for(int j = 0; j < N; j ++ )
{
int sx = i / 4 * 4, sy = i % 4 * 4;
// (i / 4 * 4, i % 4 * 4) 即当前 4 * 4 方格的左上角坐标
int dx = j / 4 ,dy = j % 4;
int s = state[sx + dx][sy + dy];
sand &= ~ (sor & s);
sor |= s;
if(str[sx + dx][sy + dy]!='-')
drawn |= s;
}
if(sor != (1 << N) - 1)
return remove(kcnt);
for(int j = sand; j; j-=lowbit(j))
{
int t = lowbit (j);
if((drawn & t) == 0)
for(int k = 0;k < N; k ++ )
{
int sx = i / 4 * 4, sy = i % 4 * 4;
int dx = k / 4, dy = k % 4;
if (state[sx + dx][sy + dy] & t)
{
draw(sx + dx, sy + dy, map[t]);
cnt -- ;
break;
}
}
}
}
if(cnt == 0)
return true;
// 优先填最少方案数的格子
int x,y,minv=100;
for(int i = 0; i < N; i ++ )
for(int j = 0; j < N; j ++)
if(str[i][j] == '-' && ones[state[i][j]] < minv)
{
x = i;
y = j;
minv = ones[state[i][j]];
}
memcpy(bstate2[kcnt], state, sizeof state);
for(int i = state[x][y]; i; i -= lowbit(i))
{
memcpy(state, bstate2[kcnt], sizeof state);
draw(x, y, map[lowbit(i)]);
if (dfs(cnt - 1)) return true;
}
return remove(kcnt) ;
}
int main()
{
for(int i = 0; i < 1 << N; i ++ )
for(int j = i; j; j -= lowbit(j))
ones[i] ++;
for(int i = 0; i < N; i ++ )
map[1 << i] = i;
while(cin >> str[0])
{
for(int i = 1; i < N; i ++ )
cin >> str[i];
for(int i = 0; i < N; i ++ )
for(int j = 0; j < N; j ++ )
state[i][j] = (1 << N) - 1;
int cnt = 0;
for(int i = 0; i < N; i ++ )
for(int j = 0; j < N; j ++ )
{
if(str[i][j]!='-')
draw(i, j, str[i][j]-'A');
else
cnt ++ ;
}
dfs(cnt);
for(int i = 0; i < N; i ++ )
cout << str[i] << endl;
cout << endl;
}
}