레이블이 Code Golf인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Code Golf인 게시물을 표시합니다. 모든 게시물 표시

2015년 9월 13일 일요일

Code Golf - 4Clojure 92번 문제

4Clojure 92번 문제는 Read Roman numerals.

로마표기수를 읽어들이는 함수를 작성하는 문제다.

(= 3999 (__ "MMMCMXCIX"))

빼기 표현에 주의해야 한다!

M = 1000
M = 1000
M = 1000
CM = 900  (C = -100, M = 1000)
XC = 90     (X = -10, C = 100)
IX = 9        (I = -1, X = 10)

(= 48 (__ "XLVIII"))

XL = 40  (X = -10, L = 50)
V = 5 
I = 1
I = 1
I = 1 

WWDC 2013년 공식 로고가 떠오른다. 
-- developer.apple.com에서
MMXIII = 2013
MM = 2000
X = 10
III = 3

일단 단순한 풀이는 빼기 규칙이 적용되느냐 아니냐를 결정하고 그런 다음 모두 더하는 것.

;; 130
(fn [roman]
  (let [m {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1}
        p (map (fn[a b]
                 (if (< (m a) (m b))
                   (- (m a))
                   (m a)))
               roman
               (rest roman))]
    (apply + (m (last roman)) p)))

이제 골프 시작~

zipmap은 keys와 vals로 map을 만드는 쉬운 방법이다. 그러나 이 경우는 코드가 더 길어진다.

기본적인 인라인으로 줄여보면,

;; 105
(fn [m r]
  (apply + 
         (m (last r))
         (map (fn [a b]
                (if (< (m a) (m b))
                  (- (m a))
                  (m a)))
              r
              (rest r)))) {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1}

m을 항상 적용하고 있으니 미리 적용시키면 될 것 같다.

;; 102
(comp
 (fn [r]
  (apply + 
         (last r)
         (map (fn [a b]
                (if (< a b)
                  (- a)
                  a))
              r
              (rest r)))) 
 #(map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} %))

comp 이득이 없는 것 같아 다시 let 을 써 봤는데, 마찬가지. ㅠ.ㅠ

;; 103
(fn [x]
  (let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} x)]
  (apply + 
         (last r)
         (map (fn [a b]
                (if (< a b)
                  (- a)
                  a))
              r
              (rest r))))) 

일단 #() 을 써서 줄이기

;; 100
(fn [x]
  (let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} x)]
  (apply + 
         (last r)
         (map #(if (< %1 %2) (- %1) %1)
              r
              (rest r))))) 

%1 중복 제거하여 1을 줄일 수 있었다.

;; 99
(fn [x]
  (let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} x)]
  (apply + 
         (last r)
         (map #((if (< %1 %2) - +) %1)
              r
              (rest r))))) 

#()의 중복을 피해서 더 줄일 수 있다.

;; 96
#(let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} %2)]
  (apply + 
         (last r)
         (map %1
              r
              (rest r)))) #((if (< %1 %2) - +) %1)

comp를 써도 같은 길이를 구할 수 있다.

;; 96
(comp
 #(apply + 
         (last %)
         (map (fn [a b] (if (< a b) (- a) a))
              %
              (rest %)))
 #(map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} %))


2015년 9월 12일 토요일

Code Golf - 4Clojure 73번 문제

73번 문제는 틱택토 판을 읽어 승자를 판별하는 함수를 작성하는 문제다.

(= :x (__ [[:x :e :o]
           [:x :e :e]
           [:x :e :o]]))

우선 마구잡이 풀이, 우선 :x가 이겼나 보고, 아니면 :o 가 이겼나 보고, 아니면 nil!
이겼는지는 row/col/diagonal이 모두 해당 플레이어인지 확인.

;; 294
(fn [board]
  (let [b2 (apply mapv vector board)
        d1 (map #(%1 %2) board [0 1 2])
        d2 (map #(%1 %2) board [2 1 0])
        win? (fn [p]
               (or (every? #(= p %) (board 0))
                   (every? #(= p %) (board 1))
                   (every? #(= p %) (board 2))
                   (every? #(= p %) (b2 0))
                   (every? #(= p %) (b2 1))
                   (every? #(= p %) (b2 2))
                   (every? #(= p %) d1)
                   (every? #(= p %) d2)))]
    (cond (win? :x) :x
         (win? :o) :o
          :else nil)))

Thinking Functionally with Haskell의 5장 Sudoku Solver와 비슷한 부분이 보인다. 결국은 3 rows, 3 cols, 2 diags 를 모두 구할 수 있으면 여기서 [:x :x :x]와 같은 것이 있는지 보면 되는거다.

collection에 요소가 있는지 확인하는 방법은 말그대로 set을 사용하면 된다. (set은 T => Bool 함수이기 때문)

;; 146
(fn [b]
  (let [c (apply mapv vector b)
        d (mapv #(%1 %2) b [0 1 2])
        e (mapv #(%1 %2) b [2 1 0])
        win? (fn [p]
               (some #{[p p p]} (concat b c [d e])))]
    (cond (win? :x) :x
         (win? :o) :o
          :else nil)))


가만 보면 원래 collection을 집합으로 보는 것이 낫겠다. 그리고 :else nil은 사족이다.

;; 136
(fn [b]
  (let [c (apply mapv vector b)
        d (mapv #(%1 %2) b [0 1 2])
        e (mapv #(%1 %2) b [2 1 0])
        win? (fn [p]
               ((set (concat b c [d e])) [p p p]))]
    (cond (win? :x) :x
         (win? :o) :o)))

그러고 보면 win?이란 함수는 set으로 처리가능하다.

;; 131
(fn [b]
  (let [c (apply map vector b)
        d (map #(%1 %2) b [0 1 2])
        e (map #(%1 %2) b [2 1 0])
        win? (set (concat b c [d e]))]
    (cond (win? [:x :x :x]) :x
         (win? [:o :o :o]) :o)))

일단 여기까지 하고 인라인, 인자 전달 등의 골프 기법 동원하여..

;; 110
(fn [a m b]
  (let [w (set (concat b
                       (apply m vector b)
                       [(m a b [0 1 2])
                        (m a b [2 1 0])]))]
    (cond (w [:x :x :x]) :x
         (w [:o :o :o]) :o))) #(%1 %2) map



2015년 9월 10일 목요일

Code Golf - 4Clojure 53번 문제

4Clojure의 53번 문제로 Code Golf를 즐기고 있다.  (지난 글)

마지막 스코어가 101글자, 도저히 더 못줄이겠다 싶었는다.

;; 101
(fn [& x]
  (#(case (count %) 1 [] %)
    (nth
      (filter #(apply < %)
               (mapcat seq
                       (iterate #(mapcat (juxt butlast rest) %)
                                x)))
      0)))

그런데, 점심 시간에 동료들에게 Code Golf를 소개하다가 방법이 떠올랐다! 불편한 모바일 브라우저에서 타이핑하여 성공! 이제 98!

;; 98
(fn [m & x]
  (#(case (count %) 1 [] %)
    (nth 
      (filter #(apply < %)
               (m seq
                  (iterate #(m (juxt butlast rest) %)
                            x)))
      0))) mapcat


(let[])바인딩 대신 첫 인자로 함수를 넘겨받는 방법으로 두번 사용된 mapcat을 하나 줄일 수 있었다.