Elice Shortest Code Competition

김수인2021-11-21

엘리스 개발팀에서는 개발팀 액티비티를 매달 개최합니다. 2021년 11월 액티비티로는 Elice Shortest Code Competition (ESCC) 를 개최했습니다. 이 대회는 ASCII 문자열로 엘리스의 favicon을 출력하는 가장 짧은 코드를 작성하는것이 목표로 favicon은 다음과 같은 모양입니다.

원래는 개발팀 내에서만 진행하려 했으나 엘리서 모두 참가하기로 룰을 변경하였고 제출된 코드는 김수인 CPO와 박정국 CTO 가 Judge 를 맡으며 평가하였습니다.

Rules

대회에는 다음 룰이 적용되었습니다.

  • 언어: 엘리스 다중 언어 실습에서 지원되는 모든 언어
    • C, C++, C#, F#, Go, Java, JS, Kotlin, Lua, PHP, Python, Ruby, Rust, Scala, Swift 등
  • 입력값: 없음
  • 출력값: 엘리스 로고
  • 출력 방법: ASCII 로 이루어진 문자열을 STDOUT 으로 출력
  • 제출 방법: 엘리스 플랫폼 내 테스트 과목에서 작성 후 제출

출력된 로고는 judge 들에 의해 엘리스 로고로 인정이 가능한지 여부를 검토하며, 제출한 코드들은 엘리스 플랫폼 내의 부정행위 방지 시스템에 의해 다른 사람의 코드를 참고하거나 카피하였는지의 여부에 대해 검사가 진행되었습니다.

예시

다음 예시는 두 명의 judge 에 의해 작성된 것입니다.

JavaScript (161 characters)

김수인 리더에 의해 자바스크립트로 작성된 예시입니다.

코드

E=L=>process.stdout.write(L);I=[...Array(20).keys()],I.map(C=>{I.map(R=>C*C-18*C+162+R*R-18*R<99?E((R+C==16||C+R==20)&&C>=5&&C<=13?"  ":"##"):E("  ")),E("\n")});

실행 결과

$ node javascript/main.js
          ##################            
        ######################          
    ##############################      
    ##############################      
  ##################################    
######################  ######  ######  
####################  ######  ########  
##################  ######  ##########  
################  ######  ############  
##############  ######  ##############  
############  ######  ################  
##########  ######  ##################  
########  ######  ####################  
######  ######  ######################  
  ##################################    
    ##############################      
    ##############################      
        ######################          
          ##################            

해설

20 x 20 의 픽셀로 원을 렌더하며 중간의 코드 R=>C*C-18*C+162+R*R-18*R<99 는 좌표 (C, R) 에 대해 수식 (C9)2+(R9)2<100(C-9)^2 + (R-9)^2 < 100 (100 이라는 숫자는 1 글자를 줄이기 위해 99 로 치환하였습니다) 의 체크로 해당 좌표가 (9, 9) 를 중심으로 가지는 반지름 99\sqrt{99} 원 안에 있는지 판별하는 역할을 합니다.
또한 // 를 x+y=cx+y = c 의 일차함수 형태에서 cc 값을 변형하면서 작성하였습니다.

해설을 쓰다 보니, 코드 C*C-18*C+162+R*R-18*R<9918*C-C*C-R*R+18*R>63 으로 바꾸면 4 글자를 더 줄였을 수 있을 것 같네요 🦝

Python (109 characters)

박정국 리더에 의해 작성된 파이썬 기반 예시 코드입니다.

코드

