달팽이 배열(수열?) 다듬은 버전 Programing

달팽이 배열?
-----------------------------------------------------------------------------------------------
위 링크의 코드는 1년 10개월전 쯤 작성 했던 코드.
그때 뭐 대충 작성하긴 했지만.
오늘 할게없어서..(휴가중)
이전 코드를 찾아 리팩토링 해봤다.
하면서 기능 추가도 했고.
이제 객체로서의 볼품을 갖춘 모습.
(대학 과제로 자주 나오나보다 --)
-----------------------------------------------------------------------------------------------


#include <stdio.h>
#include <map>
#include <assert.h>

class IDrawableObject
{
public:
    virtual void Draw() = 0;
}

// 이 클래스 자체는 자료구조 목적의 기능만을 가져야 한다.
// 하지만 예제 이해의 접근성을 위해 따로 데이터를 가지고 랜더링하는 오브젝트를 만들지는 않았다.
class CSnailArray : public IDrawableObject
{
private:
    typedef int Direction;
    typedef int Increase;
    typedef std::map<Direction, Increase> IncreaseByDirection;

private :
    static int const FirstDirection = 0;
    static int const DirCount = 4;


    Direction m_dirRight;
    Direction m_dirDown;
    Direction m_dirLeft;
    Direction m_dirUp;

    int m_nSize;
    int * m_pArr;
    IncreaseByDirection m_mIncreaseByDirection;

public :
    CSnailArray();
    CSnailArray( int nSize );
    virtual ~CSnailArray( );


    void  SetReverse(bool bReverse);
    bool  IsReverse(); // default false


    bool  GenerateSnailArray(int nSize);
    void  Release();


    bool  GetValue(int& outBuffer, int _1DimensionIndex, int _2DimensionIndex);
    int const * GetArray();


    // 이 클래스는 기본으로 콘솔에 출력 한다.
    virtual void Draw();
private:
    void  SetSize(int nSize);
    int   GetSize();


    bool  IsFirstDirection(Direction dir);
    Direction GetFirstDir();
    Direction GetNextDirection(Direction curDir);


    // 달팽이 배열이 진행될 순서를 정한다
    void  SetDirectionFlow(int nRight, int nDown, int nLeft, int nUp);


    void  InitializeList();

    void  GenIncreasement();
    void  GenArray();
    void  CreateArray();

    void  ReleaseArray();


    Increase GetIncreaseOffsetCount(Direction dir);

    void  DrawToArray(Direction startDir);
    void  DrawToArray(int& nCurOffset, int&nCurValue, Direction dir, int nDrawCount);

    void  PrintToConsole( );
};


CSnailArray::CSnailArray()
{
    InitializeList();
}


CSnailArray::CSnailArray( int nSize )
{
    InitializeList();
    SetSize(nSize);
    GenerateSnailArray(nSize);
}

CSnailArray::~CSnailArray( )
{
    ReleaseArray();
}


void CSnailArray::InitializeList()
{
    m_nSize  = 0;
    m_pArr  = NULL;

    // 정방향 셋팅
    SetReverse(false);
}

void CSnailArray::SetDirectionFlow(int nRight, int nDown, int nLeft, int nUp)
{
    m_dirRight = nRight;
    m_dirDown = nDown;
    m_dirLeft = nLeft;
    m_dirUp  = nUp;
}

CSnailArray::Direction CSnailArray::GetFirstDir()
{
    if( IsFirstDirection(m_dirRight) ) return m_dirRight;
    if( IsFirstDirection(m_dirDown) ) return m_dirDown;
    if( IsFirstDirection(m_dirLeft) ) return m_dirLeft;
    if( IsFirstDirection(m_dirUp) )  return m_dirUp;


    assert( 0 && "First Dir이 존재하지 않음" );

    return (Direction)-1;
}

bool CSnailArray::IsFirstDirection(Direction dir)
{
    return dir == FirstDirection;
}

void CSnailArray::SetReverse(bool bReverse)
{
    int nRightIndex = bReverse ? 1 : 0;
    int nDownIndex = bReverse ? 0 : 1;
    int nLeftIndex = bReverse ? 3 : 2;
    int nUpIndex = bReverse ? 2 : 3;

    SetDirectionFlow(nRightIndex, nDownIndex, nLeftIndex, nUpIndex);
}


bool CSnailArray::IsReverse()
{
    // Down방향이 첫번째 방향이면 리버스
    return IsFirstDirection(m_dirDown);
}

void CSnailArray::CreateArray( )
{
    ReleaseArray( );

    m_pArr = new int[m_nSize*m_nSize];
    int i = 0;
    while( i < m_nSize*m_nSize ) m_pArr[i++] = 0;
}

void CSnailArray::ReleaseArray( )
{
    // SAFE_DELETE_ARR(m_pArr);
    if( m_pArr )
    {
        delete [] m_pArr;
        m_pArr = NULL;
    }
}

void CSnailArray::GenArray( )
{
    CreateArray( );
}


void CSnailArray::GenIncreasement()
{
    m_mIncreaseByDirection.clear();

    m_mIncreaseByDirection[m_dirRight] = 1;  // Right방향은 오른쪽으로 한칸 이동
    m_mIncreaseByDirection[m_dirDown] = m_nSize; // Down방향은 사이즈만큼 앞으로 이동
    m_mIncreaseByDirection[m_dirLeft] = -1;  // Left방향은 왼쪽으로 한칸 이동
    m_mIncreaseByDirection[m_dirUp]  = -m_nSize; // Up방향은 사이즈만큼 뒤로 이동
}

