using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    const int UB = 9 - 1;
    struct JyoutaiDef
    {
        internal int Level;
        internal bool[,] KikiArr;
        internal bool[,] HaitiArr;
    }
    static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
    static void Main()
    {
        //反復深化深さ優先探索で解く
        for (int Depth = 1; Depth <= 9 * 9; Depth++) {
            Console.WriteLine("深さ制限={0}で解を検証中。経過時間={1}", Depth, sw.Elapsed);
            List<bool[,]> AnswerHaitiArrList = ExecDFS(Depth);
            if (AnswerHaitiArrList.Count == 0) continue;
            //回転を除外
            RemoveKaiten(AnswerHaitiArrList);
            for (int I = 0; I <= AnswerHaitiArrList.Count - 1; I++) {
                Console.WriteLine("(回転除外後の)解{0}", I + 1);
                PrintBan(AnswerHaitiArrList[I]);
            }
            Console.WriteLine("解は{0}通り。経過時間={1}", AnswerHaitiArrList.Count, sw.Elapsed);
            break;
        }
    }
    //深さ制限を引数として深さ優先探索を行う
    static List<bool[,]> ExecDFS(int pDepthMax)
    {
        var WillReturnBoolArrList = new List<bool[,]>();
        var stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;
        WillPush.Level = 0;
        WillPush.KikiArr = WillPush.HaitiArr = new bool[UB + 1, UB + 1];
        stk.Push(WillPush);
        while (stk.Count > 0) {
            JyoutaiDef Popped = stk.Pop();
            //レベル制限
            if (pDepthMax < Popped.Level) continue;
            //クリア判定
            if (Popped.KikiArr.Cast<bool>().All(X => X)) {
                WillReturnBoolArrList.Add(Popped.HaitiArr);
                Console.WriteLine("(回転除外前の)解候補{0}を発見。経過時間={1}",
                    WillReturnBoolArrList.Count, sw.Elapsed);
                continue;
            }
            //最後に龍を配置した座標を求める
            int LastRyuX = 0, LastRyuY = 0;
            for (int Y = 0; Y <= UB; Y++)
                for (int X = 0; X <= UB; X++)
                    if (Popped.HaitiArr[X, Y]) {
                        LastRyuX = X;
                        LastRyuY = Y;
                    }
            WillPush.Level = Popped.Level + 1;
            var KagentiEdakiriXSet = new HashSet<int>();
            for (int Y = LastRyuY; Y <= UB; Y++) {
                //回転解の除外で1枚目の龍は左上に配置
                if (WillPush.Level == 1 && 3 < Y) break;
                for (int X = 0; X <= UB; X++) {
                    //回転解の除外で1枚目の龍は左上に配置
                    if (WillPush.Level == 1 && 3 < X) break;
                    //最後に龍を配置した座標までは、Continue
                    if (Y == LastRyuY && X <= LastRyuX) continue;
                    //下限値枝切りされたX座標ならContinue
                    if (KagentiEdakiriXSet.Contains(X)) continue;
                    WillPush.KikiArr = (bool[,])Popped.KikiArr.Clone();
                    SetRyuKikiTrue(WillPush.KikiArr, X, Y);
                    //下限値枝切り
                    if (WillPush.Level + CalcNeedMinTesuu(WillPush.KikiArr, Y) > pDepthMax) {
                        KagentiEdakiriXSet.Add(X);
                        continue;
                    }
                    WillPush.HaitiArr = (bool[,])Popped.HaitiArr.Clone();
                    WillPush.HaitiArr[X, Y] = true;
                    stk.Push(WillPush);
                }
            }
        }
        return WillReturnBoolArrList;
    }
    //龍の配置座標を引数として効きの座標をTrueにする
    static void SetRyuKikiTrue(bool[,] pHaitiArr, int pX, int pY)
    {
        pHaitiArr[pX, pY] = true;
        for (int X = 0; X <= UB; X++) pHaitiArr[X, pY] = true;
        for (int Y = 0; Y <= UB; Y++) pHaitiArr[pX, Y] = true;
        Action<int, int> SetNaname = (pNanameX, pNanameY) =>
        {
            if (pNanameX < 0 || UB < pNanameX) return;
            if (pNanameY < 0 || UB < pNanameY) return;
            pHaitiArr[pNanameX, pNanameY] = true;
        };
        SetNaname(pX - 1, pY - 1);
        SetNaname(pX - 1, pY + 1);
        SetNaname(pX + 1, pY - 1);
        SetNaname(pX + 1, pY + 1);
    }
    //必要な最低手数を求める
    static int CalcNeedMinTesuu(bool[,] pKikiArr, int pY)
    {
        int NeedMinTesuu = 0;
        //カレント座標より2つ以上上のマスで効きがなかったら、
        //そのマスの下に龍を配置する必要あり
        for (int X = 0; X <= UB; X++) {
            for (int Y = 0; Y <= pY - 2; Y++) {
                if (pKikiArr[X, Y] == false) {
                    NeedMinTesuu++;
                    break;
                }
            }
        }
        return NeedMinTesuu;
    }
    //回転を除外
    static void RemoveKaiten(List<bool[,]> pTargetList)
    {
        Predicate<int> IsExist = (pCurrInd) =>
        {
            for (int I = 0; I <= pCurrInd - 1; I++) {
                bool IsOK1 = false, IsOK2 = false, IsOK3 = false, IsOK4 = false;
                bool IsOK5 = false, IsOK6 = false, IsOK7 = false; //回転1から7
                for (int X = 0; X <= UB; X++) {
                    for (int Y = 0; Y <= UB; Y++) {
                        bool CurrVal = pTargetList[pCurrInd][X, Y];
                        if (pTargetList[I][UB - X, Y] != CurrVal) IsOK1 = true;
                        if (pTargetList[I][UB - X, UB - Y] != CurrVal) IsOK2 = true;
                        if (pTargetList[I][X, UB - Y] != CurrVal) IsOK3 = true;
                        if (pTargetList[I][Y, X] != CurrVal) IsOK4 = true;
                        if (pTargetList[I][UB - Y, X] != CurrVal) IsOK5 = true;
                        if (pTargetList[I][UB - Y, UB - X] != CurrVal) IsOK6 = true;
                        if (pTargetList[I][Y, UB - X] != CurrVal) IsOK7 = true;
                    }
                }
                if (IsOK1 == false || IsOK2 == false || IsOK3 == false || IsOK4 == false
                 || IsOK5 == false || IsOK6 == false || IsOK7 == false)
                    return true;
            }
            return false;
        };
        for (int I = pTargetList.Count - 1; I >= 0; I--) {
            if (IsExist(I)) pTargetList.RemoveAt(I);
        }
    }
    //盤面を表示
    static void PrintBan(bool[,] pHaitiArr)
    {
        var sb = new System.Text.StringBuilder();
        for (int Y = 0; Y <= UB; Y++) {
            for (int X = 0; X <= UB; X++) {
                sb.Append(pHaitiArr[X, Y] ? '龍' : '□');
            }
            sb.AppendLine();
        }
        Console.WriteLine(sb.ToString());
    }
}