앱스토어 골드러시

비개발자가 쓴 앱개발 스토리입니다. (무서운 카메라, It Works등을 런칭) 세줄 요약해보면

1. 앱스토어는 기회의 땅이다.
2. 개발자가 아니라도 아이디어만 있으면 할 수 있다.
3.  ….

세 줄로 요약하려고 했는데 두 줄 쓰고나니 막혔습니다. 책을 다 읽고나서 내용이 없다거나 나쁜 책이라는 생각은 하지 않았지만 며칠 지나고 나서 돌아보니 두 줄 이상의 요약이 되질 않네요-_- 어쩌면 책 내용이 일관적이었다고 생각할 수도 있겠습니다.

재미있는 것은 저자가 의도한 독자의 타겟층이 프로그래머가 아닌 일반인이라는 점입니다. 이런 책을 프로그래머가 읽다보니 이런 것들이 눈에 띕니다. 앱을 의도대로 개발하려면 기획은 가능한 세세하게 하여 ‘코더‘는 ‘코딩‘에만 집중하게 하라. 중간 중간 작업 진행이 되고 있는지 확인(압박)하라. 마일스톤을 이야기 한거겠죠? 이게 참 틀린 말은 아닙니다만 프로그래머를 바라보는 고용주의 시선은 저런 것이구나 싶어서 좀 씁쓸하긴 했습니다. 코더라는 어휘를 대놓고 사용하는 것이 프로그래머 입장에서 유쾌한 일은 아닌데 저자가 그런 부분까지 알진 못하겠죠. 뭐 암튼 의도가 나쁜 것은 아니니 넘어가고요.

스마트폰과 인류의 삶에 대한 장황한 글을 쓰다 지워버렸는데요, 책 리뷰쓰면서 너무 오바할 필요는 없는 것 같습니다.-_- 결론입니다. 이 책은 앱 개발에 관심있으신 분들이 동기부여를 위해서 읽으신다면 좋을 것 같습니다. 하지만 프로그래밍을 모르시는 분들이 아이디어 하나만으로 개발자와 계약하고 프로젝트를 관리하는건 너무나 귀찮고 어려운 일이 아닐까요? (내가 개발자라서 이렇게 생각하는건가..) 오히려 개발자들이 읽고 ‘아 내가 하면 더 쉽겠구나’라는 자신감을 심어주는 책이라고 생각합니다.

Generating random numbers in game.


출처: http://xkcd.com/221/

포스팅을 시작하기 전에 미려 알려드리고자 할 것이 있습니다. 이 글은 제가 랜덤(random) 에 관해서 오랜 기간 연구하고서 쓰는 것이 아닙니다. 단지 필요에 의해 단기간(네..반나절 정도) 리서치 하고 실무에 적용했던 내용을 나중에 또 삽질하기 싫어서 기록해 두는 것입니다. 그러므로 난수에 대해 조회가 깊은 분들은 이 글을 보고 피식 웃어 넘기시면 됩니다. 다들 뉴비일때가 있는거잖아요. (MT와 WELL알고리즘으로 귀결이 되는 글입니다.)

발단은 이렇습니다. 제목에 있다시피(있어 보이려고 영어로 썼습니다. 난 도시남자니까) 게임에서는 난수를 발생시켜야 할 경우가 많습니다. 아이템이 떨어질 확률, 크리티컬 공격이 나올 확률 등등. 그런데 이 난수들이 예측 가능하거나 난수답지 않으면 문제가 생기죠. 어떤 몬스터가 정확히 11번째 공격에서 궁극 스킬을 사용한다라고 유저들이 예측(학습)해 버리면 그 공격을 모두 피할 것입니다. 10번째에서 살짝 빠져주면 되니까요. 난수를 넣는다고 넣었는데 예측이 된다거나 특정 범위의 숫자가 잘 나오지 않는다거나 하면 문제가 되죠. 전 맵에 걸쳐 고르게 사과가 떨어져야 하는데 특정 동산에서만 사과가 잘 떨어진다거나 하는 기획자의 의도와 다른 상황이 만들어져서는 안된다는 것입니다. 도입이 되게 길었네요.

보통의 c/c++ 프로그래머들이 사용하는 난수 발생 함수는 rand() 입니다.

srand( (unsigned int)time(NULL) ); // 이렇게 시간 값으로 시드 주고
int nRandNumber = rand() % 100; // 0~99까지 난수 발생

저도 이 함수를 신봉했습니다. 선배들의 입에서, 책에서, 학교에서 이렇게 하라고 했으니까요. time값을 시드로 넘겨 주고 나타나는 현란한 난수들에 압도당했던 학부생의 감동이 10년째 가시질 않아서 이것만 죽어라 사용합니다. 헌데.

The most common distribution used in games is a uniform distribution, where equally
likely random integers are needed in a range [a,b] . A common mistake is to use C code
like (rand()%(b-a+1)) + a. The mistake is that not all values are equally likely to
occur due to modulus wrapping around. This only works if  b-a+1  divides
RAND_MAX+1. For example, if RAND_MAX is 32767, then trying to generate numbers in
the range [0,32766] using this method causes 0 to be twice as likely as any other value.

