Well done, whitypig!

よく焼けました,whitypig さん。
って,わしゃ肉か!
ハッピーボ〜イズッ! ワオッ!!
そんな感じでよく冷えました。

Project Euler Problem 1 から 50 のうちで,はまったところ。

なんだかんだで,50問目まで正解できました。
できたんですが,2カ所,はまったところ,そのうち1つは不思議状態,
があったので,メモるでござる。

Problem 45

その不思議状態。
最初は,力業というかパソコンのチカラで解決。
たしか結構時間がかかった気がする。
その後,他の人のポストを見ていて,なるほどなと。
よく考えてからコードを書きましょうとの教訓をゲット。


んで,下記のコードを試してみたのよ。

(defun euler45 ()
  (loop for h from 144
        for hn = (* h (- (* 2 h) 1))
        for pn = (/ (+ 1 (sqrt (+ 1 (* 24 hn)))) 6)
        when (integerp pn)
          return hn))

ワタシの環境は,Windows XPSP3,Cygwin,NTEmacs23.2,SBCL 1.0.51.36.mswinmt.961-3f3df1b
です。


Emacs 内から,C-cC-c してコンパイルすると,unreachable なコードを削除したよ的な
メッセージが出る。むぅ。
ほいで C-cC-y して(これ便利だから覚えようね) 実行するとオワラネェ。
ならばと,Cygwin から,sbcl --script ./e45.lisp とかしてみるも,オワラネェ。
Cygwin についてきた,clisp で,clisp ./e45.lisp すると正解が出る。


sqrt ってるので,integerp が t になり得ないから,終わらないと。
repl で確かめると,

CL-USER> (integerp (sqrt 1))
NIL

となる。ならばと,

(= 1.0 (round 1.0)) ;=> T
(= 1.1 (round 1.1)) ;=> NIL

であることを利用してみることに。

(defun euler45c ()
  (loop for h from 144
        for hn = (* h (- (* 2 h) 1))
        for pn = (/ (+ 1 (sqrt (+ 1 (* 24 hn)))) 6)
        when (= pn (round pn))
          return hn))

(euler45c) ;=> 29395278

Oh, what!? No way...


ほいだらばと,この euler45c を clisp で実行してみる。

% clisp ./e45.lisp
53763265

ぎょぎょぎょ。


なんか触れてはならんものに触れた気がするので,
これ以上追求するのをやめたのです。
テクねーし。
ちなみに,rem とか,floor とかも使ってみたけど
結果は同じでした。

Problem 49。permutation にはまる。

結果からいうと,数字のリストをもらって,permutation を返す関数が
バグっていたというオチ。
得た教訓は,remove には,keyword 引数で count があるということ。
テストは大事だということ。cl-test-more をしっかり使いましょうということでしょうかね。
あと,quicklisp バンザイ。asdf なんとかというのは,ワタシの環境では動作せずでした。
でで,その permutation 関数と実行結果は,以下。

(defun permutaion (nlst)
  (labels ((f (lst)
             (if (null (cdr lst))
                 (list lst)
                 (loop for i in lst
                       nconc (mapcar (lambda (l)
                                       (append (list i) l))
                                     (permutaion (remove i lst :count 1)))))))
    (remove-duplicates (f nlst)
                       :test #'equal)))
(mapcar #'list-to-num (permutaion (num-to-list 1234))) ;=>
(1234 1243 1324 1342 1423 1432 2134 2143 2314 2341 2413 2431 3124 3142 3214
 3241 3412 3421 4123 4132 4213 4231 4312 4321)

(mapcar #'list-to-num (permutaion (num-to-list 7777))) ;=> (7777)

(mapcar #'list-to-num (permutaion (num-to-list 7979))) ;=>
(7799 7979 7997 9779 9797 9977)


ま,順列すべてを求める必要はないよね〜とかなんとか。

まとめ

  • 紙とペン大事。
  • テスト大事。
  • Problem 51 でさっそく心が折れそう。