kiyokaのブログアーカイブ

Archive of old blog posts

「10分でコーディング」をやってみた

10分でコーディング|プログラミングに自信があるやつこい!! 今日の問題はかなり簡単です。 できるだけ早い時間でエレガントなコードを書きましょう。 あまりに簡単なので制限時間を10分としてやってみてください。 これ以上かかった人は 自分はかなりプログラミングができない。 とつらい事実を認識しましょう。

Nendoで書いてみた

5分くらい考えて5分くらいでコードを書いた。 やっぱり時間を切ると、いつものコーディングパターンになっちゃうなあ。 副作用をなるべく起こさないように、そして、計算量は気にしないスタイル。 [Sekka]の辞書作成に時間がかかるのもきっと、それに違いない。と、思った…

ソースコード:cards.nnd

(use srfi-1)

(define (deal players deck)
  (let* ((lst (to_list (deck.split "")))
         (idx (append-map
               (lambda (x)
                 (range players))
               (range (/ deck.size players))))
         (idx-lst (zip idx lst)))
    (map
     (lambda (p)
       (string-join
        (filter-map
         (lambda (x)
           (when (= p (first x))
             (second x)))
         idx-lst)))
     (range players))))

(define (main argv)
  #?=(deal 3 "123456")
  #?=(deal 3 "1234567")
  #?=(deal 2 "")
  #?=(deal 1 "012345012345012345"))

実行結果

$ nendo cards.nnd 
#?="cards.nnd":24:(deal 3 "123456")
#?-    ("14" "25" "36")
#?="cards.nnd":25:(deal 3 "1234567")
#?-    ("14" "25" "36")
#?="cards.nnd":26:(deal 2 "")
#?-    ("" "")
#?="cards.nnd":27:(deal 1 "012345012345012345")
#?-    ("012345012345012345")

Gaucheで書いてみた

このプログラムを作ってみて感じたのは、Gaucheには、ぴったりのライブラリがあるので凄く早く書けそうだということ。 それは、slicesとtakeだ。 ちょっと書いてみよう。 ソースコード:cards.scm

(use srfi-1)
(use util.list)

(define (deal players deck)
  (let1 lst (map (lambda (x) (string x))
                 (string->list deck))
    (if (or (eq? 1 players)
            (eq? 0 (length lst)))
        deck
        (take
         (map (lambda (x) (apply string-append x))
              (slices lst (quotient (length lst) players)))
         players))))
  
(define (main argv)
  #?=(deal 3 "123456")
  #?=(deal 3 "1234567")
  #?=(deal 2 "")
  #?=(deal 1 "012345012345012345"))

実行結果

$ gosh cards.scm
#?="./cards.scm":16:(deal 3 "123456")
#?-    ("12" "34" "56")
#?="./cards.scm":17:(deal 3 "1234567")
#?-    ("12" "34" "56")
#?="./cards.scm":18:(deal 2 "")
#?-    ""
#?="./cards.scm":19:(deal 1 "012345012345012345")
#?-    "012345012345012345"

うーん、そうでもないか。 ライブラリが自分の思うような仕様でなく、リファレンスを調べたりしているうちに結構時間がかかってしまった。 string-splitのデリミタに空文字列が指定できない制限と、slicesが1で切れない制限とであまり短かく書けなかった… [Nendo]にutil.listライブラリを追加したら、Rubyのライブラリとの組み合わせでもっと短かく書けそうだ。

やっぱり短い時間で書き捨てスクリプトを作るにはライブラリだなぁと再認識した次第。 util.list は takeとか日常的によく出会うリスト処理が入っているので、そろそろ[Nendo*]にポーティングしよう。

追記:Gauche版修正

もっと綺麗に書けるだろうと思ってリファクタリングしてみた。

(use srfi-1)
(use util.list)

(define (deal players deck)
  (let1 lst (string->list deck)
    (if (null? lst)
        lst
        (take (map (lambda (x) (list->string x))
                   (slices lst (quotient (length lst) players)))
              players))))

(define (main argv)
  #?=(deal 3 "123456")
  #?=(deal 3 "1234567")
  #?=(deal 2 "")
  #?=(deal 1 "012345012345012345"))

ちょっとだけ短かくなったかな。 [Nend]oにutil.listライブラリを追加したら、さらに再度[Nendo]で書いてみよう。