perpet

예전에 작업하면서 코드를 어디서 주어왔는데 기억이 안난다.

그래도 참고 사이트 


http://www.codeproject.com/Articles/151946/A-High-Performance-Binary-Serializer-using-Microso


테스트 코드는 

https://dev.naver.com/svn/cgs/trunk/PacketDefine/PacketHandlerSample



Comment +12

surf

스터디/C++,CLI,C#2011. 5. 14. 00:13

 

 http://en.wikipedia.org/wiki/SURF

 

여기서 설명하는 SURF 알고리즘 opencv 에 있는 find_obj 소스코드를 기반으로 만들어졌다.

 

1.특징점 추출

( octave , layer , wavelet, hessian 을 이용해 크기와 회전에 강한 특징점을 찾아낸다)

 

 1-1 소스 이미지 integral(적분) 한다.

 개요 : wavelet 정보를 뽑을때 적분영상이 있어야 빠른 wavelet 정보를 만들수있음

 참고자료 :

 http://www.codeproject.com/KB/audio-video/haar_detection.aspx

 http://aisitei.tistory.com/174

 입력 : 입력영상

 처리 : x 축 y 축을 증가시키면서 누적된 픽셀정보를 저장한다

 출력 : 적분을 표현(representation) 한 영상

 

1-2 wavelet 정보 추출

 개요: wavelet mask 를 이용해 wavelet 정보를 octave *  layer 갯수 만큼 만든다

 octave: 이미지의 샘풀링 갯수를 지정 : ( 참고자료 : sift 의 의도와 비슷한 뜻)

              만약 3 이라면

               원본이미지 -> 원본이미지/2 -> 원본이미지 /4   의 이미지를 가짐

 layer : 해당 octave 이미지에 몇개의 layer(size) 로 wavelet 정보를 만들지 결정

            만약 3이라면

             wavelet size   ->  wavelet size  / 2 -> wavelet size/4

 

참고자료:

 http://www.cs.ucf.edu/~mali/haar/

http://www.codeproject.com/KB/graphics/edge_detection.aspx?msg=2331630

 입력 :

적분 영상

Wavelet data

    const int dx_s[NX][5] = { {0, 2, 3, 7, 1}, {3, 2, 6, 7, -2}, {6, 2, 9, 7, 1} };
    const int dy_s[NY][5] = { {2, 0, 7, 3, 1}, {2, 3, 7, 6, -2}, {2, 6, 7, 9, 1} };
    const int dxy_s[NXY][5] = { {1, 1, 4, 4, 1}, {5, 1, 8, 4, -1}, {1, 5, 4, 8, -1}, {5, 5, 8, 8, 1} };

x                                                                     y                                                  xy

Wavelet(1).png 

 

 처리 :  

dx  = icvCalcHaarPattern( s_ptr, Dx, 3 );
dy  = icvCalcHaarPattern( s_ptr, Dy, 3 );
dxy = icvCalcHaarPattern( s_ptr, Dxy, 4 );


각각의 (x , y xy)  wavelet data 를 이용해 x,y,xy 값을 추출

출력 : layer 별 각각의 x,y,xy 정보를 추출

 

 1-3  헤시안 연산

 개요:  x,y,xy 의 wavelet 정보를 바탕으로 헤시안 연산을 하여 hessianThreshold 값이 넘으면 이웃 헤시안 값을 비교 하여 layer 을 포함한 이웃 26 개 정보와 비교후 가장 값이 크면 interpolation 후 특지점으로 추가한다

 입력 : layer 별 wavelet (x,y,xy) 정보

 처리 :

  *det_ptr++ = (float)(dx*dy - 0.81*dxy*dxy);
 *trace_ptr++ = (float)(dx + dy);

