Четвёртый открытый Зеленоградский турнир 2008

#include <stdio.h>
#include <math.h>
#include <vector>
#include <map>
#define WIDTH 200
#define HEIGHT 200
#define BLOCK_DOT_THRESHOLD 5
#define countof(a) (sizeof(a)/sizeof(a[0]))
#define max( a, b ) ((a) < (b)? (b):(a))
class Field;

class Object
{
    struct point
    {
        point( int _x, int _y ):
            x(_x), y(_y){}
        int x;
        int y;
    };
    typedef std::vector< point > group;

    group m_Group;
    int m_MaxX,
        m_MaxY,
        m_MinX,
        m_MinY,
        m_SumX,
        m_SumY;
public:
    Object():
      m_MaxX(0), m_MaxY(0), 
      m_MinX(INT_MAX), m_MinY(INT_MAX),
      m_SumX(0), m_SumY(0){}
    ~Object(){}

    int AddPoint( int x, int y );
    inline point GetPoint( int n ) const;
    inline int Size() const;
    Field GetField() const;
    void Clear();
    void CutFromField( Field& f, int x, int y );
    void GetFromField( Field& f );
    void GetFromObject( const Object& o );
    double GetOrientation() const;
    void Scale( double s );
    void Rotate(double Angle);
};

struct Fld
{
    int m_Width, m_Height;
    unsigned *data;
};

class Field
{
    typedef std::vector< int > matrix;

    int m_Width,
        m_Height;
    int m_Outside;
    matrix m_Matrix;

public:
    Field( int width, int height ):
      m_Outside( 0 ),
      m_Width( width ),
      m_Height( height ),
      m_Matrix( width * height ){}
      ~Field() {};

    void Read( FILE *f )
    {
        std::vector< char > row( m_Width + 1);

        for ( int y = 0; y < m_Height; y++ )
        {
            int n = m_Width * y;
            fgets( &row[0], m_Width + 1, f );
            if( row[0] != '.' &&
                row[0] != 'x' &&
                row[0] != 'X')
            {
                y --;
                continue;
            }

            for ( int x = 0; x < m_Width; x++, n++ )
            {                
                m_Matrix[n] = row[x] == '.' ? false:true;

            }
        }
    }

    void ReadVar(unsigned * data)
    {
        unsigned D = 0, j = 0;

        for ( int i = 0; i < m_Width * m_Height; i  ++ )
        {
            if ( i % 32 == 0 )
                D = data[j++];
            m_Matrix[i] = (0 != (D & 0x80000000));
            D <<= 1;
        }

    }
    inline int Width() const
    {
        return m_Width;
    }

    inline int Height() const
    {
        return m_Height;
    }

    inline matrix::reference At( int x, int y )
    {
        if( x < 0 || y < 0 || x >= m_Width || y >= m_Height )
            return m_Outside;

        return m_Matrix.at( m_Width * y + x );
    }
    std::vector< Object > Split()
    {
        std::vector< Object > Objects;
        for ( int x = 0; x < m_Width; x++ )
        {
            for ( int y = 0; y < m_Height; y++ )
            {

                if ( At( x, y ) && 
                    ( At( x - 1, y ) ||
                    At( x + 1, y ) ||
                    At( x, y - 1 ) ||
                    At( x, y + 1 )))
                {

                    Object o;
                    o.CutFromField( *this, x, y );

                    if ( o.Size() > BLOCK_DOT_THRESHOLD )
                        Objects.push_back( o );
                }
            }
        }

        return Objects;
    }

