구글 코드잼 2015가 끝났다. R2 치고 나서 결과를 안 올렸었는데 R3랑 같이 최종 결산하면서 한꺼번에 올리기로 했다.

R2

A

A는 격자 밖으로 나가는 발판들을 전부 센 뒤, 조건대로 처리할 수 없는 발판이 있는지를 확인하는 단순한 탐색 문제였다.

16:33 AC

D

A를 풀고 나서, B와 C를 읽기는 했다. 둘 다 조금씩 끄적여 봤지만 전혀 풀이가 떠오르지 않았고, D는 풀이는 잘 떠오르지 않았지만 문제가 내 취향이고 배점도 높아서 D를 풀기로 했다. D는 가로 시작과 끝이 이어지는 원통 형태의 평면에서 각 칸에 숫자를 써 상하좌우 인접한 칸에 그 숫자가 딱 그 개수만큼 있도록 만들 수 있는 가짓수를 세는 문제였다.(2를 썼다면 상하좌우에 2가 두 개 있어야 함)

바로 감이 오는 건 없었지만 작은 숫자에 대해 백트래킹을 구해 규칙성을 관찰했고, 포함배제를 이용해 패턴을 겹치지 않게 잘 세어주면 된다. 빠트린 패턴이 있어서 두 번 WA를 받았다.

2:26:27 AC

결산

B는 각 수도꼭지의 온도와 단위 시간당 물의 양이 주어질 때, 원하는 만큼의 물을 원하는 온도로 맞추기 위해 필요한 최소 시간을 묻는 문제였다. 2차원 벡터를 합해 원하는 벡터를 만드는 형태의 문제로 변환해서 풀 수 있다고 한다. C는 두 개의 언어 사이에 공통되도록 사용되는 단어를 세는 문제였는데 Flow 문제라고 한다. 둘 다 풀이를 듣고 나니 내가 잘 못 푸는 유형이 맞았다. 대회 끝나고 나서 연습하긴 할텐데 대회 때 넘긴 건 잘한 선택이었다고 생각한다.

304위로 마무리했고 티셔츠와 함께 R3 진출권을 얻었다.

R3

B

A 풀이를 깊게 생각하지 않고 이렇게 짜면 되려나 싶어서 짰는데, 완전히 잘못된 방향의 접근이었다는 것을 거의 다 짰을 때쯤 되서 깨달았다. 일단은 지금 고치기에는 너무 멀리 왔다고 판단되어 A를 넘기고 B부터 풀었다. B는 문제 읽고 나서 바로 그리디 알고리즘을 떠올렸고, 코드도 금방 짤 수 있었다.

두 번 WA를 받았는데 한 번은 음수 modular가 음수가 나온다는 사실 때문이었고 다른 한 번은 offset 계산을 하지 않아서였다. 두 문제를 고치고 나서 맞을 수 있었다.

1:23:42 AC

A

B를 풀고 나서 다시 A를 잡았다. 새로 떠올린 A 풀이는 정확히 증명하진 않았지만 Sliding Window 기법으로 O(N)이라고 생각한 풀이를 짰다. 초기화 부분에서 빠트린 게 있어서 찾느라 한참 걸렸고, 대회 마감 1분 30초 정도를 앞두고 틀린 부분을 찾을 수 있었다. 데이터를 넣고 돌리는데 이상하게 오래 걸리는 느낌이 들었지만 다행히 시간 내에 답이 다 나왔다. 대회 끝나고 나서 다시 생각해보니 최악의 경우 O(N^2)이 걸리는 풀이였다. 문제에서 데이터를 직접 입력하지 않고 선형합동생성기로 생성하기 때문에 문제 없이 돌아갔던 것 같다.

2:29:40 AC

결산

끝나기 직전에 겨우 A, B를 풀었기 때문에 등수가 높지 않을 것으로 예상했는데 163위라는 생각보다 높은 등수로 마무리했다. C, E는 읽어보지 못했고 D는 읽어봤는데 시간을 주면 풀 수 있을 것 같은 문제라고 느꼈다. A를 풀고 나서 대회가 바로 종료되었기 때문에 건드려 볼 시간이 없었다. 예상대로 onsite는 진출하지 못했지만(전세계에서 25명 뽑는다) 생각보다 좋은 결과를 얻었다고 생각한다.