연산후 

 

 /* Non-maxima suppression. val0 is at N9[1][4]*/
                        if( val0 > N9[0][0] && val0 > N9[0][1] && val0 > N9[0][2] &&
                            val0 > N9[0][3] && val0 > N9[0][4] && val0 > N9[0][5] &&
                            val0 > N9[0][6] && val0 > N9[0][7] && val0 > N9[0][8] &&
                            val0 > N9[1][0] && val0 > N9[1][1] && val0 > N9[1][2] &&
                            val0 > N9[1][3]                    && val0 > N9[1][5] &&
                            val0 > N9[1][6] && val0 > N9[1][7] && val0 > N9[1][8] &&
                            val0 > N9[2][0] && val0 > N9[2][1] && val0 > N9[2][2] &&
                            val0 > N9[2][3] && val0 > N9[2][4] && val0 > N9[2][5] &&
                            val0 > N9[2][6] && val0 > N9[2][7] && val0 > N9[2][8] )

 

이웃중 가장 큰값인지 확인을 한후 보간을 통해 더 정확한 값을 얻어와서 특지점 리스트에 추가한다.

여기서 보간의 의미는 opencv 게시판에 누군가 잘설명한 것이 있는데 차후 주소를 알게되면 링크추가 예정

 

//////////////////////////////////////////////////////////////////////////////

 2.디스크립터 만들기

찾아낸 특징점에 고유영역을 표현할수있는 디스크립터를 만든다.

 

2-1 orientation 가우시안 웨이트를 만든다.

아래 링크에 있는 이미지와같은 정보를 얻음

http://retina.anatomy.upenn.edu/~lance/modelmath/gaussian.html

ORI_RADIUS = 6

ORI_RADIUS * ORI_RADIUS  방향에 따른 가우시안 웨이트 생성

 

2-2 patch 정보에 대한 가우시안 웨이트를 만든다.

 PATCH_SZ = 20

 PATCH_SZ * PATCH_SZ 영역에 대한 가우시안 웨이트 생성

 

2-3 각방향에 대한 orientation 정보 생성

 개요 : 특징점 주위 6 *6  사이즈안에 있는 모든 포인트에대해서 wavelet 수치를 얻는다.

입력 : 적분이미지

 

처리 :

                        

                 Untitled(3).png

 

black : 특징점

 red : ORI_RADIUS * ORI_RADIUS 방향 안에 있는 점들

green : PATCH_SZ 사이즈 박스 * 특지정에 포함된 사이즈 정보( 소스 100% 분석 안함)

 

green 박스와 아래 wavelet data  연산을 하여 orientation 정보를 만듬

 wavelet2.png

 

 각도에 따른 모든 wavelet 수치를 합산하여 가장 큰 각도 값을 얻는다. 가령 위에서는 파란색이 가장 큰 각도라 판단함

 

 출력 : 가장 수치가 높은 각도를 얻음( 회전에 강한 정보를 얻기위한 초기단계)

 

 2-4 디스크립터 생성

개요 : 크기와 회전에 강한 정보를 만듬

 입력 :  입력 이미지, 윗단계에서 얻은 가장 반응성있는 각도 정보

처리 :

descriptor2.png 

 입력된 방향정보를 기반으로 이미지정보의 gradients 값을 계산한다.

gradients 값을 기반으로 64bin 또는 128 bin  디스크립트 정보를 생성한다.

출력 :  디스크립터 정보 생성

 

3 정합 (matching)

새로운 이미지와 기존에 인식된 이미지정보의 디스크립터를 분석하여 같은 정보인지를 판별하는 작업

FLANN(Fast Library for Approximate Nearest Neighbors)

속도를 개선하기위해 정확도에 따라 근접하였다고 판단되면 해당 인덱스 값을 리턴한다.(내부적인 알고리즘 방식은 아직 분석안했음)

참고자료:

 http://people.cs.ubc.ca/~mariusm/

 http://people.cs.ubc.ca/~mariusm/index.php/FLANN/FLANN

입력 : 인식된 기술자 와 새로입력된 기술자 정보

처리 : 

 

cv::flann::Index flann_index(m_image, cv::flann::KDTreeIndexParams(4));  // using 4 randomized kdtrees

새로 들어온 이미지에대한 디스크립 정보를 kdtree 구조를 기반으로 인덱스를 만든다.

 

flann_index.knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params);

 // queries 비교할 원본이지의 디스크립터 정보