출처: http://www.lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf

이런 글을 발견하게 됩니다. 특정 상황에서 니가 예상한거보다 0이 두배는 많이 나올거다.. 라고 하는군요. 사실 현재 프로젝트에서 발생하는 난수에 문제가 있다는 것을 감지하고 리서치 중에 발견한 것입니다. 시물레이터를 만들어 돌려 보아도 어느 정도 패턴이 보이는 난수가 발생한다는 것을 확인했습니다. 그럼 어떡해야죠? 고쳐야죠. 우린 프로그래머니까.

일단 프로그래밍계의 지식in 사이트인 stackoverflow.com에 이런 글이 있습니다.

http://stackoverflow.com/questions/1046714/what-is-a-good-random-number-generator-for-a-game

오호. 이거면 되겠군요. 여러 답변이 있습니다만 눈에 띄는 것이 Mersenne TwisterWELL512 입니다. shuffle bag이니 하는 방법들도 기발하지만 일단 꼼수이므로 패스하고요.

일단 Mesenn Twister(이하 MT)를 봅시다. 요녀석이 특징이 매우 긴 period를 갖는다는 것입니다. 우리가 보통 사용하는 rand()의 경우 2^32의 period를 갖게 됩니다. 하지만 MT의 경우 2^19937-1의 period입니다. 음청크죠. 또 무슨 테스트를 패스했네. 빠르네. 어쩌네 하는데 전 뉴비라서 이해하지 못하구요. 결정적으로 와닿을만한 것은 바로. R, MATLAB, Ruby, Python등의 언어에서 기본 난수 알고리즘으로 채택되었다는 것입니다.

For many applications the Mersenne twister is quickly becoming the pseudorandom number generator of choice; for example, it is the default in R, Maple, MATLAB, Gretl and the two popular scripting languages Python[3] and Ruby[4]. Since the library is portable, freely available, and quickly generates high quality pseudorandom numbers, it is rarely a bad choice.

어때요 두근두근 하죠. 실제로 C++에서도 BOOST LIBRARY를 이용해 MT를 사용할 수 있습니다. 저도 그렇게 하면 간단했죠. 헌데 왜 저는 WELL512로 눈을 돌렸을까요. 바로. BOOST를 설치하기 귀찮았기 때문입니다….아니 난 괜찮은데 나때문에 다른 사람들 컴퓨터에 모두 boost가 깔려야 하는 상황을 팀원들이 달가워 하지 않을 것이기에…(네 전 A형 프로그래머니까요)

WELL512는 MT의 디자이너가 10년 후에 고안한 난수 발생 알고리즘입니다. 그의 주장에 따르면 MT보다 40% 빠르고 코드도 더 간단합니다. 보실까요?

/* initialize state to random bits */
static unsigned long state[16];
/* init should also reset this to 0 */
static unsigned int index = 0;
/* return 32 bit random number */
unsigned long WELLRNG512(void)
{
unsigned long a, b, c, d;
a = state[index];
c = state[(index+13)&15];
b = a^c^(a<<16)^(c<<15);    c = state[(index+9)&15];    c ^= (c>>11);
a = state[index] = b^c;
d = a^((a<<5)&0xDA442D20UL);
index = (index + 15)&15;
a = state[index];
state[index] = a^b^d^(a<<2)^(b<<18)^(c<<28);
return state[index];
}

이게 다입니다. period는 2^512 입니다. 그렇다 해도 일반 PC로 저걸 세는데 10^100(영이 백개!!)년이 걸린다고 하는군요. (googol years 라고 부릅니다.) state만 적절히 초기화 해주고 WELLRNG512함수를 호출하면 32비트 정수(난수)가 리턴됩니다.

간단한 시물레이터로 두 난수 발생기를 시뮬레이팅 해 보았을 때의 차이를 보여드리겠습니다.


C/C++의 rand함수


WELL512 알고리즘

차이가 보이시나요? 일반적인 용도로 rand함수 정도면 충분한 randomness를 보장한다고 생각하지만 게임과 같은 상황이라면 MT나 WELL같은 알고리즘을 고려해 보시는 것이 좋을 것 같습니다. 제가 위에 보여드린 코드를 그대로 가져다 쓰셔도 상관 없겠지만(public domain 입니다. 그래도 땡큐레터 한장 정도는 보내달라고 하는군요) boost library를 사용하시는 것이 더 모양새 나는 코드가 되지 않을까 생각합니다.

참고 웹페이지
http://en.wikipedia.org/wiki/Pseudorandom_number_generator
http://en.wikipedia.org/wiki/Linear_congruential_generator
http://en.wikipedia.org/wiki/Mersenne_Twister
http://stackoverflow.com/questions/1046714/what-is-a-good-random-number-generator-for-a-game
http://www.iro.umontreal.ca/~panneton/WELLRNG.html
http://kaioa.com/node/53

컨설턴트