종합 후기

이번 대회에서 가장 보람찼던 건 ‘말리지 않았다’는 점이다. 고등학교 때부터 대회만 있었다 하면 자꾸 사소한 실수를 못 찾고 계속 붙잡고 있다가 망하는 경우가 많았다. 특히 대회가 중요하면 중요할수록 심리적 압박감 때문에 이런 현상이 심해졌다. KOI도 세 번 은상만 받고 끝났고, 계절학교 때는 그렇게 잘 하다가도 선발고사만 보면 매 번 기대 이하의 성적을 거두곤 했다. 하지만 이번 코드잼에서는 실수가 있더라도 긴장하지 않고 차근차근 찾아내 결국 다 해결할 수 있었다. 내 실력이면 이 정도는 풀어야 한다고 느꼈던 문제들은 다 풀었고, 시간을 더 주면 풀 수 있을 것 같은데 못 풀었던 문제들이 좀 있었다. R3까지 와 보는 건 처음인데 느리지만 꾸준히 성장하고 있다는 것을 느낄 수 있었고, 앞으로도 성장할 여지가 많이 남아 있다는 것을 느낀 의미 있는 대회였다.

#

“게임하는데 이유가 어딨어 그냥 하는거지!” 짤방으로 유명한 원사운드님 블로그를 보다가 흥미로운 글이 있어서 가져왔다. 인터폰에서 버튼을 눌러주면 대문이 열리는데, 여기다 라즈베리파이를 병렬로 연결하고 인터넷을 잡아서 모바일로 원격에서 문을 열 수 있게 하기 위해 삽질한 과정을 담은 포스팅이다.

시간 나면 이런 것도 해보고 싶기는 한데 우선순위가 더 높은 것들이 한참 쌓여 있는데다가, 결과물을 보기까지 들여야 하는 시간이 엄청 많다보니 해보기가 쉽지 않다.

대시보드

결과부터 말하자면 B Large를 제외한 모든 문제를 해결했고, 133위로 순조롭게 Round 2에 진출했다. R1A는 시험을 쳤지만 1000등 밖이라 떨어졌고, R1B도 칠 예정이었는데 과 MT랑 날짜가 겹쳐서 가서 어떻게든 쳐보려고 노트북을 들고 갔지만 인터넷이 안 되서 결국 R1C에서 통과하게 되었다.

A

A는 Battleship이라는 게임에서 파생된 간단한 게임 문제로, 두 사람이 최적의 해로 플레이할 때 게임이 얼마나 오래 지속되는지를 묻는 문제였다. small은 1차원, large는 2차원상에서 문제를 해결해야 하지만 배의 방향이 고정되어 있어 풀이가 크게 달라지지는 않는다. 한 번 위치를 부를 때 배가 있을 수 있는 가능성이 W개 줄어든다는 것을 관찰하면 쉽게 탐욕 알고리즘을 세울 수 있다.

28:37 AC

B

무한한 수의 원숭이들에게 타자기를 하나씩 쥐어 주고 무한한 시간이 흐르면 그 중 한 마리는 셰익스피어의 햄릿을 완성시킬 것이다.

B는 위의 유명한 농담에서 파생된 문제다. 목표 문장과 원숭이의 타자기가 주어지고, 원숭이가 몇 글자를 누르는지가 주어지면 원숭이가 목표 문장을 완성하는 횟수의 기대값을 구하는 문제였다. 일단 풀이는 생각이 났지만 동적 계획법과 문자열 매칭 알고리즘을 응용하는 지나치게 복잡한 풀이라 우선은 전부 만들어보는 naive한 방법으로 small만 해결했다.

38:56 AC

C

C는 화폐 개혁을 통해 사용 가능한 동전 개수를 최소로 추가하면서 특정 금액을 지불할 수 있도록 만드는 문제였다. 보자마자 떠올린 알고리즘이 맞았고, 목표 금액이 아주 큰 경우에서 실수한 것 때문에 한 번 WA를 받고 통과했다.