    void Smooth()
    {
        int x, y;
        for ( y = 0; y < m_Height; y ++ )
        {
            bool bStart = false;
            for ( x = 0; x < m_Width; x ++ )
            {
                if ( 1 == At( x, y )) 
                    bStart = true;
                else if ( bStart && (1 == At( x, y-1 ) || 1 == At( x, y+1 ))) 
                    At( x, y ) = 2;
                else
                    bStart = false;
            }
        }

        for ( y = 0; y < m_Height; y ++ )
        {
            bool bStart = false;
            for ( x = m_Width-1; x >= 0 ; x -- )
            {
                if ( 1 == At( x, y )) 
                    bStart = true;
                else if ( bStart && (1 == At( x, y-1 ) || 1 == At( x, y+1 ))) 
                    At( x, y ) = 2;
                else
                    bStart = false;
            }
        }

        for ( x = 0; x < m_Width; x ++ )
        {
            bool bStart = false;
            for ( y = 0; y < m_Height; y ++ )
            {
                if ( 1 == At( x, y )) 
                    bStart = true;
                else if ( bStart && (1 == At( x-1, y ) || 1 == At( x+1, y ))) 
                    At( x, y ) = 2;
                else
                    bStart = false;
            }
        }

        for ( x = 0; x < m_Width; x ++ )
        {
            bool bStart = false;
            for ( y = m_Height-1; y >= 0; y -- )
            {
                if ( 1 == At( x, y )) 
                    bStart = true;
                else if ( bStart && (1 == At( x-1, y ) || 1 == At( x+1, y ))) 
                    At( x, y ) = 2;
                else
                    bStart = false;
            }
        }

        for ( x = 0; x < m_Width; x ++ )
            for ( y = 0; y < m_Height; y ++ )
                if (At( x, y )) At( x, y ) = 1;
                
    }
    void Morph( bool bErosion )
    {
        int dirs[][2] = 
        {
            { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 },
            { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 }
        };

        int x, y, j, c = !bErosion;

        for ( y = 0; y < m_Height; y ++ )
        {
            for ( x = 0; x < m_Width; x ++ )
            {
                if ( c == At( x, y ))
                    continue;

                for ( j = 0; j < countof( dirs ); j ++ )
                {
                    if ( c == At( x + dirs[j][0], y + dirs[j][1] ))
                        break;
                }

                if ( j != countof( dirs ))
                    At( x, y ) = 2;
            }
        }

        for ( y = 0; y < m_Height; y ++ )
        {
            for ( x = 0; x < m_Width; x ++ )
                if ( At( x, y ) == 2 )
                    At( x, y ) = c;
            
        }
    }

};

int Object::AddPoint( int x, int y )
{
    if ( x > m_MaxX ) m_MaxX = x;
    if ( y > m_MaxY ) m_MaxY = y;
    if ( x < m_MinX ) m_MinX = x;
    if ( y < m_MinY ) m_MinY = y;
    m_SumX += x;
    m_SumY += y;

    m_Group.push_back( point( x, y ));
    return m_Group.size() - 1;
}
inline Object::point Object::GetPoint( int n ) const
{
    return m_Group[n];
}

inline int Object::Size() const
{
    return m_Group.size();
}

Field Object::GetField() const
{
    Field f( m_MaxX - m_MinX + 1, m_MaxY - m_MinY + 1 );

    for( int i = 0; i < m_Group.size(); i ++ )
        f.At( m_Group[i].x - m_MinX, m_Group[i].y - m_MinY ) = true; 

    return f;
}

void Object::Clear()
{
    m_Group.clear();
    m_MaxX = 0;
    m_MaxY = 0;
    m_MinX = INT_MAX;
    m_MinY = INT_MAX;
    m_SumX = 0;
    m_SumY = 0;
}

void Object::CutFromField( Field& f, int x, int y )
{
    if ( f.At(x, y ))
    {
        AddPoint( x, y );
        f.At(x, y ) = false;
    }
    else
        return;

    CutFromField( f, x - 1, y );
    CutFromField( f, x + 1, y );
    CutFromField( f, x, y - 1 );
    CutFromField( f, x, y + 1 );
}

void Object::GetFromField( Field& f )
{
    for( int x = 0; x < f.Width(); x ++ )
    {
        for( int  y = 0; y < f.Height(); y ++ )
        {
            if ( f.At( x, y ))
                AddPoint( x, y );
        }
    }
}
void Object::GetFromObject( const Object& o )
{
    for ( int i = 0; i < o.Size(); i ++ )
    {
        point p = o.GetPoint( i );
        AddPoint( p.x, p.y );
    }
}
double Object::GetOrientation() const
{
    int i;
    double tmp;
    double Xc = m_SumX, 
        Yc = m_SumY,
        Ux = 0, 
        Uy = 0, 
        Uxy = 0,
        C = 0,
        O = 0;

    Xc /= m_Group.size();
    Yc /= m_Group.size();

    for ( i = 0; i < m_Group.size(); i ++ )
    {
        double _Ux, _Uy;
        _Ux = m_Group[i].x - Xc;
        _Uy = m_Group[i].y - Yc;

        Ux += _Ux * _Ux;
        Uy += _Uy * _Uy;
        Uxy += _Ux * _Uy;
    }

    Ux = 1.0/12 + Ux / m_Group.size();
    Uy = 1.0/12 + Uy / m_Group.size();
    Uxy = 1.0/12 + Uxy / m_Group.size();

    tmp = Ux - Uy;
    C = sqrt( tmp * tmp + 4 * Uxy * Uxy );

    if ( Uy > Ux )
        O = atan(( Uy - Ux + C ) / ( 2 * Uxy ));
    else
        O = atan(( 2 * Uxy ) / ( Ux - Uy  + C ));

    return O;

}
void Object::Scale( double s )
{
    Object o;
    for ( int i = 0; i < m_Group.size(); i ++ )
        o.AddPoint( s * m_Group[i].x + 0.5, s * m_Group[i].y + 0.5 );

    Field f = o.GetField();
    Clear();
    GetFromField( f );
}
void Object::Rotate(double Angle)
{
    //Scale( 2 );

    double SinA = sin( Angle );
    double CosA = cos( Angle );
    double Xc = m_SumX; 
    double Yc = m_SumY;
    Object o;

    Xc /= m_Group.size();
    Yc /= m_Group.size();

    for ( int i = 0; i < m_Group.size(); i ++ )
    {
        double Ux = m_Group[i].x - Xc;
        double Uy = m_Group[i].y - Yc;
        double x = Ux * CosA - Uy * SinA;
        double y = Ux * SinA + Uy * CosA;
        //o.AddPoint( (int)(x), (int)(y));

        o.AddPoint( (int)x, (int)y );
        o.AddPoint( (int)(x + .5), (int)(y));
        o.AddPoint( (int)(x), (int)(y + .5));
        o.AddPoint( (int)(x + .5), (int)(y + .5));

    }

    Field f = o.GetField();
    //f.Smooth();
    Clear();
    GetFromField( f );
}



