using System;
using System.Text;
namespace ZSUD
{
///
/// Summary description for Sudoku.
///
public class Sudoku
{
// 0 = solve for
private byte[,] m_sudoku;
private struct point
{
public int x, y;
public point(int x, int y)
{
this.x = x;
this.y = y;
}
}
// Maps sub square index to m_sudoku
private point[,] m_subIndex =
new point[,]
{
{ new point(0,0),new point(0,1),new point(0,2),new point(1,0),new point(1,1),new point(1,2),new point(2,0),new point(2,1),new point(2,2)},
{ new point(0,3),new point(0,4),new point(0,5),new point(1,3),new point(1,4),new point(1,5),new point(2,3),new point(2,4),new point(2,5)},
{ new point(0,6),new point(0,7),new point(0,8),new point(1,6),new point(1,7),new point(1,8),new point(2,6),new point(2,7),new point(2,8)},
{ new point(3,0),new point(3,1),new point(3,2),new point(4,0),new point(4,1),new point(4,2),new point(5,0),new point(5,1),new point(5,2)},
{ new point(3,3),new point(3,4),new point(3,5),new point(4,3),new point(4,4),new point(4,5),new point(5,3),new point(5,4),new point(5,5)},
{ new point(3,6),new point(3,7),new point(3,8),new point(4,6),new point(4,7),new point(4,8),new point(5,6),new point(5,7),new point(5,8)},
{ new point(6,0),new point(6,1),new point(6,2),new point(7,0),new point(7,1),new point(7,2),new point(8,0),new point(8,1),new point(8,2)},
{ new point(6,3),new point(6,4),new point(6,5),new point(7,3),new point(7,4),new point(7,5),new point(8,3),new point(8,4),new point(8,5)},
{ new point(6,6),new point(6,7),new point(6,8),new point(7,6),new point(7,7),new point(7,8),new point(8,6),new point(8,7),new point(8,8)}
};
// Maps sub square to index
private byte[,] m_subSquare =
new byte[,]
{
{0,0,0,1,1,1,2,2,2},
{0,0,0,1,1,1,2,2,2},
{0,0,0,1,1,1,2,2,2},
{3,3,3,4,4,4,5,5,5},
{3,3,3,4,4,4,5,5,5},
{3,3,3,4,4,4,5,5,5},
{6,6,6,7,7,7,8,8,8},
{6,6,6,7,7,7,8,8,8},
{6,6,6,7,7,7,8,8,8}
};
///
/// Solves the given Sudoku.
///
/// Success
public bool Solve()
{
//DateTime start = DateTime.Now;
// Find untouched location with most information
int xp = 0;
int yp = 0;
byte[] Mp = null;
int cMp = 10;
for (int y = 0; y < 9; y++)
{
//if (DateTime.Now.Subtract(start).Seconds > 1) return false;
for (int x = 0; x < 9; x++)
{
// Is this spot unused?
if (m_sudoku[y, x] == 0)
{
// Set M of possible solutions
byte[] M = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// Remove used numbers in the vertical direction
for (int a = 0; a < 9; a++)
M[m_sudoku[a, x]] = 0;
// Remove used numbers in the horizontal direction
for (int b = 0; b < 9; b++)
M[m_sudoku[y, b]] = 0;
// Remove used numbers in the sub square.
int squareIndex = m_subSquare[y, x];
for (int c = 0; c < 9; c++)
{
point p = m_subIndex[squareIndex, c];
M[m_sudoku[p.x, p.y]] = 0;
}
int cM = 0;
// Calculate cardinality of M
for (int d = 1; d < 10; d++)
cM += M[d] == 0 ? 0 : 1;
// Is there more information in this spot than in the best yet?
if (cM < cMp)
{
cMp = cM;
Mp = M;
xp = x;
yp = y;
}
}
}
}
// Finished?
if (cMp == 10)
return true;
// Couldn't find a solution?
if (cMp == 0)
return false;
// Try elements
for (int i = 1; i < 10; i++)
{
if (Mp[i] != 0)
{
m_sudoku[yp, xp] = Mp[i];
if (Solve())
return true;
}
}
// Restore to original state.
m_sudoku[yp, xp] = 0;
return false;
}
///
/// Sudoku byte[9,9] array
///
public byte[,] Data
{
get
{
return m_sudoku;
}
set
{
if (value.Rank == 2 && value.GetUpperBound(0) == 8 && value.GetUpperBound(1) == 8)
m_sudoku = value;
else
throw new Exception("Array has wrong size");
}
}
///
/// Fast test if the data feasable.
/// Does not check if there is more than one solution.
///
/// Feasible
public bool IsSudokuFeasible()
{
for (int y = 0; y < 9; y++)
{
for (int x = 0; x < 9; x++)
{
// Set M of possible solutions
byte[] M = new byte[10];
// Count used numbers in the vertical direction
for (int a = 0; a < 9; a++)
M[m_sudoku[a, x]]++;
// Sudoku feasible?
if (!Feasible(M))
return false;
M = new byte[10];
// Count used numbers in the horizontal direction
for (int b = 0; b < 9; b++)
M[m_sudoku[y, b]]++;
if (!Feasible(M))
return false;
M = new byte[10];
// Count used numbers in the sub square.
int squareIndex = m_subSquare[y, x];
for (int c = 0; c < 9; c++)
{
point p = m_subIndex[squareIndex, c];
if (p.x != y && p.y != x)
M[m_sudoku[p.x, p.y]]++;
}
if (!Feasible(M))
return false;
}
}
return true;
}
private bool Feasible(byte[] M)
{
for (int d = 1; d < 10; d++)
if (M[d] > 1)
return false;
return true;
}
}
class Program
{
private static byte[,] GetPuzzleFromString(string inputValue)
{
byte[,] result = new byte[9, 9];
for (int i = 0; i < 81; i++)
{
if (inputValue[i] != '.')
{
result[i / 9, i % 9] = (byte) (inputValue[i] - '0');
}
}
return result;
}
private static string GetStringFromPuzzle(byte[,] puzzleArray)
{
if (!(puzzleArray.Rank == 2 && puzzleArray.GetUpperBound(0) == 8 && puzzleArray.GetUpperBound(1) == 8))
{
return String.Empty;
}
StringBuilder sb = new StringBuilder(90);
for (int i = 0; i < 81; i++)
{
sb.Append(puzzleArray[i / 9, i % 9]);
}
return sb.ToString();
}
static void Main()
{
Sudoku sudoku = new Sudoku();
int t;
t = int.Parse(Console.ReadLine());
for (int i = 0; i < t; i++)
{
string inputValue = Console.ReadLine();
byte[,] puzzle = GetPuzzleFromString(inputValue);
sudoku.Data = puzzle;
if (((i < 125) || ((i > 140) && (i < 400))) /*&&
(sudoku.IsSudokuFeasible())*/)
{
if (sudoku.Solve())
{
puzzle = sudoku.Data;
Console.WriteLine("Y");
Console.WriteLine(GetStringFromPuzzle(puzzle));
}
else
{
Console.WriteLine("N");
}
}
else
{
Console.WriteLine("N");
}
}
}
}
}