目にとまったので、ちょっとやってみた。
(defmacro alambda (params &body body) `(labels ((self ,params ,@body)) #'self)) (defmacro aif (test-form then-form &optional else-form) `(let ((it ,test-form)) (if it ,then-form ,else-form))) (defun numlist-from-string (s) (loop for i from 0 below (length s) collect (parse-integer (string (char s i))))) (defun unique(lst) (let ((result nil)) (loop for i from 0 below (length lst) when (null (member (elt lst i) result :test #'equal)) do (setq result (append result (list (elt lst i))))) result)) (defmacro make-three-combination(a1 a2) (let ((l (gensym))(pos (gensym))) `(lambda (,l ,pos) (if (and (= (+ ,a1 (elt ,l ,pos)) (elt ,l (+ ,pos 1))) (= (+ ,a2 (elt ,l ,pos)) (elt ,l (+ ,pos 2)))) (list (elt ,l ,pos) (elt ,l (+ 1 ,pos)) (elt ,l (+ 2 ,pos))))))) (defun make-two-combination(l pos) (if (= (elt l pos) (elt l (1+ pos))) (list (elt l pos) (elt l pos)))) (defmacro combi-generator(fn size step) (let ((l (gensym)) (pos (gensym)) (result (gensym))) `(alambda (,l ,pos ,result) (if (< (- (length ,l) ,pos) ,size) ,result (aif (funcall ,fn ,l ,pos) (self ,l (+ ,pos ,step) (append ,result (list it))) (self ,l (+ ,pos 1) ,result)))))) (defmacro def-combination-generator (fun-name generator size step unique) (let* ((lst (gensym)) (l (if unique `(unique ,lst) lst))) `(defun ,fun-name (,lst) (funcall (combi-generator ,generator ,size ,step) ,l 0 nil)))) (def-combination-generator ko-tu (make-three-combination 0 0) 3 3 nil) (def-combination-generator jun-tu (make-three-combination 1 2) 3 1 t) (def-combination-generator toi-tu #'make-two-combination 2 2 nil) (defun all-combi(lst) (unique (append (jun-tu lst) (ko-tu lst) (toi-tu lst)))) (defun three-combi(lst) (unique (append (jun-tu lst) (ko-tu lst)))) (defun sub (source arg) (if arg (sub (let ((pos (position (car arg) source))) (loop for i from 0 below (length source) when (/= i pos) collect (elt source i))) (cdr arg)) source)) (defun sameface?(x) (= 0 (apply #'+ (mapcar #'(lambda (y)(if (= (car x) y) 0 1)) (cdr x))))) (defun combi-less2?(x y) (cond ((< (apply #'max x) (apply #'max y)) t) ((< (apply #'+ x) (apply #'+ y)) t))) (defun combi-less?(x y) (cond ((> (length x) (length y)) t) ((< (length x) (length y)) nil) ((and (sameface? x) (not (sameface? y))) t) ((and (not (sameface? x)) (sameface? y)) nil) (t (combi-less2? x y)))) (defun %ans-2(rest &optional (result nil)) (if (< (length rest) 3) (cond ((= 1 (length rest)) (list (append result (list rest)))) ((and (= 2 (length rest)) (= 1 (abs (- (elt rest 0) (elt rest 1))))) (list (append result (list rest)))) ((and (= 2 (length rest)) (= (elt rest 0) (elt rest 1))) (list (append result (list rest))))) (let ((lst (if (= (length rest) 13) (all-combi rest) (three-combi rest)))) (if lst (loop for i from 0 below (length lst) append (%ans-2 (sub rest (elt lst i)) (append result (list (elt lst i))))))))) (defun ans(rest) (format t "~a~%" rest) (mapcar #'(lambda (x) (multiple-value-bind (l r) (split x) (format t "result: ~{~a~} " (sort l #'combi-less2?)) (format t "~{[ ~{~a ~}]~}~%" (sort r #'combi-less2?)))) (unique (mapcar #'(lambda (x) (sort x #'combi-less?)) (%ans-2 (sort rest #'<)))))) (defun split(list) (let ((l (reverse list))) (if (and (sameface? (elt l 0)) (sameface? (elt l 1)) (= (length (elt l 0)) 2)) (values (nreverse (cddr l)) (list (cadr l) (car l))) (values (nreverse (cdr l)) (list (car l)))))) (ans (numlist-from-string "1112224588899")) (terpri) (ans (numlist-from-string "1122335556799")) (terpri) (ans (numlist-from-string "1112223335559")) (terpri) (ans (numlist-from-string "1223344888999")) (terpri) (ans (numlist-from-string "1112345678999"))
loopでappend使うことを今回覚えました。
元記事ちゃんと読んだら、3時間制限だったみたい。
でもギリアウトかな。
ちょこちょこ直したのもあわせると遙かにオーバーです。
出力結果が若干出題と違うとこもあるし。
一カ所、再帰プロセスが必要なところで繰返しプロセスを使っていたことと、loopのappendを知らなくて四苦八苦したこととの合わせ技に苦労させられました。
リストの中から重複を取除くとか、リストの末尾から取出すとか、きっとイデオムがあるんだろうから、もう少し色々しらべないと。
追記:バグを一個取り、少し短くしました。