int FieldDistance( Field &f1, Field &f2 )
{
    int x, y;
    int d = 0;

    for ( x = 0; x < max( f1.Width(), f2.Width()); x ++ )
    {
        for ( y = 0; y < max( f1.Height(), f2.Height()); y ++ )
            d += abs( f1.At( x, y ) - f2.At( x, y ));
    }

    return d;
}
unsigned data0[] = {0x3FC01FF0, 0xD8006C, 0x630031, 0x8038E018, 0x300C180C, 0xE07FF03, 0x1830061, 0x8031C019, 0xF83FFC1F, 0xF07FF83F};
Fld pat0 = {17, 17, data0};
unsigned data1[] = {0xFFE1FFF0, 0xC0E180E3, 0xC6038C, 0xE1FF83F, 0xF86038C0, 0x39803300, 0x6601CC07, 0xBFFE7FF0};
Fld pat1 = {15, 17, data1};
unsigned data2[] = {0xFC87FE3, 0x839C06E0, 0xB000C00, 0x3000C003, 0xC0030, 0x600DC0, 0x73C787FC, 0xE1FF00E0};
Fld pat2 = {14, 17, data2};
unsigned data3[] = {0xFFC3FFC6, 0x3180E60, 0x1D803600, 0xD803600D, 0x803600D8, 0x3601D80, 0xE6073FF8, 0xCFFE3FE0};
Fld pat3 = {14, 17, data3};
unsigned data4[] = {0xFFFBFFE3, 0x18C0630, 0x18C60318, 0xFE03F80, 0xC603180C, 0x3300CC0, 0x3300FFFF, 0x3FFFFFFF};
Fld pat4 = {14, 17, data4};
unsigned data5[] = {0xFFFFFFF3, 0xCC0330, 0xCC60318, 0xFE03F80, 0xC603180C, 0x3000C0, 0x3003FE0, 0xFF83FC0};
Fld pat5 = {14, 17, data5};
unsigned data6[] = {0xFC87FE3, 0x839C06E0, 0xB000C00, 0x3000C003, 0x7FC1FF0, 0x2E009C0, 0x238387FE, 0xE1FF80F0};
Fld pat6 = {14, 17, data6};
unsigned data7[] = {0x7C7CF8F8, 0xC06180C3, 0x186030C, 0x61FFC3F, 0xF86030C0, 0x6180C301, 0x86030C06, 0x3F1FFE3E};
Fld pat7 = {15, 17, data7};
unsigned data8[] = {0xFFFFFC18, 0x300600C, 0x1803006, 0xC01803, 0x600C01, 0xC3FFFFF};
Fld pat8 = {11, 17, data8};
unsigned data9[] = {0xFFC3FF0, 0x6001800, 0x60018006, 0x180063, 0x18C0630, 0x18C06383, 0x8F1C1FE0, 0x7F80380};
Fld pat9 = {14, 17, data9};
unsigned data10[] = {0xFE7EFE7E, 0x303830F0, 0x30E033C0, 0x37803F80, 0x3FC038E0, 0x30603030, 0x30303038, 0x3018FE1F, 0xFE1FFE0E};
Fld pat10 = {16, 17, data10};
unsigned data11[] = {0xFF83FE01, 0x80060018, 0x600180, 0x6001800, 0x60018046, 0x1180460, 0x11807FFF, 0x1FFFFFFF};
Fld pat11 = {14, 17, data11};
unsigned data12[] = {0xF00FF81F, 0x781E7C3E, 0x6C366636, 0x66766366, 0x63E663C6, 0x61C66186, 0x60066006, 0x6006FC3F, 0xFC3FFC3F};
Fld pat12 = {16, 17, data12};
unsigned data13[] = {0xF07FF0FC, 0xF031E063, 0xE0C6C18C, 0xC319C631, 0x8C6198C3, 0xB1836306, 0xC6078C0F, 0x9F873F06};
Fld pat13 = {15, 17, data13};
unsigned data14[] = {0xFC07F83, 0x871C0E60, 0x1F003C00, 0xF003C00F, 0x3C00F0, 0x36019C0, 0xE38707F8, 0xC1FE01E0};
Fld pat14 = {14, 17, data14};
unsigned data15[] = {0xFFC7FF8C, 0xE603301, 0x980CC066, 0x73FF1FF, 0xC006003, 0x1800C0, 0x3FE1FE0};
Fld pat15 = {13, 17, data15};
unsigned data16[] = {0x1F83FC70, 0xE606C03C, 0x3C03C03, 0xC03C03E0, 0x770E3FC1, 0xF81F13FF, 0xF13FF38E};
Fld pat16 = {12, 17, data16};
unsigned data17[] = {0xFFC1FFE0, 0xC0C181C3, 0x186030C, 0xE18783F, 0xE07F80C3, 0x81838303, 0x6070C07, 0xBF83FF03};
Fld pat17 = {15, 17, data17};
unsigned data18[] = {0x1FA3FF70, 0xF6074036, 0x7803F8, 0xFE00700, 0x3C03C03E, 0x3F0EFFE, 0xEFFE0F0};
Fld pat18 = {12, 17, data18};
unsigned data19[] = {0xFFFFFFFC, 0x30F0C3C3, 0xF0C3C30, 0x80C00300, 0xC003000, 0xC003000C, 0x300FF8, 0x3FE07F8};
Fld pat19 = {14, 17, data19};
unsigned data20[] = {0xFCFFF3F6, 0x1980660, 0x19806601, 0x98066019, 0x80660198, 0x63018C0, 0xC1C707F8, 0xC1FE01E0};
Fld pat20 = {14, 17, data20};
unsigned data21[] = {0xFC3FFC3F, 0x300C300C, 0x301C1818, 0x18381C30, 0xC300C30, 0x6600660, 0x6E003C0, 0x3C00380, 0x3800180};
Fld pat21 = {16, 17, data21};
unsigned data22[] = {0xFE3FFE3F, 0x60066186, 0x61C673C6, 0x33C433CC, 0x33EC366C, 0x366C366C, 0x362C1E3C, 0x1C3C1C3C, 0x1C3C1C38};
Fld pat22 = {16, 17, data22};
unsigned data23[] = {0xF83EF83E, 0x30381830, 0x1C600EE0, 0x7C00380, 0x38007C0, 0xEE01C60, 0x18303838, 0x701CFC3F, 0xFC3FFC3E};
Fld pat23 = {16, 17, data23};
unsigned data24[] = {0xF87FF0FC, 0xC0E0C181, 0xC6019C03, 0xB003C003, 0x8006000C, 0x180030, 0x6000C0, 0x7FC0FF0};
Fld pat24 = {15, 17, data24};
unsigned data25[] = {0x7FE7FE40, 0xE40C4184, 0x38030060, 0xE01C018, 0x33037036, 0x3C03FFF, 0x3FFFFFF};
Fld pat25 = {12, 17, data25};
unsigned data26[] = {0xC00060, 0x70003C, 0x3E001F, 0x801DC00C, 0xF00E7806, 0x1C03FF03, 0xFF8181E1, 0x8070C03C, 0xE01EFC1F, 0xC03DF83F};
Fld pat26 = {17, 17, data26};
unsigned data27[] = {0xFFE07FF0, 0xE0F1C1E3, 0x81C7038E, 0xF1E3E3F, 0xF870F8E0, 0x79C0F380, 0xE703CE0F, 0xCFFF7FF8};
Fld pat27 = {15, 17, data27};
unsigned data28[] = {0x7EC7DF3, 0xC1DE0370, 0xFC01F00, 0x3800E003, 0x800F003C, 0x7005E0, 0x33C187FC, 0x61FF01F0};
Fld pat28 = {14, 17, data28};
unsigned data29[] = {0xFFE01FFE, 0xE0F8701, 0xE380F1C0, 0x3CE01E70, 0xF38079C, 0x3CE01E7, 0xE380F1, 0xC078E0F8, 0x7FF8FFE0, 0xFFF1FFC0};
Fld pat29 = {17, 17, data29};
unsigned data30[] = {0xFFF87FF0, 0xE031C063, 0x8007020E, 0x41FF83F, 0xF07060E0, 0x41C00380, 0x6700CE03, 0x8FFF7FFE};
Fld pat30 = {15, 17, data30};
unsigned data31[] = {0xFFF1FF8E, 0x6703380, 0x1C10E187, 0x1C3FE1C3, 0xE087003, 0x801C00E0, 0xF01FE0};
Fld pat31 = {13, 17, data31};
unsigned data32[] = {0x7F40F9E, 0xF038F00, 0xC7006780, 0x13C001C0, 0x7FE01F78, 0x73C039E, 0x1C780E3, 0xC070F838, 0x3FFC03F0, 0x7FF807E0};
Fld pat32 = {17, 17, data32};
unsigned data33[] = {0xFF3FCF03, 0xC380E0E0, 0x38380E0E, 0x38380E0, 0xE0383FFE, 0xE038380, 0xE0E03838, 0xE0E0383, 0x80E0F03C, 0xC0F3FCFF};
Fld pat33 = {18, 17, data33};
unsigned data34[] = {0xFF3C3838, 0x38383838, 0x38383838, 0x3838383C, 0x38383CFF};
Fld pat34 = {8, 17, data34};
unsigned data35[] = {0x3F870381, 0xC0E07038, 0x1C0E0703, 0x81C0E773, 0xE773F0F0};
Fld pat35 = {9, 17, data35};
unsigned data36[] = {0xFF7F0F07, 0x38380E1, 0xC038E00E, 0x7003B800, 0xFC003F80, 0xFF003BE, 0xE7C038, 0xF80E1F03, 0x83E0F07E, 0xC1FBFCFF};
Fld pat36 = {18, 17, data36};
unsigned data37[] = {0xFF00F003, 0x800E0038, 0xE00380, 0xE003800, 0xE003800E, 0x3804E0, 0x3380CFFF, 0x33FFFFFE};
Fld pat37 = {14, 17, data37};
unsigned data38[] = {0xFC00FCF0, 0x3C3E01E, 0xF80783E, 0x3E0FC0F, 0x83707E0D, 0xE1B8338E, 0xE0CF3383, 0x1CCE0C7E, 0x3830F8E0, 0xC3C38307, 0xE0E183C, 0xF3F18FF};
Fld pat38 = {22, 17, data38};
unsigned data39[] = {0xF81FBE03, 0x8F8083C0, 0x41F020BC, 0x104F0827, 0xC411E208, 0x79041E82, 0x7C101E0, 0x80F04038, 0x700CFE02, 0xE019FC04};
Fld pat39 = {17, 17, data39};
unsigned data40[] = {0x7E01EF8, 0x383C781C, 0x701EF00E, 0xF00FE00F, 0xE00FE00F, 0xF00EF00E, 0x701E781C, 0x3C381FF0, 0x1FF007C0};
Fld pat40 = {16, 17, data40};
unsigned data41[] = {0xFFC1FF8E, 0x1E70F383, 0x9C1CE1E7, 0x1F3FF1DE, 0xE007003, 0x801C00E0, 0xF01FE0};
Fld pat41 = {13, 17, data41};
unsigned data42[] = {0xF81EE1C, 0x38E0EE07, 0x703F80FC, 0x7E07783, 0x9C1C71C1, 0xFC07C00F, 0xE007C006};
Fld pat42 = {13, 17, data42};
unsigned data43[] = {0xFFE01FF8, 0xE1E0707, 0x38381C1, 0xC0E1E071, 0xE03FC01D, 0xF00E7807, 0x1E038781, 0xC3C0E0F0, 0x783EFF0F, 0xF07DFE1F};
Fld pat43 = {17, 17, data43};
unsigned data44[] = {0x3F4F7B83, 0x706E05E0, 0xBF03F83F, 0x81F80FC0, 0xFC0F81F8, 0xC1BFF4F8};
Fld pat44 = {11, 17, data44};
unsigned data45[] = {0xFFFFFFFC, 0x3860E103, 0x800E0038, 0xE00380, 0xE003800, 0xE003800E, 0x3801E0, 0x7807F8};
Fld pat45 = {14, 17, data45};
unsigned data46[] = {0xFE1F9C03, 0xE018700, 0xC38061C0, 0x30E01870, 0xC38061C, 0x30E0187, 0xC38061, 0xE0307830, 0x1FF003F0, 0x3FE007E0};
Fld pat46 = {17, 17, data46};
unsigned data47[] = {0xFE0FBC03, 0x8F018780, 0xC1E0E0F0, 0x6038301E, 0x30071803, 0xDC00EC00, 0x7E003E00, 0xF000780, 0x18000C0, 0x3000180};
Fld pat47 = {17, 17, data47};
unsigned data48[] = {0xFFFC7CE1, 0xE0E38783, 0xF0E0C1C, 0x382070F1, 0x81E3C603, 0x9F100E7E, 0xC03DBB00, 0x76EC01F3, 0xE007C780, 0xF1E0038, 0x700060C0, 0x300060C0};
Fld pat48 = {22, 17, data48};
unsigned data49[] = {0xFF9F8F81, 0xC1E0E03C, 0x30079801, 0xEC003F00, 0x78001E0, 0x7C003F, 0x801DE006, 0x3C030781, 0xC1E1E03C, 0x80F3F8FF};
Fld pat49 = {18, 17, data49};
unsigned data50[] = {0xFF1FDF03, 0xC3C06078, 0x300E1C03, 0xC6007B00, 0x1EC003E0, 0x78001C, 0x70001, 0xC0007000, 0x1C000780, 0x1E001FE0};
Fld pat50 = {18, 17, data50};
unsigned data51[] = {0x3FFCFFF2, 0x7883C20, 0xF007803C, 0xF00780, 0x3C00F007, 0x803C04F0, 0x1780FFFF, 0x3FFFFFFF};
Fld pat51 = {14, 17, data51};
unsigned data52[] = {0x3800780, 0x1F003F00, 0xEE01DC03, 0x9C0E381C, 0x383FF0FF, 0xE1FFE701, 0xCE03BC03, 0xF803F007};
Fld pat52 = {15, 17, data52};
unsigned data53[] = {0xFFC7FF3F, 0xF9C0EE07, 0x703B879F, 0xFCFFE70F, 0xB81FC07E, 0x3F03BFF, 0xFBFF9FF8};
Fld pat53 = {13, 17, data53};
unsigned data54[] = {0xFC07FC3, 0xFF9E0E70, 0x3F806E00, 0x3800E003, 0x800E01B8, 0x7703DE1, 0xE3FF87FC, 0xE1FF01F0};
Fld pat54 = {14, 17, data54};
unsigned data55[] = {0xFFC3FF8F, 0xFF381EE0, 0x3B80FE01, 0xF807E01F, 0x807E01F8, 0xFE03B81, 0xEFFF3FF8, 0xCFFE3FE0};
Fld pat55 = {14, 17, data55};
unsigned data56[] = {0xFFF7FFBF, 0xFDC00E00, 0x7003801F, 0xFCFFE700, 0x3801C00E, 0x7003FF, 0xFFFFFFFF};
Fld pat56 = {13, 17, data56};
unsigned data57[] = {0xFFFFFFFF, 0xF00E01C0, 0x3807FEFF, 0xDFFB8070, 0xE01C038, 0xC0380700};
Fld pat57 = {11, 17, data57};
unsigned data58[] = {0x7F03FF0, 0xFFF3C0F7, 0xFC01F8, 0x7000E0, 0xFFC1FF80, 0x3F807700, 0xEF83CFFF, 0xC7FE03F0};
Fld pat58 = {15, 17, data58};
unsigned data59[] = {0xE03F01F8, 0xFC07E03, 0xF01FFFFF, 0xFFFFFF01, 0xF80FC07E, 0x3F01F80, 0x1F80FC07};
Fld pat59 = {13, 17, data59};
unsigned data60[] = {0xFFFFFFFF, 0xFFFFFFFF};
Fld pat60 = {3, 17, data60};
unsigned data61[] = {0x381C0E0, 0x70381C0E, 0x70381C0, 0xFC7E3F9F, 0x3FFDFC7C};
Fld pat61 = {9, 17, data61};
unsigned data62[] = {0xE07B83EE, 0x1F38F8E7, 0xC3BE0FF0, 0x3F80FF03, 0xFE0F3C38, 0x78E1E383, 0xCE07B80F, 0xEE03F80F};
Fld pat62 = {14, 17, data62};
unsigned data63[] = {0xE01C0380, 0x700E01C0, 0x380700E0, 0x1C038070, 0xE01C03F, 0xFFFFFFFF};
Fld pat63 = {11, 17, data63};
unsigned data64[] = {0xF00FF01F, 0xF81FF81F, 0xF83FFC3F, 0xFC3FFC37, 0xEE77EE77, 0xEE67E7E7, 0xE7E7E7E7, 0xE3C7E3C7, 0xE3C7E3C7};
Fld pat64 = {16, 17, data64};
unsigned data65[] = {0xE03F81FC, 0xFF07FC3, 0xFF1FF8FD, 0xE7E73F3D, 0xF8FFC3FE, 0x1FF07F81, 0x3F81FC07};
Fld pat65 = {13, 17, data65};
unsigned data66[] = {0xFE03FE0, 0xFFF3C1E7, 0x1FC01F8, 0x3F003E0, 0x7C01F80, 0x3F007701, 0xEF078FFF, 0x87FC03E0};
Fld pat66 = {15, 17, data66};
unsigned data67[] = {0xFFC7FF3F, 0xFDC0FE03, 0xF01F81FC, 0x3EFFF7FF, 0x3801C00E, 0x700380, 0x3801C00};
Fld pat67 = {13, 17, data67};
unsigned data68[] = {0xFC07FE1, 0xFBE3C1CF, 0x3DC03B8, 0x77006E0, 0xDC03B80, 0x738FE79F, 0x8FFF07FF, 0x83FF8006};
Fld pat68 = {15, 17, data68};
unsigned data69[] = {0xFFE3FFCF, 0xFFB80EE0, 0x3B80EE07, 0xBFFCFFE3, 0xFF0E1E38, 0x38E0F381, 0xEE03B80F, 0xEE03F807};
Fld pat69 = {14, 17, data69};
unsigned data70[] = {0x1FC1FF1F, 0xFCE0E607, 0x3819F007, 0xF81FF01F, 0xB81FC07E, 0x3F83DFF, 0xF8FF81F8};
Fld pat70 = {13, 17, data70};
unsigned data71[] = {0xFFFFFFFF, 0xFFC1C007, 0x1C0070, 0x1C00700, 0x1C007001, 0xC007001C, 0x7001C0, 0x7001C0};
Fld pat71 = {14, 17, data71};
unsigned data72[] = {0xE03F01F8, 0xFC07E03, 0xF01F80FC, 0x7E03F01, 0xF80FC07F, 0x7FC79FF, 0xF8FF81F0};
Fld pat72 = {13, 17, data72};
unsigned data73[] = {0xE00FC01F, 0xC03B80E7, 0x1C7078E, 0xE0E1C1C, 0x7838E039, 0xC077006E, 0xFC01F0, 0xF001C0};
Fld pat73 = {15, 17, data73};
unsigned data74[] = {0xE0781F81, 0xE07F07C1, 0xDC3F0770, 0xFC39C3B0, 0xE31EE38E, 0x738C39C6, 0x70E71DC1, 0xB87707E1, 0xD81F83E0, 0x7C0F80F0, 0x3E03C070, 0x1C038070};
Fld pat74 = {22, 17, data74};
unsigned data75[] = {0x781CF078, 0xF0E0F3C0, 0xEF01FC01, 0xF801E007, 0xC00FC03F, 0xC0F781C7, 0x87879E07, 0xBC07F807};
Fld pat75 = {15, 17, data75};
unsigned data76[] = {0xF01FE039, 0xE0F1E1C1, 0xC703DE03, 0xB807F007, 0xC007000E, 0x1C0038, 0x7000E0, 0xE001C0};
Fld pat76 = {15, 17, data76};
unsigned data77[] = {0x7FF9FFE7, 0xFF803C00, 0xE007803C, 0x1E00F00, 0x3C01E00F, 0x7803C0, 0xFFFFFFF, 0xFFFFFFFF};
Fld pat77 = {14, 17, data77};
Fld * Pats[] = {
&pat0, &pat1, &pat2, &pat3, &pat4, &pat5, &pat6, &pat7, &pat8, &pat9, &pat10, &pat11, &pat12, &pat13, &pat14, &pat15, &pat16, &pat17, &pat18, &pat19, &pat20, &pat21, &pat22, &pat23, &pat24, &pat25, &pat26, &pat27, &pat28, &pat29, &pat30, &pat31, &pat32, &pat33, &pat34, &pat35, &pat36, &pat37, &pat38, &pat39, &pat40, &pat41, &pat42, &pat43, &pat44, &pat45, &pat46, &pat47, &pat48, &pat49, &pat50, &pat51, &pat52, &pat53, &pat54, &pat55, &pat56, &pat57, &pat58, &pat59, &pat60, &pat61, &pat62, &pat63, &pat64, &pat65, &pat66, &pat67, &pat68, &pat69, &pat70, &pat71, &pat72, &pat73, &pat74, &pat75, &pat76, &pat77, };
struct pattern
{
    pattern(const Field &_f): f(_f){}
    Field f;
    char c;
};
std::vector< pattern > Patterns;

