2019년 10월 20일 일요일

신입 게임 프로그래머 면접 질문

 *제가 면접을 봐왔던 회사 기준입니다. 회사마다 중요하게 여기는 부분이 다르기 때문에 회사에 맞추어 면접을 준비하셔야 합니다. 또한, 저는 고졸로 프로그래머 취업을 도전했습니다. 그래서 대학 진학 후 취직하시는 분들과 질문 수준이 다를 수 있습니다.

기술면접


 회사에서 신입 프로그래머에게 기술 면접으로 원하는 것은 면접자가 기본기가 쌓여있는지 확인하는 것이기 때문에 최신 기술이나 복잡한 문제를 내는 경우는 드물다. 그렇기 때문에 메모리 구조나 자료구조, 평소에 자신이 짠 코드들을 왜 이렇게 짰는지 정확하게 알고 가는 것이 중요하다.
 평소에 듣기만 했거나 이해하지 못한 것들은 솔직하게 "이해는 못하였지만 ~라고 알고있습니다."라고 답하는 것이 좋다. 괜히 이상한 대답을 하면 큰 감점을 당할 수 있다.
 제일 중요한 것은 평소에 프로그래밍할 때 기본기에 대해 충분히 생각하고, 최적화를 고민해서 짠다면, 기술면접은 차분하게 보면 통과할 수 있다.

자료구조

 보통 자료구조 문제를 물어볼 때는 자료구조를 얼마나 이해하고 있는지와 어디서 활용했는지를 중요하게 보기 때문에 메모리가 어디서 할당되고 구조는 어떻게 되어있는지 이해하고 가는 것이 중요하다.

1. vector vs list

 vector은 배열 기반의 구조이고, list는 구조체 속에 포인터로 이어주는 구조이다. 또한 vector에는 capacity라고 메모리를 미리 할당 해놓을 수 있어서 바로바로 할당하는 list와 속도 차이가 날 수 있다.
 둘의 구조가 다르기 때문에 사용하는 곳도 다르다. 그래서 면접자들은 vector와 list를 어디서 활용해 보았냐고 질문을 자주 한다.
  emplace_back과 push_back에 대한 차이점을 물어볼 수도 있다. emplace_back은 stl안에서 객체를 직접 생성해 주기 때문에 생성자에 들어가는 변수만 넣어주면 된다. 때문에 복사가 일어나지 않는다. 하지만 push_back은 객체를 생성하고 컨테이너에 넣어주기 때문에 복사가 일어나게 된다.

2. c# dictionary, c++ map

 dictionary는 해쉬테이블 구조이고, map은 레드블랙 이진트리로 되어있어 탐색 속도에서 차이가 날 수 있다. dictionary는 map보다 빠르지만 메모리를 좀 더 차지하고, map은 dictionary보다 조금 더 느리지만 메모리를 덜 차지한다. 

3. 이진탐색

 정렬되어있는 배열에서 (예를들면 1부터 9까지) 어떻게 하면 특정 수를 찾을 수 있을 지 문제를 내주는 경우가 있었다. 
 이진탐색은 중간 데이터와 찾는 데이터를 비교해서 작으면 왼쪽, 크면 오른쪽방향으로 다시 탐색해보는 알고리즘이다. 점점 절반으로 탐색할 데이터가 줄어들기 때문에 기하급수적으로 줄어든다고 볼 수 있다. 시간 복잡도에 대해 물어보는 경우도 많으니 공부해 가면 좋을것이다. 
이진트리의 시간복잡도: O(logN)

수학


 주로 공업수학에 대해 많이 물어본다. sin그래프를 그려보라는 회사도 있었고, 거기서 2sin이나 cos + 1, arctan등 응용에 대해 물어보는 회사도 있었다.



 아직 행렬을 물어보는 회사는 없었지만, 내가 대학을 진학했으면 충분히 질문했을 것이다. 행렬의 곱셈이나 역행렬 정도 알고가면 많은 도움이 될 것이다.



 근의 공식은 중학교 3학년 때 부터 배우는 근에 대한 공식이다. 근의 공식은 알고리즘으로 방정식을 풀 때 굉장히 유용하기 때문에 질문하는 회사들이 많다.



출처 - https://terms.naver.com/entry.nhn?docId=3350163&cid=60210&categoryId=60210

 수학을 잘한다는 것은 평소에 논리적이고 이과적인 생각을 많이 한다는 뜻이므로 프로그래머에겐 굉장히 중요하다. 그래서 수학을 물어보는 회사들이 상당히 많다.
(실제로 회사가서 미적분을 다시 공부하는 경우도 많다.)

포트폴리오

 회사는 신입 프로그래머를 판단할 방법이 많이 없어 서류에 있는 포트폴리오를 주로 보기도 한다. 면접자가 제작한 기능들에 대해서 물어보고 제작한 이유와 생각들을 물어본다. 그래서 면접에 임하기 전에 자신이 제작한 포트폴리오를 보고 코드나 제작한 이유들을 생각해 보면 면접관과 재미있는 대화들을 많이 나눌 수 있을 것이다.


엔진


 최근 유니티 엔진과 언리얼 엔진을 안쓰는 회사는 거의 없다. 그러므로 유니티나 언리얼엔진에 대해 간단하게 몇가지 질문을 할 수 있다.

1. 오브젝트 풀 - 유니티

 c#에서는 가비지 컬렉터로 메모리를 해제하기 때문에 오브젝트를 한꺼번에 생성해놓고 돌려쓰는 것이 효율적이다. 유니티 엔진에서는 매우 기본적인 방식이기 때문에 질문하는 경우가 많다. (오브젝트 풀에 관해서는 블로그에 따로 쓸 예정이다.)

