LoginSignup
1

More than 5 years have passed since last update.

「数を作る」をSchemeで(横へな9参考)

Last updated at Posted at 2013-07-22

http://qiita.com/Nabetani/items/7c46e8409c456e8fabd1
http://nabetani.sakura.ne.jp/hena/ord9nummake/
「数を作る」をSchemeでやってみました。

先にすべての組み合わせを作ってから、指定番目を取り出す方法です。

いつもの通りErlangで始めたのですが、あまり関数脳になっていないためか自分のコードの書き方に納得がいかず、Schemeに立ち戻って書いてみました。

が、やはりコードに納得いっていません。上手い人が書いたらもっとスマートでエレガントになるはず。あと関数名にプログラミング能力の限界が見えてます。

実行環境はMIT/GNU Schemeです。他のSchemeでは文字列操作関数とかformat関数の書式指定子とかが違うと思います。

正直死にそうです。括弧が、括弧が襲ってくる~ (@_@)

;; 与えられた整数リストから4つを使った全組み合わせを返す
(define (combi4 unselected selected)
  (define (delete-one x ls) ;; xを1つだけ削除したリストを返す
    (cond
     ((null? ls) '())
     ((= x (car ls)) (cdr ls))
     (else (cons (car ls) (delete-one x (cdr ls))))))
  (define (if6append9 x f) ;; xが6以外ならf(x)を、6ならf(6)とf(9)を連結して返す
    (if (= x 6)
        (append (f 6) (f 9))
        (f x)))
  (define (nextlevel x results) ;; 数を1つ組み合わせて次の桁へ進む
    (append
     (if6append9
      x
      (lambda (y)
        (combi4 (delete-one x unselected)
                (cons y selected)))) results))
  (if (= 4 (length selected))
      (list selected)
      (fold nextlevel '() unselected)))

;; リストの全組み合わせからn番目の整数を返す
(define (solve2 n ls)
  (define (list->num ls) ;; [1,1,0,9] -> 1109
    (fold (lambda (x s) (+ x (* s 10))) 0 ls))
  (define (take-n x over ls) ;; n番目があればその値、なければoverに指定された値を返す
    (if (> x (length ls))
        over
        (car (drop ls (- x 1)))))
  (take-n n '- (filter
             (lambda (x) (>= x 1000))
             (sort (delete-duplicates
                    (map list->num 
                         (combi4 ls '()))) <))))

;; 文字列を与えると問題を解く
(define (solve s)
  (define (char->number c)
    (- (char->integer c) (char->integer #\0)))
  (define (colon-idx)
    (string-search-forward ":" s))
  (define (get-n)
    (string->number (string-head s (colon-idx))))
  (define (get-numlist)
    (map
     char->number
     (string->list
      (substring s (+ 1 (colon-idx)) (string-length s)))))
  (solve2 (get-n) (get-numlist)))

;; テスト
(define (test data expected)
  (define (eq a b) ;; 数値または-を比較する
    (if (symbol? a) (eq? a b) (= a b)))
  (format #t "~A: ~A -> ~A~%"
          (if (eq expected (solve data)) "ok" "ng")
          data expected))

(define (tests)
  (begin
    (test "13:01167" 1109)
    (test "1:1234" 1234)
    (test "13:01167" 1109)
    (test "1:1234" 1234)
    (test "2:1234" 1243)
    (test "7:1234" 2134)
    (test "24:1234" 4321)
    (test "25:1234" '-)
    (test "2:1116" 1119)
    (test "2:0116" 1019)
    (test "3:6666" 6696)
    (test "16:6666" 9999)
    (test "10:01267" 1097)
    (test "14:111167" 1671)
    (test "1:1111" 1111)
    (test "2:1111" '-)
    (test "1:666633" 3366)
    (test "72:666611" 9999)
    (test "73:666622" '-)
    (test "1:666600" 6006)
    (test "52:666600" 9999)
    (test "53:666600" '-)
    (test "25:06688" 8086)
    (test "93:02566" 6502)
    (test "11:06688" 6809)
    (test "169:01268" 9801)
    (test "174:01268" 9821)
    (test "66:012288" 8201)))

(tests)

結果の一部:


ok: 1:1234 -> 1234
ok: 2:1234 -> 1243
ok: 7:1234 -> 2134
ok: 24:1234 -> 4321
...

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1