//  indices  queries 요청한 정보와 가장 근사한 인덱스 정보를 뽑아준다.

//  dists       뽑아준 인덱스 정보(거리값)을 리턴해준다.

//  knn       가장 근사한 후보인덱스 갯수 요청

 

인식되여있는 기술자정보를 queries 값으로 주면 해당하는  가장 비슷하다고 판단된 새로운기술자정보의 인덱스를 knn  갯수만큼 

평가된 dits 정보와 같이 준다

여기서 knn 이 2 값을 사용하여 가장 가깝다고 생각하는 인덱스 2개를 뽑는다.

dists_ptr[2*i]<0.6*dists_ptr[2*i+1]

이두개의 인덱스 평가값이 거의 비슷한 수치가 나오면 같은 기술자정보로 인식한다.

이것이 의미하는것은 하나의 입력이미지에 octave 마다  기술자 정보가 있기 때문에 octave 갯수만큼 기술자가 검색되여지는 특징을 이용한 것이다.

 

출력 : 같은 기술자 정보라고 인식되여진 페어 정보

 

 cvFindHomography 이용하여 객체의 정확한 범위?를 측정

 

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.

Comment +6

  • perpet 2011.05.14 00:17

    예전에 surf 를 분석했을때 정리하던 자료
    몇년전부터느끼지만 비젼처리 하는쪽 소스를 보면서 수학적지식뿐아니라
    문제를 푸는 사고가 넓어지는것 같다.

  • 좋은 자료 설명, 감사합니다.

  • ugg 2013.07.14 18:24

    창밖을 봐 바람에 나뭇가지가 살며시 흔들리면 네가 사랑하는 사람이 널 사랑하고 있는거야.

  • 창밖을 봐 바람에 나뭇가지가 살며시 흔들리면 네가 사랑하는 사람이 널 사랑하고 있는거야.

  • 좋으면 좋고 싫으면 싫은 거지, 뭐가 이렇게 어렵고 복잡하냐구

  • ama3208 2018.03.16 11:51

    opencv 에 있는 find_obj 소스코드를 기반으로 만들어졌다는 말씀은 opencv를 이용해서 짠 알고리즘이라는건가요 ??

 자신들이 만든 게임의 캐릭터 액션정보나 AI 스테이트 정보를 비주얼툴로 보거나 보여주고 싶을때가 있다.

간단한게 외부라이브러리를 이용해 하루만에 뷰어를 만들수있는 툴을 만들어보자.

 

작업프로세스는 이렇다.

게임 액션과 액션사이에 링크정보가 있다 이것은 특정 이벤트가 발생해야만 다른액션으로 이동을 하는 구조를 가질수있다.

가령 stand 액션에서 key_left 가 눌러지면 left_uun , key_right ,눌리면 right_run 이란 액션으로 넘어간다고 하고 이것을 텍스트 형식으로 저장을 하면

state : stand

link : key_left, left_run

link : key_right , right_run

state : left_run

state : right_run

 

이런식으로 기획자들이 자신들이 편한 방식으로 텍스트, 또는 xml 로 저장을 할것이다.

프로그래머가 자주 이 링크정보를 보고싶을때가 있는데 이정보가 일반적으로 한캐릭에 수십가지의 액션정보가 있어 텍스트로 보기로는 상당히 힘들다

 

 이런텍스트를 uml 툴같은 다이어그램으로 보고 싶을때가있는데 여기서 가장 손쉽고 빠르게 만드는 방법을 설명한다.

 

작업방식은 공개된 다이어그램 뷰어를 구해서 그포맷에 맞게 자신들의 콘텐츠정보를 컨버트 해주면된다.

여기서는 http://www.graphviz.org/ 를 사용했다. 우리가 해줄것은 이 공개소프트웨어가 인식가능한 포맷으로 나의 컨텐츠 정보를 읽어와 변경해주면된다.

 graphviz    에서 dot 포맷이 있는데 이것으로 직접 내가 포맷을 만들어줘도 되지만 이 컨버팅 작업또한 공개소스를 이용하면 간단하게 해결할수있다.

