2011年11月20日星期日

算24【备份】

以前写过,不过这次应该代码好看些了吧。
#!python2
from itertools import *
from operator import *
calc24 = lambda a,b,c,d:list(set(sum((
(o(p(i,q(j,k)),l)==24 and ["(%s%s(%s%s%s))%s%s"%s] or [])+
(o(i,p(q(j,k),l))==24 and ["%s%s((%s%s%s)%s%s)"%s] or [])+
(o(i,p(j,q(k,l)))==24 and ["%s%s(%s%s(%s%s%s))"%s] or [])+
(o(p(i,j),q(k,l))==24 and ["(%s%s%s)%s(%s%s%s)"%s] or [])+
(o(p(q(i,j),k),l)==24 and ["(((%s%s%s)%s%s)%s%s)"%s] or [])
for nums,opp in [((a,b,c,d),(add,sub,mul,lambda x,y:truediv(x,y) if y else float('nan')))]
for j,i,k,l in permutations(nums) for o,p,q in product(opp,repeat=3)
for r in [dict(zip(opp,("+","-","*","/")))] for s in [(i,r[o],j,r[p],k,r[q],l)]),[])))

>>> calc24(6,6,6,6)
['6+((6+6)+6)', '(((6+6)+6)+6)', '(6+(6+6))+6', '(6+6)+(6+6)', '(((6-6)-6)*6)', '(6-6)*(6+6)', '6+(6+(6+6))']
>>> calc24(2,3,8,9)
['(8/(9*3))-2', '8/(2/(9-3))', '8*(9-(2*3))', '8*((9/3)-2)', '(((9*3)/2)-8)', '(8*2)/(9-3)', '(((9/3)*8)-2)', '(9/3)-(2/8)', '(9*3)-(8/2)', '8*(9-(3*2))', '(9*(3-2))*8', '(9*(2-3))*8']

下面这个考虑了交换律的重复。故意写个很累赘的样子,
而且为了吻合IEEE还把mapcan和format等等都替换了一下。
(define (calc24 a b c d)
  (define (flat-map p x)
    (apply append (map p x)))
  (define (filter p x)
    (cond ((null? x) '())
          ((p (car x)) (cons (car x) (filter p (cdr x))))
          (else (filter p (cdr x)))))
  (define (drop-one x lst)
    (cond ((null? lst) '())
          ((equal? x (car lst)) (cdr lst))
          (else (cons (car lst) (drop-one x (cdr lst))))))
  (define (perm lst)
    (if (null? lst)
        '(())
        (flat-map
         (lambda (x)
           (map (lambda (y) (cons x y))
                (perm (drop-one x lst))))
         lst)))
  (define (pow lst n)
    (if (zero? n) '(())
        (flat-map
         (lambda (x)
           (map (lambda (y) (cons x y))
                (pow lst (- n 1))))
         lst)))
  (define (buld-exp num ops)
    (apply
     (lambda (i j k l)
       (apply
        (lambda (o p q)
          (list
           `(,o (,p ,i ,j) (,q ,k ,l))
           `(,o (,p ,i (,q ,j ,k)) ,l)))
        ops))
     num))
  (define (eval-exp exp)
    (if (list? exp)
        (let ((arg (map eval-exp (cdr exp)))
              (/ (lambda (x y)
                   (if (zero? y) +nan.0 (/ x y)))))
          (case (car exp)
            ((+) (apply + arg))
            ((-) (apply - arg))
            ((*) (apply * arg))
            ((/) (apply / arg))
            ((--) (apply - (reverse arg)))
            ((//) (apply / (reverse arg)))
            (else (error "op?"))))
        exp))
  (define (show-exp exp)
    (define (bin-op-str op arg)
      (apply (lambda (x y)
               (string-append "(" x op y ")"))
             (map (lambda (x)
                    (if (number? x) (number->string x) x)) arg)))
    (if (list? exp)
        (let ((arg (map show-exp (cdr exp)))
              (/ (lambda (x y) (if (zero? y) +nan.0 (/ x y)))))
          (case (car exp)
            ((+) (bin-op-str "+" arg))
            ((-) (bin-op-str "-" arg))
            ((*) (bin-op-str "*" arg))
            ((/) (bin-op-str "/" arg))
            ((--) (bin-op-str "-" (reverse arg)))
            ((//) (bin-op-str "/" (reverse arg)))
            (else (error "op?"))))
        exp))
  (define (unique lst)
    (if (null? lst) '()
        (cons (car lst)
              (unique
               (filter (lambda (x)
                         (not (equal? x (car lst)))) lst)))))
  (unique
   (flat-map
    (lambda (x)
      (flat-map
       (lambda (y)
         (flat-map
          (lambda (z)
            (if (= 24 (eval-exp z))
                (list (show-exp z))
                '()))
          (buld-exp x y)))
       (pow '(+ - * / -- //) 3)))
    (perm (list a b c d)))))

(calc24 2 3 8 9)
("(((9-3)/2)*8)" "(8/(2/(9-3)))" "((8/2)*(9-3))" "((9-3)/(2/8))" "((9-3)*(8/2))" "((8*(9-3))/2)" "((9-(2*3))*8)" "((9-(3*2))*8)")
(calc24 6 6 6 6)
("((6+6)+(6+6))" "((6+(6+6))+6)" "((6*6)-(6+6))" "(((6*6)-6)-6)")

更多的不同语言写的可以看这个:
http://rosettacode.org/wiki/24_game/Solve

乱如备份下平时在npp里面用来插入行首空格的东西。
能用,不过貌似可能会干出多余的事情来,比如不仅仅是行首的情况。
另外使用前务必先用一下npp自带的转义& < > "的菜单命令。
editor.pyreplace(r"^ ", r"&nbsp;")
def s():editor.pysearch(r"&nbsp; " ,lambda x,y:rp())
def rp():editor.pyreplace(r"&nbsp; ", r"&nbsp;&nbsp;") and False or s()
s()


如果要变成算24的游戏的话,还要一个随机数生成,和表达式计算的东西。

没有评论: