2007년 8월 19일 일요일

Erlang 공부 - 넥슨 입사 시험 문제 1 번 풀이

지난 번에 Common Lisp으로 풀어 본 넥슨 입사 시험 문제 1 번에 대해서 이번에는 Erlang으로 다시 한번 시도해봤습니다.

상세한 문제 내용은 이전 글을 참고해주시고, 간단히 요약을 하면 다음과 같습니다.
1부터 5000 사이의 Self Number들의 합을 구하시오.

풀이 내용은 다음과 같습니다.
-module(selfnum).
-export([sum_of_digits/1,
generate/1,
get_self_numbers/2,
get_sum_of_self_numbers/2]).

sum_of_digits(N) ->
Digits = integer_to_list(N),
sum_of_digits1(Digits).

sum_of_digits1(Digits) ->
Nums = lists:map(fun(D) ->
D - $0 end,
Digits),
lists:sum(Nums).

generate(N) when N > 0 ->
N + sum_of_digits(N).

get_self_numbers(M, N) when M =< N ->
Range_Nums = lists:seq(M, N),
Gen_Nums = lists:map(fun generate/1, Range_Nums),
lists:subtract(Range_Nums, Gen_Nums).

get_sum_of_self_numbers(M, N) when M =< N ->
Self_Nums = get_self_numbers(M, N),
lists:sum(Self_Nums).

sum_of_digits 메서드(method)를 다르게 구현해봤습니다.
-module(selfnum).
-export([sum_of_digits/1,
generate/1,
get_self_numbers/2,
get_sum_of_self_numbers/2]).

sum_of_digits(N) ->
Digits = integer_to_list(N),
sum_of_digits(Digits, 0).

%%---------------------------------------
%% Tail-recursion 방식으로 구현
sum_of_digits([D|Rest], Acc) ->
I = D - $0,
sum_of_digits(Rest, Acc + I);
sum_of_digits([], Acc) ->
Acc.
%%---------------------------------------

generate(N) when N > 0 ->
N + sum_of_digits(N).

get_self_numbers(M, N) when M =< N ->
Range_Nums = lists:seq(M, N),
Gen_Nums = lists:map(fun generate/1, Range_Nums),
lists:subtract(Range_Nums, Gen_Nums).

get_sum_of_self_numbers(M, N) when M =< N ->
Self_Nums = get_self_numbers(M, N),
lists:sum(Self_Nums).

compile하고 각 메서드에 대해 실행한 결과는 다음과 같습니다.


[그림 1] 실행 결과

Erlang도 예전부터 관심은 있었는데, 계속 공부를 미루다 최근에 와서야 마음 먹고 집중해보고 있습니다. 오랫동안 C/C++, Java 관련 일만 해와서인지 패러다임이 다른 프로그래밍 언어에 익숙해지는 것이 쉽지 않습니다. 하지만, 재미있습니다. 모르고 있던 새로운 것을 알게 된다는 것은 그 자체만으로도 충분히 기쁨입니다. :)

2007년 8월 16일 목요일

Einstein Puzzle - 논리적 사고 능력이 요구되는 퍼즐 게임

회사에서 일을 하다 보면 '합법적으로' 어쩔 수 없이 시간을 죽여야 하는 경우가 발생하곤 합니다. 개발하고 있는 전체 소스를 새로 빌드한다거나 다른 팀의 patch를 기다린다거나 하는 상황이 바로 그런 경우인데요, 저는 이런 애매한 자투리 시간을 효과적으로 보내기 위해서 간단한 퍼즐 게임을 주로 하는 편입니다.(물론 책을 읽는다거나 공부를 하는 등의 좀더 생산적인 일들을 할 수도 있습니만...) 특히 요즘 두뇌 개발 게임이 하나의 큰 유행이 되고 있기 때문에 퍼즐 게임에 대한 저의 관심이 몇 배는 더 증폭되어 있죠.

주로 하는 퍼즐 게임이 Windows XP에 내장되어 있는 Spider 카드 게임, 가로/세로/서브셀 내에서 1부터 9까지 단 한 번만 나타나도록 배열해야 하는 Sudoku, 주어진 조건에 따라 기호들의 제 위치를 정확하게 찾아야 하는 Einstein Puzzle 등입니다. 이 중 오늘 소개해드릴 것이 바로 Einstein Puzzle입니다.