http://quickgraph.codeplex.com/ 에가면 쉽고 간단하게 dot 포맷으로 변경가능하다.

 

전체 작업방식은 내콘텐츠 정보를 읽어 QuickGraph  를 이용해 dot 포맷파일을 생성하고  graphviz 로 이파일을 가지고 원하는 다이어그램 이미지를 만들면된다.

 

 QuickGraph 로 dot 를 생성하면

 digraph G {
0 [label="stand"];
1 [label="left_run"];
2 [label="right_run"];
0 -> 1 [ label="key_left"];
0 -> 2 [ label="key_right"];
}

 

이 만들어지고

 

  graphviz  를 돌리면

 

command>  dot a.dot -Tjpg -o a.jpg

 

 

Throwing_Spirit_Grudge.gif 

 

 

 파일이 나온다.

 

 

 

 

 

 

 

 

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.

Comment +1

  • ghd 2013.07.17 10:06

    눈을 감아봐 입가에 미소가 떠오르면 네가 사랑하는 그 사람이 널 사랑하고 있는거야.

소스요청하시는분들이 몇분계서서 올려요

설명은 http://blog.daum.net/hazzling/16781469
참고하시면됩니다.
HMM

Comment +0

1년동안 다른거 공부하랴 c# 게임서버에 신경을 못쓰고 있네요.

간단하게 제가 제시하는 코딩방식은 이렇습니다.

 

예를 들어 설명하자면 유저가 로그인하여 아이디와 패스워드를 검증하는 코딩을 짠다고 봅시다.

보통 디비쿼리시 디비에 쿼리를 날리는순간 블럭이 되여 이것을 비동기 처리합니다.

그래서 코드가 보통이렇게 되죠.

 

void login_packet(string id, string pass)

{

int x;

db.query_login(id,pass,query_resultLogin) ; // 쿼리 결과 핸들 등록

return;

}

 

void query_resultLogin(int ret)

{

   if( ret == 0)   // 결과에 따라 처리

 

   client.send_login_result(ret) ;

 

}

 

이걸 c# 에서 yield 를 이용한 코딩을 하면 간단하게

 

void login_packet(string id, string pass)

{

int x;

yield db.query_login(id,pass) ;

 

  if( ret == 0)   // 결과에 따라 처리

 

   client.send_login_result(ret) ;

}

 

이렇게 표현될수있다는겁니다.

이런구조의 장점을 들어보자면

  1.  함수하나의 스코프안에서 원하는 구현부위를 표현하여 직관적입니다.
  2. 원시적인 비동기콜방식으로 할경우 쿼리 전 변수가 쿼리결가후에도 필요하면 해당변수를 외부에 저장할 글로벌 변수로 만들어야합니다. 위에 x 라는 변수가 쿼리 결과에서도 참조가 필요한 케이스가 발생할경우..( yield 를 하면 필요가 없겠죠)
  3.  명시적인 리모트 함수선언을 할수있습니다. 지금까지는 일반적인 패킷함수를 표현하면 void login(id,pass)  를 표현하면 알아서 loing 패킷을 만들어주고 send 함수를 만들어주는 수준이지만 yield  구조를 갖으면 리턴받아야하는 패킷도 명시적으로 표현할수있습니다.  가령 int query_login(id,pass) 라고 패킷을 선언하면 컨텐츠코딩단에서 해당하는 query_login 결과값이 올때까지 다른핸들링이 작동을 안하도록 할수있습니다. 또한 요청을 수행하는 디비단이나 다른서버가 다른형식의 패킷을 보내면 시퀀스를 어겼다고 네트웍시스템이 감지할수있습니다.

     

구체적인 구조를다시 만들면

 

server 인터페이스 선언에

int login_packet(string id,string pass) ;  를 선언하고

 

int login_packet(string id, string pass)

