FizzBuzz
369랑 살짝 비슷한 게임입니다. 위키피디아엔 애기들 교육용 놀이라는데, 구글에 검색하면 관련 내용은 거의 온데간데없는 수준이고 코드만 난무합니다.
룰은 간단합니다. 1부터 시작해 3의 배수엔 Fizz를, 5의 배수엔 Buzz를 얘기하면 됩니다. 3과 5의 공배수인 15의 배수엔 FizzBuzz를 외쳐야 합니다.
그냥 풀어만 보고 넘어간 문제였는데, 어쩌다 알게 된 코드 골프(최대한 짧은 코드로 결과를 구현하는 것) 사이트에 있길래 저 도전과제 하나만 보고 난생처음 보는 언어들로 풀어봤네요.
와중에 PHP랑 Javascript는 1등도 먹었습니다.
게임은 접어도 도전과제만 보면 깨고 싶은 욕구는 사라지질 않네요.
C
#include <stdio.h>
int main(void){ for (int i = 1; i < 101; i++) { if (i % 3 == 0 && i % 5 == 0) { printf("FizzBuzz\n"); } else if (i % 3 == 0) { printf("Fizz\n"); } else if (i % 5 == 0) { printf("Buzz\n"); } else { printf("%d\n", i); } } return 0;}
굉장히 정석적이고 정상적인 FizzBuzz 구현 방법입니다.
사실 위 코드를 보시면 아시겠지만, 이제 막 공부를 시작한 사람이 아니고서야 딱히 흥미를 느끼기 어려운 코드입니다. 이래서 보통 이런 문제를 코드 골프에 쓰지 않나 싶네요. 짧게 줄이려고 갖은 꼼수 동원하다 보니 머리를 많이 굴려야 하더라고요.
Javascript
for (let i = 1; i < 101; i++) { console.log( i % 3 === 0 && i % 5 === 0 ? "FizzBuzz" : i % 3 === 0 ? "Fizz" : i % 5 === 0 ? "Buzz" : i );}
벌써 동업자가 있다면 몇 대 줘 터질 코드긴 하지만, 아직 더 줄여야 합니다.
보통 for 루프를 시작할 때, i = 1; i < 101; i++
에서 i=0;++i<100;
같은 방식으로 글자를 줄이는 것으로 시작합니다.
게다가 자바스크립트처럼 좀 근본이 없는 언어는 a = 1처럼 변수를 선언해도 별문제가 없습니다.
for (i = 1; ++i < 101;) { console.log((i % 3 ? "" : "Fizz") + (i % 5 ? "" : "Buzz") || i);}
천천히 보시면 이해가 될 겁니다.
%는 나머지를 구하는 것이고, 숫자는 0을 제외하면 참이니 i % 3
이란 조건은 3으로 나누어떨어지면 false를, 아니면 true를 반환합니다.
String을 더하면 두 문자열이 합쳐집니다.
조건에 텅 빈 문자열이 들어가면 false입니다.
많이 짧아지긴 했지만, i % 3
, i % 5
두 가지 조건에 계속 ? "" : "String"
이 들어가는 게 영 보기 거슬립니다.
for (초기문; 조건문; 증감문) { 실행 문장;}
넘어가기 전에 짧게 for loop의 동작 방식을 살펴보겠습니다.
- 초기문 실행.
- 조건문 검사 (참이면 진행, 거짓이면 종결)
- 실행 문장 실행
- 증감문 실행
위 방법으로 for loop가 동작합니다.
for (i = 0; ++i < 101; console.log(i % 5 ? x || i : x + "Buzz")) x = i % 3 ? "" : "Fizz";
위를 활용해 실행 문장에 변수를 하나 선언해두고 증감문에서 console.log를 실행하면 이런 기괴하고 짧은 코드가 탄생합니다.
for(i=0;++i<101;console.log(i%5?x||i:x+'Buzz'))x=i%3?'':'Fizz'
이를 압축하면 62글자로 이루어진 짧은 FizzBuzz가 탄생합니다.
PHP
while($i++<100)echo[Fizz][$i%3].[Buzz][$i%5]?:$i,''
얘도 하나씩 뜯어보면 이해 가능하실 겁니다.
Array에 없는 인덱스에 접근해도 아무런 오류도 없고, undefined가 뜨지도 않으니 위 코드처럼 기괴하게 작성해도 잘 작동합니다.
CSS
여담으로, for 루프 없이 HTML,CSS로도 가능합니다.
- var n = 0;ol while n < 100 li - n++
ol>li*100을 다 적을 순 없으니 Pug로 대체합니다.
ol { list-style: decimal inside;}
li:nth-child(3n), li:nth-child(5n) { list-style-type: none;}
li:nth-child(3n):before { content: 'Fizz';}
li:nth-child(5n):after { content: 'Buzz';}
실행 결과