Einstein Puzzle 역시 머리와 눈을 꽤 아프게 만드는 게임이지만, 중독성 하나만큼은 상당히 강력합니다. 이 게임은 그 이름에서도 알 수 있듯이 유명한 '아인슈타인의 퍼즐'에 착안하여 만든 것으로, 서술 문장 대신 기호와 기호들의 위치에 대한 부분 조건을 주고 기호들의 순서를 맞추도록 요구하는 퍼즐 게임입니다.

기호는 6 가지 종류로 구성되어 있고, 각 종류마다 6 개의 아이템으로 구성됩니다. 즉, 6 x 6 격자 공간에 기호들의 정확한 위치를 결정해주는 것이 목표입니다. 퍼즐을 푸는 규칙은 크게 가로 조건과 세로 조건 두 가지로 나누어지는데, 각각의 규칙에 대해 간단히 정리해보면 다음과 같습니다.

1. 가로 규칙



이것은 '네모'가 '숫자 1'의 왼쪽에 배치되어 있다는 것을 의미합니다. 그러나 '네모'와 '숫자 1' 사이에 다른 기호가 있는지 없는지, 몇 개의 기호가 있는지는 알 수 없습니다.



이것은 '세모'와 '알파벳 D'가 서로 인접해 있음을 의미합니다. 그러나, 이 두 기호의 순서는 알 수 없습니다. 즉, 두 기호 사이에 아무 기호도 오지 않지만 '세모'가 '알파벳 D'의 왼쪽일 수도 있고 오른쪽일 수도 있습니다.



이것은 '주사위 2'와 '알파벳 A', 그리고 '로마숫자 3'이 인접해 있음을 의미합니다. 그러나, 바로 위의 규칙과 마찬가지로 세 기호의 순서는 알 수 없습니다. 즉, '주사위 2' - '알파벳 A' - '로마숫자 3' 순서로 배치되어 있을 수도 있고, '로마숫자 3' - '알파벳 A' - '주사위 2' 순서로 배치되어 있을 수도 있다 말이 됩니다.

2. 세로 규칙



세로 규칙은 단 하나뿐입니다. 예제의 그림은 '연산자 +'와 '알파벳 D'가 같은 열(column)에 배치된다는 뜻입니다.


게임 진행 방법

규칙에 부합하지 않는 기호를 제거할 때마우스 오른쪽 버튼을, 규칙에 부합하는 기호를 바로 선택할 때마우스 왼쪽 버튼을 사용하면 됩니다.


자 이제 도전해봅시다!

Einstein Puzzle은 Windows와 MacOS X 용 바이너리 및 소스가 무료로 제공되며 공식 홈페이지에서 다운로드가 가능합니다. Einstein Puzzle의 공식 홈페이지는 다음과 같습니다.

LINK: http://games.flowix.com/en/index.html


팁 한 가지

게임을 몇 번 해보면 자연스레 알게 되겠지만, 결국 이 퍼즐 게임은 조건에 부합하지 않는 기호들을 제거해나가는 과정의 연속입니다. 그렇기 때문에 게임을 많이 하다 보면 깊이 고민하지 않고도 바로 알 수 있는 규칙의 패턴을 터득하게 됩니다. 그 중에서 가장 빨리 터득할 수 있는 패턴을 알려드립니다.
  • 가로 첫 번째 규칙 그림에서, '네모'는 절대로 6 열에 올 수 없고, '숫자 1'은 절대로 1 열에 올 수 없습니다.
  • 가로 세 번째 규칙 그림에서, '알파벳 A'는 절대로 1 열과 6 열에 올 수 없습니다.
자, 이제 논리적 사고 능력 및 인지 능력이 계발될 수 있다고 굳게 믿으시면서 Einstein Puzzle에 한번 도전해보세요.

덧.
PDA 용으로는 Mobirate Brain Master라는 게임에 포함되어 있는 것을 발견할 수 있었습니다만, 상용 소프트웨어더군요.

덧2.
이 게임은 단 한번의 실수도 용납되지 않습니다. 마우스 버튼 잘못 눌러서 유리 깨지는 듯한 효과음을 들을 때면 가슴이 철렁할 수 있으므로, 임산부나 노약자는 피해주시기 바랍니다. ㅡㅡ