{

int x;

yield db.query_login(id,pass) ; <= db 에 쿼리를 날리고 올때까지 알아서 기다려줌(그동안 다른 클라이언트핸들링은 처리됨)

 

  if( ret == 0)   // 결과에 따라 처리

 

yield return ret;  <= loing_packet 를 콜한 콜러에게 send 해줌 , 또한 함수 선언에 리턴값으로 int 를 준다고 했으므로 리턴이 없거나 다른형을날리면 네트웍 시스템이 인지하여 경고처리가 가능

}

 로 표현이 됩니다.  마치 일반 어플리케이션 코딩하듯이 하면된다는거죠

 

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.

Comment +1

  • ghd 2013.07.13 13:18

    귀를 기울여봐 가슴이 뛰는 소리가 들리면 네가 사랑하는 그 사람 널 사랑하고 있는거야.

 작업하다보면 foreach 안에서 remove 를 할때가 꼭있다.

속도무시하고 편하게 사용하고 싶을때 사용하면 좋을듯하다.

어떤식으로 구현하는지 의도만 파악하고 자신의 입맛대로 바꾸길 바란다.

 

lib 코드

  1.  
  2. using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
  3. /// 버전 0.1
    /// perpet@hitel.net 구본수
    /// 소스 수정해서 사용하는건 문제 없으나 수정을 하면 반드시 원 제작자에게 수정된 소스를 메일로 보내야합니다. 버그나 개선된것을 꼭알려달라는 뜻입니다.
    ///
    /// 초기 버전이라 버그가 많을수있습니다..
  4.  
  5. namespace Foreach_safe_list
    {
  6.     class SafeCollection<TKey, TValue> //: Dictionary<TKey, TValue>
        {
            //원본리스트
            Dictionary<TKey, TValue> _List = new Dictionary<TKey,TValue>();
  7.         // 임시 add list
            Dictionary<TKey, TValue> _AddList = new Dictionary<TKey, TValue>();
  8.         // 임시 remove list
            List<TKey> _RemoveList = new List<TKey>();
  9.         public Dictionary<TKey, TValue>.KeyCollection Keys
            {
                get { return _List.Keys; }
           
  10.        }
  11.  
  12.         public void Clear()
            {
                if (bForeachCount == 0)
                {
                    _List.Clear();
                }
                else
                {
  13.                 _AddList.Clear();
                    _RemoveList.Clear();
  14.                 foreach(TKey key in _List.Keys)
                        _RemoveList.Add(key);
  15.             }
  16.         }
  17.        public Dictionary<TKey, TValue>.ValueCollection Values {
               get{return _List.Values;}
            }

  18.         public bool ContainsKey(TKey key)
            {
                // 제일 먼저 add list 에서 찾아봐야한다
                bool ret = _AddList.ContainsKey(key);
                if (ret == true)
                    return true;
                // 그다음 remove list 에서 찾아봐야한다.
                if (_RemoveList.Contains(key))
                {
                    return false;
                }
  19.             return _List.ContainsKey(key);
            }
  20.         public bool TryGetValue(TKey key, out TValue value)
            {
                if (bForeachCount == 0)
                {
                    return _List.TryGetValue(key, out value);
                }
                else
                {
                    // 제일 먼저 add list 에서 찾아봐야한다
  21.                 bool ret = _AddList.TryGetValue(key, out value);
                    if (ret == true)
                        return true;
  22.                 // 그다음 remove list 에서 찾아봐야한다.
                    if (_RemoveList.Contains(key))
                    {
                        return false;
                    }

  23.                 return _List.TryGetValue(key, out value);
                }
  24.             //return false;
            }

  25.   public void Add(TKey key ,TValue value)
      {
                if (bForeachCount == 0)
                {
                    _List.Add(key, value);
                }
                else
                {
                    _AddList.Add(key,value);
                }
  26.   }

  27.         public void Remove(TKey key)
            {
                if (bForeachCount == 0)
                {
                    _List.Remove(key);
                }
                else
                {
                    if (_AddList.ContainsKey(key))
                    {
                        _AddList.Remove(key);
                    }
                    else
                    {
                        if (!_List.ContainsKey(key) || _RemoveList.Contains(key))
                        {
                            throw new Exception("dosen't have key");
                        }
  28.                     _RemoveList.Add(key);
                    }
                   
                }
            }
           
            public void StartForeach()
            {
                bForeachCount++;
            }
  29.         public void EndForeach()
            {
                bForeachCount--;
                if (bForeachCount == 0)
                {
  30.                 // remove 먼저해야함
  31.                 foreach (TKey item in _RemoveList)
                    {
                        _List.Remove(item);
                    }
  32.                 _RemoveList.Clear();
  33.                 foreach (KeyValuePair<TKey, TValue> item in _AddList)
                    {
                        _List.Add(item.Key, item.Value);
                    }
                    _AddList.Clear();
                }
            }

  34.   public uint bForeachCount = 0;
  35.         public Dictionary<TKey, TValue>.Enumerator BaseGetEnumerator()
      {
                return _List.GetEnumerator();
      }
  36.   public IEnumerator GetEnumerator()
      {
       return new SafeEnumerator(this);
      }

  37.         class SafeEnumerator : IEnumerator, IDisposable
            {
                SafeCollection<TKey, TValue> _list;
                Dictionary<TKey, TValue>.Enumerator enumerator;
  38.             public object Current { get { return enumerator.Current; } }
                public bool MoveNext() {
  39.                 while (enumerator.MoveNext())
                    {
                        if (_list._RemoveList.Contains(enumerator.Current.Key))
                            continue;
                        return true;
                    }
  40.                 return false;
               
                }
                public void Reset() {
                    //enumerator...Reset();
                }
  41.             public SafeEnumerator(SafeCollection<TKey, TValue> list)
                {
                    _list = list;
                    enumerator = _list.BaseGetEnumerator();
  42.                 _list.StartForeach();
  43.             }
  44.             public void Dispose()
                {
                    _list.EndForeach();
                }
            }

  45.  }
    }

 