54:16 AC

전체 후기

문제를 풀면서 예상했던대로 B Large는 훨씬 쉬운 풀이가 존재했다. 나는 한 번 길을 잘못 들면 잘못된 풀이에 계속 빠져 있는데, 그걸 잘 파악해서 B Large를 빠르게 넘기고 C를 푼 게 이번 라운드의 성공 요인이라 생각한다. 100점이 아닌 사람들 중에서는 1위를 했고, 라운드 초반에는 잠깐이나마 Top 10에도 올라갔었기 때문에 성공적이었다고 생각한다.

이번에 못 풀었던 B Large 복습하고 R2에서도 좋은 결과를 얻어 올해는 꼭 티셔츠를 받고 싶다!

물리 숙제를 끝내고 잠깐 남는 시간에 뭘 할까 하다가 게임이 그닥 끌리지 않아서 시간이 더 지나기 전에 지난주에 쳤던 구글 코드잼 풀이나 써보자 하고 오랜만에 블로그를 켰다가 한참동안 블로그 업데이트에 시간을 썼다.

저번에 언급했다시피 요새 마크다운에 꽂혀서 과제나 게시글 등을 마크다운으로 많이 작성하고 있다. 지금까지는 마크다운 에디터에서 HTML로 뽑은 후 붙여 넣는 식으로 사용하고 있었는데, 이번 기회에 블로그에 마크다운으로 게시글 작성이 가능하게 세팅이나 하자 싶어서 플러그인 검색을 시작했고 Jetpack 플러그인을 사용하기로 결정했다. 다른 플러그인도 있었지만 이 플러그인이 WordPress.com 공식 플러그인이라 호환성이나 업데이트 측면에서 안정적일 것이라 느꼈고, shortcode 등 추가적인 문법 필요 없이 바로 에디터에서 마크다운을 사용할 수 있다는 점이 좋았다.

Jetpack에서 마크다운 외에도 소셜 댓글 및 공유 기능, 사이트 통계 등의 기능을 제공하길래 이 중에서도 마음에 드는 기능들을 골라서 활성화했다. 설치 후 테스트 하면서 기존에 달아 놓았던 Facebook 댓글 플러그인이랑 MathJax 플러그인이 제대로 동작하지 않길래 Jetpack에서 지원하는 기능으로 마이그레이션 했고, 블로그에 코드 삽입용으로 사용하던 Crayon Highlighter랑 마크다운 backtick 코드 태그가 충돌하는 문제를 inline code는 마크다운으로 사용하고, block code는 기존의 하이라이터를 사용하도록 충돌을 해결했다.

지금까지도 종종 생각했던 것이지만 프로그래밍을 안다는 것은 현대 사회에서 정말 엄청난 장점이라 느낀다. 문제가 발생했을 때 기반이 되는 기술들을 대략적이나마 파악하고 있기 때문에 문제의 원인에 대해 훨씬 빠르고 정확한 직관을 가질 수 있고, 자신이 필요로 하는 기능을 ‘직접 만들수 있다’는 사실은 문제 상황에서 취할 수 있는 선택지를 크게 넓혀준다. 이러한 문제 파악 – 가설 설정 – 문제 해결에 이르는 과정은 과학적 방법론과도 방향성이 일치한다.

이러한 맥락에서 나는 소프트웨어 교육을 공교육에 포함시키자는 입장에 대해 크게 찬성한다. 이를 통해 디지털 생태계에 대한 전반적인 지식을 쌓을 수 있으며, 이러한 지식들은 위에서 언급한 문제 상황에 대한 직관을 향상시키는데 큰 도움이 된다. 특히 프로그래밍은 Computational Thinking이라 불리는 사고방법을 익히는데 가장 효과적인 수단이다. 주의해야 할 점은 실제 교육 과정에서 왜 소프트웨어 교육이 필요한지에 대한 이해가 명확해야 한다는 점이다. 필요성에 대한 충분한 이해 없이 교육이 이루어진다면 조악한 앱이나 홈페이지 따위를 따라 만들면서 모든 아이들을 개발자로 양성하는 것이 목표라 오해 받을 수 있다.