사실 이 책 산지는 꽤 되었다. 세계문학상 수상작은 거의 사서 읽기 때문에 아무 의심 없이 구매하긴 했다. 하지만 요즘 바쁘기도 바빴고 제목이 그리 와닿지 않아서 읽기를 미뤄두고 있었다. 컨설턴트라니. 표지엔 컴퓨터 얼굴의 사람이 걸어다니고. 지루한 회사 이야기가 나올 것만 같았으니까.

결론적으로 회사 이야기가 나온다. 이게 우리들이 알고 있는 일반적인 회사가 아니어서 그렇지 회사이야기이 것은 맞다. 추리 소설에 재능이 있는 주인공이 바로 이 회사에 스카웃 되어 완전 범죄로 귀결되는 살인 시나리오를 쓴다. 그리고 그가 만들어낸 시나리오대로 사람이 죽어나간다. 그런 킬러의 이야기. 오랜만에 책을 펴고 그 자리에서 다 읽어버린 재미있는 책. 막판에 좀 철학적으로 빠지면서 흥미가 떨어지지만, 그래도 재미있었다는덴 이견이 없다.

소설과 현실의 경계를 넘나들며 우리가 잘 아는 ‘에어장’ 사건도 하나의 에피소드로 등장한다. 더 이야기 하면 책 내용 다 나올 것 같아서 패스. 읽어보길 추천한다. 재미있고 또 이런 저런 생각을 많이 하게 된다.

퇴사를 앞두고

2년 전입니다. 대학생이었던 어느 여름날. 시험공부가 무척이나 하기 싫었던 기말고사 기간으로 기억합니다.

게임업계에 대한 막연한 동경이 있던 저는 인터넷에서 한 구인 광고를 발견합니다. 드래곤볼 온라인 서버 프로그래머 모집.

와. 이거다. 드래곤볼이다. 여름 방학에 아르바이트나 인턴을 해야겠다는 목표가 있긴 했지만 본격적으로 일을 해야겠다는 계획은 없었습니다. 하지만 드래곤볼이라는 거부할 수 없는 매력은 절 청담동으로 이끌었지요. 그리고 처음으로 경험해본 입사 면접.

통역하시는 분이 있는데도 굳이 유창하지도 않은 일본어로 나를 어필하려 노력했던 그날을 생각하니 아직도 손이 오글거리네요. 그렇게 하이 간바리마스를 외쳐대던 저는 졸업도 하지 않은채 게임업계에 입문하게 됩니다. 믿고 뽑아주신 분들에게 아직도 감사할 따름입니다.

그리고 2년이 흘렀죠. 많은 일을 겪었습니다. 클로즈베타와 오픈베타를 경험했고 뒤이은 상용화를 생각하면 아직도 가슴이 뜁니다. 좋은 일만 있었던 것은 아닙니다. 흔히들 말하는 섭따(서버 다운)와 각종 버그, 점검 등등 이 업계에서 겪을 수 있는 거의 모든 이벤트를 경험해 보았습니다.

정이 많이 들었지요. 이 회사에. 그리고 이 프로젝트에. 크게 성공한 게임은 아니지만 그래도 내가 사랑하는 타이틀이 온라인 게임화 되는 중심에 서있었다는데 만족합니다. 내가만든 대기표에 수천명씩 줄서는 그 쾌감이 상상이 되나요?

돌이켜 생각해보니 감회가 새롭네요. 아무튼 저는 이제 퇴사를 눈앞에 두고 있습니다. 제가 작성한 코드만 해도 수천 수만 라인은 될텐데, 이 프로젝트에서 벗어난다니. 글쎄요. 시원 섭섭이란 흔한 단어로 이 감정이 다 표현되는 것 같진 않습니다.

얻은 것도 많습니다. 온라인 게임에 대해서 많이 배웠고, 개발에 대한 자신감도 붙었습니다. 어떤 프로젝트에 어떤 언어로 투입된다고 해도 이젠 겁이 나질 않아요. 음.. 자신감이라기보단 거만한 프로그래머가 된 것 같기도 하네요. 하지만 null pointer 한방에 수만명씩 떨어져 나가는 것을 목격해본 이후론 이게 쉬운 일은 아니란 생각도 많이 했습니다.

바쁘게 살았습니다. 회사를 다니며 꾸준히 번역을 했고 올해 들어선 낮에는 학교 밤에는 회사를 병행하는 강행군을 했습니다. 끝이 안보이던 이 행보에 드디어 마침표를 찍게 되네요. 올해 저는 졸업을 하고 같은 시기에 퇴사를 합니다. 퇴사한다 소문을 내고 다녔더니 뒤이어 이 질문을 많이 받습니다. 앞으로 뭘 할거냐. 어느 회사로 가는 것이냐.

아직 정해진 것이 아무 것도 없습니다. 그저 쉬고싶은 마음만 간절합니다. 이제 저는 갑니다. 인사하고 서류에 싸인하는 그 날 바로 훌쩍 여행이라도 다녀오고 싶네요. 물론 현실은 절 놓아주지 않겠지만요

소속이 없어진다는 불안감이 왜 없겠냐만은 경험해 보지 못한 또 다른 무언가가 날 기다린다는 생각에 가슴이 두근거리기도 합니다. 내가 아닌 남도 궁금해 하는데 하물며 저 자신은 어떻겠나요.