test code

 

  1.  sdsd
  2. using System;
    using System.Collections.Generic;
    using System.Text;
  3. namespace Foreach_safe_list
    {
  4.     class buff
        {
            public bool _flag;
            public buff(bool flag)
            {
                _flag = flag;
            }
          
            public void update(){}
          
           
        }
  5.  class Program
     {
  6.  
  7.   static void Main(string[] args)
      {
                SafeCollection<int, buff> a = new SafeCollection<int, buff>();
  8.             a.Add(1,new buff(true));
                a.Add(2,new buff(true));
                a.Add(3,new buff(false));
                a.Add(4,new buff(true));

  9.             foreach (KeyValuePair<int, buff> aaa in a)
       {
                    if( a.ContainsKey(2))
                        a.Remove(2);
  10.                 foreach (KeyValuePair<int, buff> bbb in a)
                    {
                        bbb.Value.update();
                        if (bbb.Value._flag == false)
                            a.Remove(bbb.Key);
                    }
                }
  11.             foreach (KeyValuePair<int, buff> aaa in a)
                {
                    if (a.ContainsKey(2))
                        a.Remove(2);
  12.                 foreach (KeyValuePair<int, buff> bbb in a)
                    {
                        if (!a.ContainsKey(2))
                            a.Add(2, new buff(true));
  13.                 }
  14.             }
  15.             foreach (KeyValuePair<int, buff> aaa in a)
                {
                    Console.WriteLine("{0}", aaa.ToString());
                }
  16.  
  17.   }
     }
    }
  18.  

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.

Comment +1

2.퀘스트

스터디/C++,CLI,C#2009. 9. 14. 20:11

 

그렇다면 이것으로 간단한 퀘스트를 짜보고 간단한 핵심 코드 리뷰를 해보자

Demo2

일반적으로 기획자가 상상하는 단순한 퀘스트를 상상해보자.

1.유저가 npc 를 클릭한다.

2.유저에게 A 를 만나달라고 대화박스를 보인다

3.승낙을 하면 아이템을 준다.

4.A를 클릭하면 고맙다고 한다.

아주일반적인 퀘스트 내용이다.

 

이것을 정말 저런순서대로 코딩을 할수없을까?

 

밑에 코드를 보자

 

quest1 버튼을 누르면 밑에 코드가 돌아간다.

 

우선 퀘스트 코드를 보자

 [소스1]


  1.         public IEnumerator GetEnumerator()
            {

    // 이미 퀘스트를 받았나?

                if (_Owner._QuestInfo.Contains(1))
                {

  2.        

            yield return new NCondition.WaitMessage("여기서 뭐하나", 2);

                    yield break;
                }

  3.            // 부탁을 한다.

                NCondition.WaitMessage msg = new NCondition.WaitMessage("반갑군. 내부탁을 들어줄수있나?", 0);

                yield return msg;

  4.            
  5.             if (msg.Ret() == "OK")
                {

                // ok 이면 퀘스트를 준다

                    _Owner._QuestInfo.Add(1);

                    yield return new NCondition.WaitMessage("고맙군 어서 친구를 찾아주게 ", 2);
                }
                else
                {

  6.                //

        yield return new NCondition.WaitMessage("실망일세 꺼지라우", 2);

                    yield break;
                }

  7.             // A를 클릭하면

                yield return new NCondition.WaitClickEvent(1);

  8.          
  9.             // 보상을 해주던지 다른이벤트를 하던지 하여간 여기서 끝냄

                yield return new NCondition.WaitMessage("반갑군 자네가 그친구인가? 너무늦었네... ", 5);


                yield break;
            }

     

     


 

한마디로 yield 로 표현된 코드는 우리가 일일히 스테이트관리를 해야하는작업을 코드가 알아서 만들어준다고 보면된다.

우리는 귀찮은 스테이트 관리와 데이타 관리를 컴파일러에게 넘겨주고 우리가 필요한 컨텐츠 코드작성만 하면되는것이다.

 [소스2]

  1.  
            public void Update()
            {
  2.             // 등록된 enumerable 오브젝트를 가지고 있다.
                // for 문중 ProcessList 에 있는 아이템을 지울수있는 구조를 위에 뒤에서 앞으로 for 문을 돈다.(성능은 좋지않다)
               
                for (int index = ProcessList.Count - 1; index >= 0; index--)
                {
                    JobInfo pProcess = ProcessList[index];
  3.                 // 현재 스크립트용 함수에서 yield return new icondition 류가 있는지 본다.
                    if (pProcess.m_Condition != null)
                    {
                        // yield return new icondition 이 있으면 완료가 될때까지 스킵한다.
                        if (pProcess.m_Condition.IsComplete() == false)
                        {// 선행작업이 완료되지 않았다.
                            continue;
                        }
                    }
  4.                 // yield 나 yield return 이 올때까지 프로세스가 진행된다.
                    if (pProcess.m_ProcessEnum.MoveNext() == true)
                    {
                        // 유저가 요정한 yield return new icondition 을 저장한다.
  5.                     pProcess.m_Condition = (ICondition)pProcess.m_ProcessEnum.Current;
                        continue;
                    }
                    else
                    {
                        // enumerable 문을 다 완료하였다면 지운다.
                        ProcessList.Remove(pProcess);
                    }
                }
  6.         }

위[소스2] 코드는 [소스1] 의 코드를 어떻게 제어할수있는지 보여주는 코드이다.

이샘풀소스에 위코드 두가지를 이해한다면 핵심적인 내용은  다이해한거라 볼수있다.


다음에는 이 yield 프로그래밍을 가지고 분산프로그램을 쉡게 구현할수있는 방법을 소개해 보겠다.

이 글은 스프링노트에서 작성되었습니다.

Comment +1

YIELD 키워드(lua coroutine)

이글은 c# 을 스크립트나 병렬처리를 하기위한 기초지식을 위한 글이다..

 c# 을쓰면서 yield 키워드를 쓰는일이 거의 없을수도 있다. 그것은 필요가 없는것이 아니라 그용도와 사용방식을 잘 모르기때문인것 같다.

특히나 이 yield  키워드는 c++ 에 없는 키워드이기에 c++ 프로그래머 들에게는 너무 생소하다.

(c++ 에서  Fiber 라는 것이 있다고 한다.나는 써보지를 않아서....)

 