x=[' '*(6-i//2)+'#'*i for i in[5,7,9]];print('\n'.join(x+['#'*(5-i)+'  ##'*2+'#'*i for i in[1,2,3]]+x[::-1]))

실행 결과

$ python python3/main.py
    #####
   #######
  #########
####  ##  ###
###  ##  ####
##  ##  #####
  #########
   #######
    #####

해설

첫 번째 줄을 실행하여 변수 x 에 다음 리스트를 할당합니다.

['    #####', '   #######', '  #########']

그 뒤, 3개의 줄에 걸쳐,

  • 4개의 #, 공백, 2개의 #, 공백, 3개의 #
  • 3개의 #, 공백, 2개의 #, 공백, 4개의 #
  • 2개의 #, 공백, 2개의 #, 공백, 5개의 #
    을 만듭니다.

마지막으로, 처음으로 만든 x 와 중간에 만든 리스트, 그리고 x를 거꾸로 나열한 문자열을 출력합니다.

평가 및 시상

엘리서들은 일주일 간 코드를 제출할 시간이 주어졌고 제출한 코드에 대해 참가자들의 발표 및 설명이 이루어졌습니다. 코드 대회 참가자들은 준비한 점심을 나누어 먹으며 다른 사람들의 참신한 아이디어를 감상했습니다.

노력은 가상 (149 characters)

프로그래밍이 업인 개발팀에 비해 숙련도가 상대적으로 낮을 비-개발팀원을 위한 상으로 참신한 아이디어가 돋보인 코드입니다.

수상: 김경민 (Tech Content 팀)

코드

p=print;r=range;s="#";b=" "
m=[b*i+s*(20-2*i)for i in r(1,4)]
p('\n'.join(m[::-1]))
for i in r(8):
    p(s*(11-i)+"  ##  "+s*(i+3))
p('\n'.join(m))

결과

$ python3 -u python3/main.py
   ##############
  ################
 ##################
###########  ##  ###
##########  ##  ####
#########  ##  #####
########  ##  ######
#######  ##  #######
######  ##  ########
#####  ##  #########
####  ##  ##########
 ##################
  ################
   ##############

평가

Python 언어로 작성된 프로그램으로 print, range 에 대한 short link 를 이용하여 코드의 길이를 짧게 만들었습니다. Python 언어의 특성 상 여러 개의 문자열을 짧은 코드로 출력할 수 있는데, 예를 들면 '#' * 3 과 같은 syntax 로 ### 를 출력할 수 있고, 이런 특성을 잘 활용했습니다.

원을 그리기 위해 공백을 linear 하게 모델링 하였으나 20 글자 정도의 길이에서는 문제가 되지 않았습니다.

예술상 (250 characters)

다른 출품작들에 비해 원의 표현이 아름다웠기 때문에 예술상에 선정되었습니다.

수상: 유인성 (Frontend 팀)

코드

#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
int main(){for(int i=0;i<11;i++){if(i<3||i>7){cout<<setw(abs(i-5)*-2+24)<<string(abs(i-5)*-4+29,'@');}else{cout<<string(11-i,'@')<<"..@@@.."<<string(i+1,'@');}cout<<'\n';}}

출력 결과

$ g++ -o main -O2 -Wall cpp/main.cpp
$ stdbuf -i0 -o0 -e0 ./main
     @@@@@@@@@
   @@@@@@@@@@@@@
 @@@@@@@@@@@@@@@@@
@@@@@@@@..@@@..@@@@
@@@@@@@..@@@..@@@@@
@@@@@@..@@@..@@@@@@
@@@@@..@@@..@@@@@@@
@@@@..@@@..@@@@@@@@
 @@@@@@@@@@@@@@@@@
   @@@@@@@@@@@@@
     @@@@@@@@@

평가

타 출품작과 마찬가지로 원에 대한 모델링을 linear 하게 하였으나, 모델의 offset 을 적절하게 잡아 1-2-3 번째 라인의 경우 공백의 수가 2가 차이나고, 3-4번째 라인의 공백의 수가 1이 차이나게 되어 더욱 원에 가까운 출력 결과를 얻을 수 있었습니다. 추가로, 출력 문자 @. 의 선택이 더욱 로고를 부드럽게 보이게 했습니다.

최우수상 (92 characters)

기술적 측면 및 코드의 짧음 모두 다른 출품작에 비해 가장 우수하였던 코드입니다.

수상: 조민석 (Backend 팀)

코드

[print(('§'*n).center(9))for n in[5,9,9,9,5]]
[print(f'\x1b[{8-x};{x}H § ')for x in[5,4,3]]

출력 결과

$ python3 -u python3/main.py
  §§§§§  
§§§§ § §§
§§§ § §§§
§§ § §§§§
  §§§§§

평가 및 해설

코드의 길이를 극단적으로 줄이기 위해 로고의 사이즈는 세로x가로 기준 5x9 글자로 제한하였습니다. 가로의 길이가 10글자 이상이 되면, 이 코드에서 사용한 메서드에 들어가는 파라미터에 10 이라는 값을 입력하기 위해 9 에 비교하면 1바이트가 추가되기 때문입니다.

첫 번째 줄은 [5, 9, 9, 9, 5] 라는 리스트를 만들고 이 리스트 안의 원소들에 대해 iteration 을 수행하면서 각각의 원소에 대해 ('§'*n).center(9) 라는 명령어를 수행하고 이것을 출력합니다.

center 메서드는 Python string의 빌트인 메서드로, width 값을 받아 width-길이의 문자열을 만들고 이 가운데에 해당 메서드를 호출한 문자열을 위치시킵니다. 예를 들면,

>>> '###'.center(7)
'  ###  '

이로서 # 에 대해 [5,9,9,9,5] 개의 길이를 가진 문자열을 생성하고 각각의 문자열을 길이가 9인 공백의 가운데에 위치시킬 수 있게 됩니다. 여기까지 진행한 뒤의 결과값은 다음과 같습니다.

  §§§§§  
§§§§§§§§§
§§§§§§§§§
§§§§§§§§§
  §§§§§

다음으로 이 코드에서 사용된 재미있는 트릭은 ANSI escape sequence 를 이용한 것으로 엘리스의 실행 환경이 쉘을 진행한다는 것을 이용한 것입니다. 일반적으로 이 escape sequence 는 쉘에서 컬러나 텍스트의 스타일을 정의하는데 자주 사용됩니다. 특정한 escape sequence 를 사용하면, 커서를 원하는 위치에 옮길 수 있습니다. 이 코드에서 사용한 방식은 커서를 특정 line과 column 에 위치하게 하는 것으로 다음과 같습니다.

- Position the Cursor:
  \033[<L>;<C>H
     Or
  \033[<L>;<C>f
  puts the cursor at line L and column C.

프로그램을 실행하면서 명령어가 bash 에 출력되므로, 커서를,

  • (3, 5)
  • (4, 4)
  • (5, 3)
    에 순차적으로 위치시키면서 문자열 § 을 출력하면 이미 출력된 원 위에 이 문자열을 덮어씌우면서 엘리스 로고에서 // 를 출력할 수 있게 됩니다. 따라서 두 번째 라인을 실행한 이후의 결과는
  §§§§§  
§§§§ § §§
§§§ § §§§
§§ § §§§§
  §§§§§

로 엘리스 로고가 만들어졌습니다.

Notable (373 characters)

이 코드는 박정국 리더에 의해 작성된 것으로 주어진 엘리스 로고를 완벽하게 출력하는것을 유지하면서 코드의 길이를 짧게 하는 것을 목표로 하였습니다.

코드

import pip;pip.main(['install','base65536','climage']);
import site;site.main();
import climage as c,base65536 as b;
open('.png','wb').write(b.decode('薉籎㸍㸚㐀䄀絉蝄㐀匀㐀匀㨈㐀瀀𣐰㒢㐀𓄁籒㑂𥒮𦼜㐀㠀癧癍㐀𡖱𨈋㥡㐀㴀絰𓅙㐀𠰝㐀𠰝鈁䞢㒁㔀縟癄絔𣭋𦆖𤠊䀰𦆆𠄊𤜾𡽋氏𤜄𦳃𖢓𥧥礌緝𣄥𡱍𧛴䳝𥎝𨋗杶𨓻㡢𣳬褝𐙱㟷杔𧝘𡊚𣡂蜉徜𒇅𧸛𡴓霐𣼨𥶃蕪憃𢯄𧮧𨃄𤫾𢪵𣚞懿抮暍挟䲍䨟𡒼燺𠗄𓍏𣺸磛肋溍𢍷靸𦁮𖧓𡬏續𡂮䟚𦅎倴𦪨奉肉抐𢒖䓦𧺑𣨺𡭐奃𥲶驂淌𢚾飊䏵簄𧨹𓅏召揰𦰽𦕋𠓪慣𤟍𥄹𣾋𡵻𤲻𥷡岉𢣦𤫔𡿬𥫅𢷮覆𧑓㤚懶𠌞𔑒㖮䮋𢵑𐛾𤠒𣃞𢍓ꍊ𣂠𣶏褓𦪊嫄𦵢𣙺𦵑𥷈𡣖𠵑𢥈𐚗慖𠫆𥚛頧㯌䞿𢂏𢵰爘㐀㐀穉祎瞮𠡠'));
print(c.convert('.png'))

실행 결과

다음과 같이 터미널에서 한 글자당 한 픽셀의 이미지가 출력되는 것을 확인할 수 있습니다.

해설

가장 첫 줄이 하는 것은 기본 환경에서 제공되지 않는 패키지인 base65536climage 를 설치하는 것입니다. base65536 은 UTF-32 인코드된 텍스트에서 바이너리 데이터를 표현하기 위한 인코딩 방식으로 유니코드에서 사용하는데에 최적화되어 있습니다. 또한 climage 는 CLI 환경에서 이미지를 터미널에 프린트 할 수 있습니다.

이 코드가 진행하는 것은 엘리스 로고를 터미널에서 표현할 수 있는 정도로 downscale 한 이미지를 base65536 으로 인코딩 하고, 이것을 png 파일에 저장하여 climage 라이브러리를 이용하여 출력하는 것입니다. 본 대회에서는 바이트 수가 아니라 문자열 (character) 수를 카운트 하므로, 이 룰을 hack 한 훌륭한 솔루션이라고 할 수 있습니다.

마치며…

본 대회는 IOCCC (The International Obfuscated C Code Conteest – 가장 혼란스러운 C 코드 작성 대회) 에서 영감을 받아 시작하였는데, 엘리서들의 창의력이 제가 생각했던 것보다 매우 뛰어나서 즐거웠습니다. 단순하게 원이나 선을 계산하는 방식에 최적화가 이루어진 것 이상으로 커서를 이동하거나 base65536 을 이용하여 코드 글자 수를 줄인 것 등을 보며 개발자로서 이런 생각을 할 수 있는 동료와 일하는 것이 행복하다고 느꼈습니다.

최우수상 작은 브랜드팀이 제작한 엘리스 사내 포스터에 인쇄되었습니다 :)
최우수상 작은 브랜드팀이 제작한 엘리스 사내 포스터에 인쇄되었습니다 :)

  • #elice
  • #competition
실습형 플랫폼으로 임직원 디지털 전환 교육에 성공하세요

DX교육은 엘리스

입력해주신 이메일은 회사소개서 발송에만 활용됩니다