2014年2月25日

codejamの過去問でcommon lispの練習2

問題は2013のqualification round B

結果用の高さ100の芝生を用意して、入力される刈り込みたい候補案を高さ100のものに適用する
適用は、入力縦横一行取り出して、その一行の一番高いものを結果用に当てはめる
当てはめる際に入力より高い場合は入力値に合わせる
すでに入力より低い場合はそのまま
縦横当てはめて結果用と入力が同じかどうか判定


(defmacro form1(x) `(format t "~A~%" ,x))

(defun repeat(x n)
  (labels ((rec(i acc)
    (if (= i n)
      acc
      (rec (1+ i) (cons x acc)))))
 (rec 0 nil)))

(defun range(n)
  (labels ((rec(i acc)
    (if (= i n)
      (reverse acc)
      (rec (1+ i) (cons i acc)))))
 (rec 0 nil)))

(defun readstream(callback)
  (labels ((rec(n)
    (let ((line (read-line *standard-input* nil)))
      (when line
     (funcall callback line n)
     (rec (1+ n))))))
 (rec 0)))

(defun parseNM(line)
  (read-from-string (format nil "(~A)" line)))

(defun maxval(lst)
  (reduce #'max (cdr lst) :initial-value (car lst)))

(defun toverticalvals(lst)
  (mapcar (lambda(i)
   (reduce (lambda(r x) (max r (nth i x))) (cdr lst) :initial-value (nth i (car lst))))
 (range (length (car lst)))))

(defun applyverticalvals(lst vlst)
  (mapcar (lambda(r) (mapcar #'min r vlst)) lst))

(defun compute(in)
  (labels ((rec(in acc)
    (if (null in)
      (reverse acc)
      (rec (cdr in) (cons (repeat (maxval (car in)) (length (car in))) acc)))))
 (equal in (applyverticalvals (rec in nil) (toverticalvals in))))
  )

(defun test()
  ;(form1 (toverticalvals '((2 1 2) (1 8 1) (2 1 3))))
  ;(form1 (range 10))
  ;(form1 (maxval '(8 7 6 5 4 3 2)))
  )
(test)

(let ((in nil)
   (no_of_problem 0)
   (problemindex 0)
   (size '(1 0))
   (nextsizeindex 1)
   (messagelut '((t . "YES") (nil . "NO"))))
  (readstream (lambda(line n)
    ;(format t "~A ~A ~A~%" n nextsizeindex line)
    (cond ((zerop n) (setf no_of_problem (read-from-string line)))
       ((= n nextsizeindex) (incf problemindex) (setf size (parseNM line)) (setf nextsizeindex (+ nextsizeindex (car size) 1)) (setf in nil))
       (t (setf in (cons (parseNM line) in)) (when (= n (1- nextsizeindex))
                 (format t "Case #~A: ~A~%" problemindex (cdr (assoc (compute (reverse in)) messagelut)))))
       )
    )
     )
  )

2014年2月18日

codejamの過去問でcommon lispの練習

codejamの季節が近づいてきたのでcommon lispの練習をしました
問題は2013のqualification round

まずA
入力をアトムへ置き換えて横向きのリストで格納して、さらに縦向きのリストと斜めのリストを作ってX,Oどちらかが勝っている状態があるか検索
とりあえず横向きで検索、見つからなかったら縦向きで検索、さらに見つからなかったら斜めで検索
X,Oどちらの勝利状態も見つからない場合引き分けかどうか判定
マクロの練習として、縦向きのリストの作成をマクロで展開してみました
例えば将棋やオセロなんかのプログラムだとリストを走査する際にループじゃなくていちいち展開しているっぽいなと思ったので、一度マクロで試してみたかったので無理やりマクロ使いましたが結果はいいのか悪いのか不明
プログラムが分かりにくくなったのはとりあえず分かる


(defun readstream(callback)
  (labels ((rec(n)
    (let ((line (read-line *standard-input* nil)))
      (when line
     (funcall callback line n)
     (rec (1+ n))))))
 (rec 0)))

(let ((a '(0 1 2 3)))
  (defun tosymb(line)
 (mapcar (lambda(n) (read-from-string (substitute #\B #\. line) nil nil :start n :end (1+ n))) a))
  (defmacro tocross(lst)
 `(list
    (list ,@(mapcar (lambda(n) `(nth ,n (nth ,n ,lst))) a))
    (list ,@(mapcar (lambda(n) `(nth (- 3 ,n) (nth ,n ,lst))) a))
    ))
  (defmacro tovertical(lst)
 `(list
    ,@(mapcar (lambda(m)
     (cons 'list (mapcar (lambda(n) `(nth ,m (nth ,n ,lst))) a))
     ) a)
    )
 )
  (defun makelst(b n)
 (mapcar (lambda(m) (if (= n m) 't b)) a))

  (defmacro searcher(lst v)
 `(let ((target ',(mapcar (lambda(n) (makelst v n)) a)))
    (labels ((rec(ta)
      (cond ((null ta) nil)
      ((equal (car ta) ,lst) ',v)
      (t (rec (cdr ta))))))
   (rec (cons (list ',v ',v ',v ',v) target))
    )
 ))
  )

(defun hanbetsu(inlst)
  (labels ((rec(lst)
    (cond ((null lst) nil)
       ((searcher (car lst) x) 'x)
       ((searcher (car lst) o) 'o)
       (t (rec (cdr lst))))))
 (rec inlst)))

(defun drawp(lst)
  (labels ((rec(lst)
    (cond ((null lst) 'd)
       ((find 'b (car lst)) 'n)
       (t (rec (cdr lst))))))
 (rec lst)))

(defmacro ifelse(pred else)
  `(let ((r ,pred))
  (if r
    r
    (progn ,else))))

(defun test()
  (let ((lst '((a b c d) (e f g h) (i j k l) (m n o p))))
 (format t "~A~%" (macroexpand-1 '(ifelse (hanbetsu (tocross in)) (lambda()))))
 ;(format t "~A~%" (drawp '((a z c d e))))
 ;(format t "~A~%" (mapcar (lambda(n) (makelst 'x n)) '(0 1 2 3)))
 ;(format t "~A~%" (macroexpand-1 '(searcher (car lst) x)))
 ;(format t "~A~%" (hanbetsu '((x x t x))))
 ;(format t "~A~%" (macroexpand-1 '(tocross lst)))
 ;(format t "~A~%" (tocross lst))
 ;(format t "~A~%" (macroexpand-1 '(tovertical lst)))
 ;(format t "~A~%" (tovertical lst))
 (format t "~%~%")
 ))
;(test)

(defun compute(in)
  (ifelse (hanbetsu (tocross in))
    (ifelse (hanbetsu (tovertical in))
      (ifelse (hanbetsu in)
        (drawp in)))))

(let ((in nil)
   (index 0)
   (messagelut '((x . "X won") (o . "O won") (d . "Draw") (n . "Game has not completed"))))
  (readstream (lambda(line n)
    (cond ((zerop (rem n 5)) (setf in nil) (incf index))
    ((= (rem n 5) 4)
     (progn
    (setf in (cons (tosymb line) in))
    (format t "Case #~A: ~A~%" index (cdr (assoc (compute (reverse in)) messagelut)))
    ))
    (t (setf in (cons (tosymb line) in)))))
  )
  )

2014年2月16日

Lispの割り算まとめ

mod rem
floor truncate ceiling round

mod:floorの余り
rem:truncateの余り

floor:商-∞
truncate:商0
ceiling:商+∞
round:商を近い整数

x < 0の場合
(truncate x)と(ceiling x)は同じ
x > 0の場合
(floor x)と(truncate x)は同じ




'FLOOR     (/   3  2) is   1   1/2
'TRUNCATE  (/   3  2) is   1   1/2
'CEILING   (/   3  2) is   2  -1/2
'ROUND     (/   3  2) is   2  -1/2
'FLOOR     (/  -3  2) is  -2   1/2
'TRUNCATE  (/  -3  2) is  -1  -1/2
'CEILING   (/  -3  2) is  -1  -1/2
'ROUND     (/  -3  2) is  -2   1/2
'FLOOR     (/   4  2) is   2     0
'TRUNCATE  (/   4  2) is   2     0
'CEILING   (/   4  2) is   2     0
'ROUND     (/   4  2) is   2     0

2014年2月14日

clispはスクリプトとして実行できる

こりゃ便利だな
ファイルの先頭に

#!/usr/local/bin/clisp

とか追加してファイルに実行権限つけるとそのまま実行できるって便利だな

まだまだ未熟者のみにはいちいちコンパイルして実行してってやらなくてすむのは大変ありがたいですね

2014年2月13日

Erlangの文法は難しい

セミコロン、カンマ、ピリオドの使い分けが難しい
なかなか慣れない馴染まない
関数節がセミコロン区切り

と思っていたら「;」はor、「,」はand、「.」は終了とすると覚えやすいのだってね