나또한 이 개념을 알게 된 계기도 서버에서 스크립트로 lua 에서 coroutine 개념을 처음 써보고 후에 c# 에서 이 개념을 써보고 싶어서 자료를 찾던중 yield  라는 키워드로 제공되는것을 알았다.

우선

 

http://asyncsample.googlecode.com/files/AsyncSample.zip

 

에서 소스를 다운받는다.

다음 Enumerable 솔루션 파일을 열고

(ms visual c# 2008 express  http://www.microsoft.com/express/download/ )

 
Demo0 프로젝트를 본다.


우선 이 yield 키워드가 어떠한 일을 하는지 보고 이것을 가지고 어떠한 곳에서 사용할수있는지 보자.

우선 핵심적인 내용은 TestCode1() 함수안에 있는 코드의 진행을 IEnumerator.MoveNext() 라는 함수로 제어를 할수있다는것이다.


루아를 써보신분은 쉽게 접근을 할수있겠지만 코루틴을 처음 보시는분은 아직도 감이 오지않을것이다.

c++ 프로그래머 이라면 과연 저것이 내부적으로 어떻게 움직이는지 궁금할것이다.

 

http://www.lutzroeder.com/dotnet/

 

여기 사이트에 들어가서 reflector/ 프로그램을 다운받고 위에 샘풀코드 실행파일을 역어셈해보자

역어셈코드를 보면 코드가 어떻게 움직이는지 바로 느낄수있을거다.

 

원래 코드이다

 

  1.  
            public static IEnumerable TestCode1()
            {
  2.             int x = 3;
  3.             yield return x;
                x++;
                yield return x;
                x++;
                yield return x;
                x++;
                yield return x;
                x++;
  4.             yield break;
  5.         }

 

 .net Reflector 를 사용하여 위코드가 어떻게 변환되였는지 보자

 

  1.  

    private bool MoveNext() 
    {
  2. switch (this.<>1__state)
    {
    case 0:
    this.<>1__state = -1;
    this.<x>5__1 = 3;
    this.<>2__current = this.<x>5__1;
    this.<>1__state = 1;
    return true;
    case 1:
    this.<>1__state = -1;
    this.<x>5__1++;
    this.<>2__current = this.<x>5__1;
    this.<>1__state = 2;
    return true;
    case 2:
    this.<>1__state = -1;
    this.<x>5__1++;
    this.<>2__current = this.<x>5__1;
    this.<>1__state = 3;
    return true;
    case 3:
    this.<>1__state = -1;
    this.<x>5__1++;
    this.<>2__current = this.<x>5__1;
    this.<>1__state = 4;
    return true;
    case 4:
    this.<>1__state = -1;
    this.<x>5__1++;
    break;
    }
    return false;
    }

위코드가 변화되는것이 흥미롭다면  Demo01 도 한번 컴파일 하고 Reflector 로 보기 바란다.

 

그런데 과연 이것이 어떠한 코드표현에 유용한지 이해가 안간다면

우선  gpg 5권을 10.4 단락을 읽어보기 바란다 거기서 표현하고자 하는 의도와 여기서 말하는것은 다른것이 없다.

 

핵심적인 내용은 순차적인 어떠한 서술내용을 프로그램밍으로 직관적으로 표현할수있다라는것이다.

이것이 앞으로 이해할 핵심적내용이다 이 서술적 프로그래밍은 앞으로 이해할 프로그래밍을 설명하는 핵심적 문구라 볼수있다.

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.

Comment +1

공부한게 아까워서 정리하는차원에 wpf 버전으로 만든다.
http://www.codeproject.com/KB/recipes/Shortest_Path_Problem.aspx 문서보고 만듬.

Comment +1

  • nike 2013.07.11 07:37

    눈을 감아봐 입가에 미소가 떠오르면 네가 사랑하는 그 사람이 널 사랑하고 있는거야.

실버라이트 어풀을 만들고 여기다 올려보자..
wpf 도 테스트

Comment +1

  • ghd 2013.07.14 23:40

    당신은 내가사랑할 만한 사람이 아니예요,사랑하지 않으면 안될 사람이예요.