int main(int argc, char * argv[])
{
    int i, t;
    scanf( "%d", &t );
 
    

    for ( i = 0; i < countof( Pats ); i ++ )
    {
        Field f ( Pats[i]->m_Width, Pats[i]->m_Height );
        f.ReadVar( Pats[i]->data );
        pattern pat( f );
        pat.c = i % 26 + 'A';
        Patterns.push_back( pat );
    }

    Field f( WIDTH, HEIGHT );
    
    while( t-- )
    {
        f.Read( stdin );
        
        std::vector<Object> Objects = f.Split();
        Object GroupObject;

        for( int i = 0; i < Objects.size(); i ++ )
            GroupObject.GetFromObject( Objects[i] );

        double O = GroupObject.GetOrientation();

    
        for( int i = 0; i < Objects.size(); i ++ )
        {
            Object obj = Objects[i];
            obj.Scale( 3 );
            obj.Rotate( -O );
            Field fld = obj.GetField();
            fld.Morph( true );
            fld.Morph( false );
            fld.Smooth();
            fld.Smooth();
            obj.GetFromField( fld );
            obj.Scale( 16.0 / fld.Height());
            fld = obj.GetField();

            int min_distance = 0xfffffff;
            int index = -1;

            for ( int j = 0 ;j < Patterns.  size(); j ++ )
            {
                int d = FieldDistance( fld, Patterns[j].f );

                if ( d < min_distance )
                {
                    min_distance = d;
                    index = j;
                }
            }

            printf( "%c", Patterns[ index ].c );
        }

        printf("\n");
    }
}