void CSnailArray::SetSize(int nSize)
{
    m_nSize = nSize;
    GenIncreasement();
}


int CSnailArray::GetSize()
{
    return m_nSize;
}

bool CSnailArray::GenerateSnailArray(int nSize)
{
    SetSize(nSize);
    GenArray( );

    Direction direction = GetFirstDir();
    if( direction == -1 ) return false;

    DrawToArray(direction);

    return true;
}

void CSnailArray::DrawToArray(Direction startDir)
{
    int nDrawCount = m_nSize;// 최대사이즈
    int nDrawCountLifeCycle = 1;// 최대사이즈는 한번만 긋는다

    // 처음 오프셋 증가값을 대입하기전에 대입시 0이 되게 -값 대입 == Offset 0부터 시작되게 하는 처리
    int nOffset = -m_mIncreaseByDirection[startDir];
    Direction curDirection = startDir;

    int nValue = 1;
    while( nValue <= (m_nSize * m_nSize) )
    {
        if( nDrawCountLifeCycle == 0 )
        {
            --nDrawCount;
            nDrawCountLifeCycle = 2;
        }

        DrawToArray(nOffset, nValue, curDirection, nDrawCount);

        --nDrawCountLifeCycle;
        curDirection = GetNextDirection(curDirection);
    }
}


// nCurOffset부터 nCurValue를 dir방향으로 nDrawCount만큼 씀
void CSnailArray::DrawToArray(int& nCurOffset, int&nCurValue, Direction dir, int nDrawCount)
{
    for( int iCount = 0; iCount < nDrawCount; ++nCurValue, ++iCount )
    {
        nCurOffset += GetIncreaseOffsetCount(dir);
        m_pArr[nCurOffset] = nCurValue;
    }
}


CSnailArray::Increase CSnailArray::GetIncreaseOffsetCount(Direction dir)
{
    return m_mIncreaseByDirection[dir];
}

CSnailArray::Direction CSnailArray::GetNextDirection(Direction curDir)
{
    Direction dirNextValue = curDir + 1;
    Direction dirDispatchedNextValue = dirNextValue % DirCount;

    return dirDispatchedNextValue;
}


void CSnailArray::Release()
{
    m_nSize = 0;
    ReleaseArray();
}


bool CSnailArray::GetValue(int& outBuffer, int _1DimensionIndex, int _2DimensionIndex)
{
    if( _1DimensionIndex < 0 || _1DimensionIndex >= m_nSize ) return false;
    if( _2DimensionIndex < 0 || _2DimensionIndex >= m_nSize ) return false;

    int nIndex = (_2DimensionIndex*m_nSize + _1DimensionIndex);
    outBuffer = *(m_pArr + nIndex);
 
    return true;
}

int const * CSnailArray::GetArray()
{
    return m_pArr;
}


void CSnailArray::Draw()
{
    PrintToConsole();
}

void CSnailArray::PrintToConsole( )
{
    printf( "\n" );

    int i = 0;
    while( i < m_nSize * m_nSize )
    {
        printf( "%3d ", m_pArr[i] );
        if( (( i+1 ) % m_nSize) == 0 )
           printf( "\n" );
        ++i;
    }
}

void main()
{
    CSnailArray kSnArr(10);
    kSnArr.Draw();
    kSnArr.Release();


    // reverse snail
    kSnArr.SetReverse(true);
    kSnArr.GenerateSnailArray(5);
    kSnArr.Draw();
// kSnArr.Release();


    int nPickVal = -1;
    if( kSnArr.GetValue(nPickVal, 4, 3) )
        printf("\narray[4,3] == %d\n", nPickVal);
    else
        printf("\n[CSnailArray::GetValue] 유효하지 않은 범위의 인덱스로 참조 시도\n");


    kSnArr.Release();
}

-----------------------------------------------------------------------------------------------
결과

__1 __2 __3 __4 __5 __6 __7 __8 __9 _10
_36 _37 _38 _39 _40 _41 _42 _43 _44 _11
_35 _64 _65 _66 _67 _68 _69 _70 _45 _12
_34 _63 _84 _85 _86 _87 _88 _71 _46 _13
_33 _62 _83 _96 _97 _98 _89 _72 _47 _14
_32 _61 _82 _95 100 _99 _90 _73 _48 _15
_31 _60 _81 _94 _93 _92 _91 _74 _49 _16
_30 _59 _80 _79 _78 _77 _76 _75 _50 _17
_29 _58 _57 _56 _55 _54 _53 _52 _51 _18
_28 _27 _26 _25 _24 _23 _22 _21 _20 _19

__1 _16 _15 _14 _13
__2 _17 _24 _23 _12
__3 _18 _25 _22 _11
__4 _19 _20 _21 _10
__5 __6 __7 __8 __9


array[4,3] == 10
-----------------------------------------------------------------------------------------------

놀자!


트랙백

이 글과 관련된 글 쓰기 (트랙백 보내기)
TrackbackURL : http://eve8110.egloos.com/tb/4249666 [도움말]

덧글

덧글 입력 영역