Common Lisp備忘録

忘れた記憶を取り戻す

ABC 003b.lisp

ACしたコード その1

(let ((a (concatenate 'list (read-line)))
      (b (concatenate 'list (read-line)))
      (ans '())
      (flag t))

  (mapcar #'(lambda (n m)
              (if (char= n m)
                nil
                (cond ((char= n #\@) (push m ans))
                      ((char= m #\@) (push n ans))
                      (t (push #\b ans)))))
          a b)

  (mapcar #'(lambda (q)
              (if (find q (concatenate 'list "atcoder"))
                nil
                (setq flag nil)))
          ans)

文字qが文字列"atcoder"の中に含まれるかどうかの判定にfindが使える。

[1]> (find #\a (concatenate 'list "atcoder"))
#\a
[2]> (find #\z (concatenate 'list "atcoder"))
NIL

ACしたコード その2

(let ((a (concatenate 'list (read-line)))
      (b (concatenate 'list (read-line))))

  (defun create-chklst (lst1 lst2)
    (let ((lst '()))
      (mapcar #'(lambda (n m)
                  (if (char= n m)
                    nil
                    (cond ((char= n #\@) (push m lst))
                          ((char= m #\@) (push n lst))
                          (t (push #\b lst)))))
              lst1 lst2)
      lst))

  ;;; (format t "~A~%" (create-chklst a b))

  (defun check-lst-p (lst1)
    (not (member 'nil
                 (mapcar #'(lambda (c)
                             (if (find c (concatenate 'list "atcoder"))
                               t
                               nil))
                         lst1))))

  ;;; (format t "~S~%" (check-lst-p (create-chklst a b)))


  (format t "~A~%"
          (if (check-lst-p (create-chklst a b))
            "You can win"
            "You will lose")))

副作用の扱い(ansとflag)が手続き型っぽかったので関数型っぽい書き方にした。
標準入力から与えられた二つのリストの同じインデックスの要素の片方のみが@の場合、もう一つのリストの同じインデックスの文字を要素とするリストを生成し、それをチェックリストとした。

booleanを要素とするリストにNILが含まれているかどうかの判定

Break 6 [7]> (member 'nil '(T T T nil))
(NIL)
Break 6 [7]> (member 'nil '(T T T))
NIL

のように、member関数を使えば、
すべての要素がTの場合にNIL
一つでもNILを含んでいればリスト(真偽値はT)
を返す処理が書ける。しかし、このままではTとNILが逆転しているため、member関数の前にnotをつけた。

ACしたコード その3

(let ((a (concatenate 'list (read-line)))
      (b (concatenate 'list (read-line))))

  (defun create-chklst (lst1 lst2)
    (let ((lst '()))
      (mapcar #'(lambda (n m)
                  (if (char= n m)
                    nil
                    (cond ((char= n #\@) (push m lst))
                          ((char= m #\@) (push n lst))
                          (t (push #\b lst)))))
              lst1 lst2)
      lst))

  ;;; (format t "~A~%" (create-chklst a b))

  (defun check-lst-p (lst1)
    (every #'identity
           (mapcar #'(lambda (c)
                       (if (find c (concatenate 'list "atcoder"))
                         t
                         nil))
                   lst1)))

  ;;; (format t "~S~%" (check-lst-p (create-chklst a b)))


  (format t "~A~%"
          (if (check-lst-p (create-chklst a b))
            "You can win"
            "You will lose")))

(not (member 'nil
の代わりに
(every #'identity
した。こっちの方がロジックがわかりやすい。