2. 컴포넌트 패턴

 유니티, 언리얼에서는 컴포넌트 패턴을 통해 기능들을 붙일 수 있다. 컴포넌트 패턴은 기능을 추가하기 쉽고, 상속 할 때 커플링 문제가 해결되기 때문에 엔진에서 자주쓰는 패턴이다. 한번 제작하거나 이해하고 가면 플러스 점수가 될 수 있을 것이다.

3. C++ vs C# - 유니티

 유니티에서는 C#스크립트를 사용하고 있기 때문에 C++과는 다른점이 많다. 대표적인 이유로 가비지 컬렉터가 있다. C++에서는 가비지 컬렉터가 없고 포인터가 있기 때문에 할당을 해주면 반드시 해제를 해줘야되고, C#에서는 가비지 컬렉터가 알아서 해제를 해주기 때문에 해제를 안해줘도 된다. 
 C#에서는 포인터가 없고 class로 생성하게 된다면 Reference(참조)형 타입이 된다는 특징이 있다. 그래서 참조 접근을 많이하며 처음에 구조체를 만들 때 (struct인지 class인지)신중해야 한다.

알고리즘

 알고리즘은 어떤 문제가 나오는지는 알 수 없지만, 문자열이나 이진탐색, 스택, 큐 등이 많이 나온다.

프로그래머스 - https://programmers.co.kr/

여기서 프로그래머 테스트를 보는 경우도 많아 문제를 많이 풀어보는 것이 좋다.

2018년 2월 26일 월요일

랜덤맵 생성 타일 그리기

 저번에 만들어본 랜덤맵으로 타일을 그려 보았다. 저번의 데이터를 불러와서 랜더링만 해주면 되는 문제기 때문에 어렵지 않을거라 생각했었는데 살짝 기본기에서 에러가 난거같다.



 내 타일맵은 arr[60][60] 라서 타일이 3600개가 깔린다... 처음에는 60 * 60도 적은 숫자인거 같아서 100 * 100을 해보았더니 프레임이 20이 나오는 기적을 볼 수 있었다. 렌더하는 함수에서 최적화가 안되어있는 문제도 있는거같다.
 타일 그리는 방식은 별거 없었다. 테두리 4방향을 구해서 전부 다 다르게 그리고, 모서리도 전부 다르게 숫자를 넣어서 만약 1이면 모서리, 2이면 테두리 이런식으로 예외처리를 해주게 되었다. 하드코딩이라서 다음에 코드보기 힘들다는 단점과, 이렇게 하나하나씩 처리를 해주다보면 랜덤맵 생성이다보니 내가 알 수 없는 버그가 날 수 있다는 단점이 있다. 다음에 수정할 때 알고리즘을 하나 생각해서 짜는게 좋을 듯 싶다.

다음에는 블로그에 direct x9 프레임워크도 올려봐야겠다. 내 프레임워크는 아직 미숙한 부분이 많아서 피드백을 받고싶다.

2018년 2월 20일 화요일

bsp 트리구조를 이용한 랜덤맵 생성

 이번에 directx 9을 이용하여 멀티플레이 하는 게임을 만들어 보자는 생각이 들어서 평소에 만들어보고 싶었던 랜덤맵 생성에 대해서 알고리즘을 짜보게 되었다. 맵을 서버에서 랜덤으로 생성하여 이차원 배열만 클라이언트에 넘겨주면 데이터 절약과 동시에 연산도 빠를거 같아서 이차원 배열을 이용하여 만들었다. 애초에 타일맵이라 이것말고는 생각이 나지 않는다.
 bsp 이진공간 분할법을 이용한 랜덤맵 생성이다.
알고리즘에 대하여 간단하게 설명하자면

1. 간단한 이진트리 구조를 만든다.
class TreeNode
{
     private:
     TreeNode *leftTree;
     TreeNode *rightTree;
     TreeNode *parentTree;
     public:
     TreeNode *GetLeftTree() { return leftTree; }
     TreeNode *GetRightTree() { return rightTree; }
     TreeNode *ParentTree() { return parentTree; }
}
대충 기본 구조를 이렇게 짰다. 객체들을 포인터로 해놓은 이유는 언제든지 메모리 추가가 가능하고, 자식구조에 대해서 접근이 가능하기 위해서이다. 그리고 트리안에 x, y, width, height 값을 저장하게 만든다.












일단 트리 하나를 만들어 좌표값을 넣어주면 이렇게 큰 네모가 머릿속에 그려질 것이다.

2. 둘로 쪼갠다.












왼쪽이 LeftTree, 오른쪽이 RightTree이다. 이전 부모의 좌표값을 토대로 랜덤하게 자른다.
랜덤값이 너무 크면 안되니까 30%에서 70%사이에 랜덤값을 주어 잘랐다.

3. 반복한다.












2번을 일정값 이하로 떨어지면 함수를 return 하게 하여 공간이 너무 작게 나오지 않도록 해준다.

4. 트리 안에 방을 만든다.












트리 안에 넣어둔 좌표값을 이용해 범위 안에 방을 만든다. 트리 구조로 잘라서 둘이 겹칠 일은 없다.

5. 마지막 자손 노드의 방부터 연결을 시켜준다.












나는 가로로 잘랐으면 가로로 연결하고 세로로 잘랐으면 세로로 연결하는 식으로 알고리즘을 짰다. 살짝 코드보기가 더럽고 안좋은 알고리즘이라 좀 더 좋은 알고리즘이 필요한거 같다.

6. 5번을 반복하며 부모 노드까지 연결시켜 준다.




























처음이다보니 알고리즘 짜는데 좀 오래걸렸던거 같다... 이제 클라에서 이미지 넣어봐야 겠다. github 주소-> https://github.com/LeeYonggi/RandomMap_bspTree