うーん,どっかがバグってるはず。
どもです。
現在,Problem 54 をやっていて,答えが出て,その答えが400で,
怪しいなぁと思いつつ入力したら,やっぱり不正解orz。
ユニットテスト書いてないので,どこがバグっているかわからんし,
ちと疲れたので今日はここまで。
ちなみに調べたところ,役で引き分けになるのは,
ブタ,ワンペア,ツーペア,スリーカードのいずれかのようだ。
これも怪しいがね。
以下コード。
;;;; problem 54 (defparameter *cards* (make-hash-table)) (clrhash *cards*) (loop for i from 2 to 10 do (setf (gethash (digit-char i) *cards*) i)) (setf (gethash #\J *cards*) 11) (setf (gethash #\Q *cards*) 12) (setf (gethash #\K *cards*) 13) (setf (gethash #\A *cards*) 14) (defparameter *p1-hands* nil) (defparameter *p2-hands* nil) (defun read-hands (filename) (with-open-file (is filename :direction :input) (do ((ch (read-char is nil :eof) (read-char is nil :eof)) (num) (suit) (hand) (ncard 0) (nhands 0)) ((or (eq ch :eof)) (setf *p1-hands* (nreverse *p1-hands*) *p2-hands* (nreverse *p2-hands*)) nhands) (cond ((or (char= ch #\ ) (char= ch #\Newline)) (incf ncard) (push (list num suit) hand) (cond ((= ncard 5) (push (sort hand #'< :key #'car) *p1-hands*) (incf nhands) (setf hand nil)) ((= ncard 10) (push (sort hand #'< :key #'car) *p2-hands*) (incf nhands) (setf hand nil ncard 0)))) ((or (digit-char-p ch) (char= ch #\J) (char= ch #\Q) (char= ch #\K) (char= ch #\A)) (setf num (gethash ch *cards*))) ((alpha-char-p ch) (setf suit (read (make-string-input-stream (princ-to-string ch))))))))) (defun construct-hands (filename) (setf *p1-hands* nil *p2-hands* nil) (read-hands filename)) (defun hand->rank (hand) (cond ((royal-flush-p hand) 9) ((straight-flush-p hand) 8) ((four-card-p hand) 7) ((fullhouse-p hand) 6) ((flush-p hand) 5) ((straight-p hand) 4) ((three-card-p hand) 3) ((two-pairs-p hand) 2) ((one-pair-p hand) 1) ((high-card-p hand) 0))) (defun royal-flush-p (hand) "HAND should properly be sorted." (and (every #'identity (mapcar #'eql (mapcar #'car hand) '(10 11 12 13 14))) (flush-p hand))) (defun straight-flush-p (hand) (and (straight-p hand) (flush-p hand))) (defun four-card-p (hand) (loop with nums = (mapcar #'car hand) for i in nums when (= 4 (count i nums)) return i finally (return nil))) (defun fullhouse-p (hand) (let ((three (three-card-p hand))) (if three (let ((nums (remove three (mapcar #'car hand)))) (if (= (car nums) (cadr nums)) (list three (car nums)) nil)) nil))) (defun flush-p (hand) (and (every #'eql (mapcar #'cadr hand) (cdr (mapcar #'cadr hand))) (apply #'max (mapcar #'car hand)))) (defun straight-p (hand) (and (every (lambda (n) (= n 1)) (mapcar #'- (sort (cdr (mapcar #'car hand)) #'<) (sort (mapcar #'car hand) #'<))) (apply #'max (mapcar #'car hand)))) (defun three-card-p (hand) (count-ncard-p hand 3)) (defun count-ncard-p (hand count) (loop with nums = (mapcar #'car hand) for n in nums when (= count (count n nums)) return n finally (return nil))) (defun two-pairs-p (hand) (let ((nums (mapcar #'car hand)) (ret nil)) (and (loop for n in nums when (= 2 (count n nums)) return (setf nums (remove n nums) ret (cons n ret)) finally (return nil)) (loop for n in nums when (= 2 (count n nums)) return (cons n ret) finally (return nil))))) (defun one-pair-p (hand) (count-ncard-p hand 2)) (defun high-card-p (hand) (apply #'max (mapcar #'car hand))) (defun judge-hands (hand1 hand2) "Return t if hand1 wins. Otherwise nil or -1." (let ((rank1 (hand->rank hand1)) (rank2 (hand->rank hand2))) (cond ((> rank1 rank2) t) ((< rank1 rank2) nil) (t ;; Tie (case rank1 ;; highest card (0 (high-card-tie hand1 hand2)) ;; one pair (1 (one-pair-tie hand1 hand2)) ;; two pairs (2 (two-pairs-tie hand1 hand2)) (3 (three-card-tie hand1 hand2)) (4 (straight-tie hand1 hand2)) (5 (flush-tie hand1 hand2)) (6 (fullhouse-tie hand1 hand2)) (7 (four-card-tie hand1 hand2)) (8 (straight-flush-tie hand1 hand2)) (otherwise -1)))))) (defun high-card-tie (hand1 hand2) (judge-highest (mapcar #'car hand1) (mapcar #'car hand2))) (defun judge-highest (nums1 nums2) (if (or (null nums1) (null nums2)) -1 (let ((m1 (apply #'max nums1)) (m2 (apply #'max nums2))) (cond ((> m1 m2) t) ((< m1 m2) nil) (t (judge-highest (remove m1 nums1) (remove m2 nums2))))))) (defun one-pair-tie (hand1 hand2) (let ((nums1 (mapcar #'car hand1)) (c1 (one-pair-p hand1)) (nums2 (mapcar #'car hand2)) (c2 (one-pair-p hand2))) (cond ((> c1 c2) t) ((< c1 c2) nil) (t (judge-highest (remove c1 nums1) (remove c2 nums2)))))) (defun two-pairs-tie (hand1 hand2) (let* ((nums1 (mapcar #'car hand1)) (c1 (sort (two-pairs-p hand1) #'<)) (nums2 (mapcar #'car hand2)) (c2 (sort (two-pairs-p hand2) #'<)) (ret (judge-highest c1 c2))) ;(format t "c1=~S, c2=~S~%" c1 c2) (if (not (numberp ret)) ret (judge-highest (set-difference nums1 c1) (set-difference nums2 c2))))) (defun three-card-tie (hand1 hand2) (let ((c1 (three-card-p hand1)) (c2 (three-card-p hand2))) (cond ((> c1 c2) t) ((< c1 c2) nil) (t (error "Cannot happen in three cards!!"))))) (defun straight-tie (hand1 hand2) (let ((c1 (straight-p hand1)) (c2 (straight-p hand2))) (cond ((> c1 c2) t) ((< c1 c2) nil) (t (error "Tie with straight!!"))))) (defun flush-tie (hand1 hand2) (let ((nums1 (mapcar #'car hand1)) (c1 (flush-p hand1)) (nums2 (mapcar #'car hand2)) (c2 (flush-p hand2))) (cond ((> c1 c2) t) ((< c1 c2) nil) (t (judge-highest (remove c1 nums1) (remove c2 nums2)))))) (defun fullhouse-tie (hand1 hand2) (let* ((c1 (fullhouse-p hand1)) (c2 (fullhouse-p hand2))) ;;(format t "c1=~S, c2=~S~%" c1 c2) ;; compare three cards part (> (car c1) (car c2)))) (defun four-card-tie (hand1 hand2) -1) (defun straight-flush-tie (hand1 hand2) -1) (defun euler-problem-54 () (construct-hands "poker.txt") (loop for h1 in *p1-hands* for h2 in *p2-hands* for result = (judge-hands h1 h2) with p1-wins = 0 with p2-wins = 0 when (not (numberp result)) do (if result (incf p1-wins) (incf p2-wins)) finally (return (list p1-wins p2-wins))))