Guest User

Untitled

a guest
Mar 18th, 2012
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scheme 8.17 KB | None | 0 0
  1. ;(module metadice
  2. ;        mzscheme
  3. (begin
  4. (require (lib "pregexp.ss"))
  5. (require (lib "list.ss"))
  6. (require (rename (lib "1/list.ss" "srfi") every every))
  7. (require (rename (lib "1/list.ss" "srfi") take-while take-while))
  8. (require (rename (lib "1/list.ss" "srfi") drop-while drop-while))
  9. (require (rename (lib "1/list.ss" "srfi") find find))
  10.  
  11. ; This is a porting of the syntax of bananabot, but not the implementation. This implementation has several goals:
  12. ; * Learn Scheme
  13. ; * Write a completely declarative, useful program
  14. ; * Reimplement all this logic the way it should have been done in the first place, without stupid regexp hacks.
  15.  
  16.  
  17.  
  18.  
  19. ;;;;;;;;;; Dice implementation ;;;;;;;;;;
  20.  
  21. ; The basic "roll a die" procedure
  22. (define (die x)
  23.   (+ 1 (random x)))          
  24.  
  25. ; As above, but exploding on max roll
  26. (define (wild-die x)
  27.   (let ((roll (+ 1 (random x))))
  28.     (if (not (= roll x))
  29.         roll
  30.         (+ roll (wild-die x)))))
  31.    
  32. ; Roll more than one die. 100000 seems to be the upper limit of x; that takes 2-4 seconds.
  33. (define (dice x y)
  34.   (case x
  35.     ((0) 0)
  36.     ((1) (die y))
  37.     (else (+ (die y) (dice (- x 1) y)))))
  38.  
  39. ; A common type of roll in some systems - one die wild, the others normal.
  40. (define (open-dice x y)
  41.   (+ (wild-die y) (dice (- x 1) y)))
  42.  
  43.  
  44.  
  45.  
  46. ;;;;;;;;;; Parsing implementation ;;;;;;;;;;
  47.  
  48. (define operators (list "\\+" "-" "\\(" "\\)" "d" "o" "\\*" "/" "\\^" "\\\\" "%" "#" ","))
  49. (define literals (list "\\d+"))
  50.  
  51. ; this section is a program really I mean it does lots of calculations and stuff but TECHNICALLY these are constants ;_;
  52. ; Seriously, they are at least only calculated once, rather than every line of input. That's something.
  53. ; however the way the frontend currently works it is useless
  54. (define valid-tokens (append operators literals))
  55. (define re-validator (pregexp (foldr
  56.                                (lambda (x y)
  57.                                  (string-append x "|" y))
  58.                                (car valid-tokens)
  59.                                (cdr valid-tokens))))
  60. (define re-literal-validator (pregexp (foldr
  61.                                (lambda (x y)
  62.                                  (string-append x "|" y))
  63.                                (car literals)
  64.                                (cdr literals))))
  65.  
  66. ; Does this really need to be a seperate procedure? Only to keep core logic out of the main loop.
  67. (define pregexp-match*
  68.    (lambda (regex string)
  69.      (letrec
  70.          ((pregexp-match*
  71.            (lambda (regex string pos)
  72.              (let ((endpos (pregexp-match-positions regex string pos)))
  73.                (if (eq? endpos #f) '()
  74.                    (cons (pregexp-match regex string pos)
  75.                          (pregexp-match* regex string (cdar endpos))))))))
  76.        (pregexp-match* regex string 0))))
  77. (define (tokenize s)
  78.   (map car (pregexp-match* re-validator s)))
  79.  
  80. ; ugh this works in such a stupid way because and is a stupid special form instead of, I don't know, A PROCEDURE
  81. (define (validate l)
  82.   (every (lambda (x) (car (pregexp-match re-validator x)))
  83.          l))
  84.  
  85. ; Give this function a constant or a special case - something to hand to the dice engine
  86. ; Die handing should be in the parser, because 3d6 is a valid number.
  87. ; Scheme thinks it's 3.000000 :( It's even an integer!
  88. (define (handle-literal x)
  89.   (cond
  90.     ((list? x) (map handle-literal x))
  91.     ((pregexp-match "\\d+d\\d+" x)
  92.      (let* ((ns (pregexp-split "d" x))
  93.             (n (string->number (car ns)))
  94.             (s (string->number (cadr ns))))
  95.        (dice n s)))
  96.     ((number? (string->number x)) (string->number x))
  97.     (else "error: unrecognised literal")))
  98.  
  99. ; Multiplex rolls - n is number
  100. (define (multi n t)
  101.   (case n
  102.     ((0) '())
  103.     ((1) (list t))
  104.     (else (cons t
  105.                 (multi (- n 1) t)))))
  106. (define (rmulti t n) (multi n t))
  107.  
  108.  
  109.  
  110. ; parsing logic prototype:
  111. ; ARGUMENTS a list of valid tokens
  112. ; RETURN the result of calculation
  113. ; so we have a huge case statement (no Haskell pattern-matching :() and recurse
  114. (define maybe-map-3 (lambda (f x y)
  115.                     (if (list? y)
  116.                         (map (lambda (y) (f x y))
  117.                              y)
  118.                         (if (list? x)
  119.                             (map (lambda (x) (f x y))
  120.                                  x)
  121.                             (f x y)))))
  122.  
  123. (define maybe-map-2 (lambda (f x)
  124.                       (if (list? x)
  125.                           (maybe-map-3 maybe-map-2 f x)
  126.                           (f x))))
  127.  
  128. (define (str=? s x)
  129.         (if (list? s)
  130.             (every (lambda (s) (equal? x #t))
  131.                    (map (lambda (s) (string=? s x))
  132.                         s))
  133.             (string=? s x)))
  134.  
  135. (define (parse l)
  136.   (let* ((operate (lambda (x f)
  137.                   (maybe-map-3 f
  138.                              (parse (take-while
  139.                                      (lambda (s) (not (str=? s x)))
  140.                                      l))
  141.                              (parse (cdr (drop-while
  142.                                           (lambda (s) (not (str=? s x)))
  143.                                           l))))))
  144.          (check (lambda (x)
  145.                 (find (lambda (s) (str=? s x))
  146.                       l)))
  147.          (replace-deepest-parantheses (lambda (xs)
  148.                                         (let* ((rpre (reverse (take-while
  149.                                                      (lambda (s) (not (str=? s ")")))
  150.                                                      xs)))
  151.                                                (post (cdr (drop-while
  152.                                                            (lambda (s) (not (str=? s ")")))
  153.                                                            xs)))
  154.                                                (mid (reverse (take-while
  155.                                                               (lambda (s) (not (str=? s "(")))
  156.                                                               rpre)))
  157.                                                (pre (reverse (cdr (drop-while
  158.                                                               (lambda (s) (not (str=? s "(")))
  159.                                                               rpre)))))
  160.                                           (append pre (cons (maybe-map-2 number->string
  161.                                                                         (parse mid))
  162.                                                             post))))))
  163.      (cond ; Parenthesis insertion
  164.            ((check "(") (parse (replace-deepest-parantheses l)))
  165.            ; Low precendence - O(1) mathematics
  166.            ((check "+") (operate "+" +))
  167.            ((check "-") (operate "-" -))
  168.            ; Medium precedence
  169.            ((check "*") (operate "*" *))
  170.            ((check "^") (operate "^" expt))
  171.            ((check "/") (operate "/" /))
  172.            ((check "\\") (operate "\\" quotient))
  173.            ((check "%") (operate "%" remainder))
  174.            ; High precedence - dice
  175.            ((check "d") (operate "d" dice))
  176.            ((check "o") (operate "o" open-dice))
  177.            ; Multiplexing
  178.            ((check "#") (operate "#" multi))
  179.            ((check ",") (operate "," rmulti))
  180.            ; Literals
  181.            (else (handle-literal (car l))))))
  182.        
  183.        
  184.  
  185.  
  186. ;;;;;;;;;; Main ;;;;;;;;;;
  187. (if (> (vector-length argv) 0)
  188.     (let* ((raw-input (apply string-append (vector->list argv)))
  189.            (tokenized-input (tokenize raw-input)))
  190.       (display
  191.        (if (validate tokenized-input)
  192.            (parse tokenized-input)
  193.            "error: incorrect syntax"))
  194.       (newline))
  195.     (letrec
  196.         ((raw-input "")
  197.          (tokenized-input ())
  198.          (mainloop (lambda ()
  199.                      (set! raw-input (read-line))
  200.                      (if (eof-object? raw-input) ()
  201.                          (begin
  202.                            (set! tokenized-input (tokenize raw-input))
  203.                            (display
  204.                             (if (validate tokenized-input)
  205.                                 (parse tokenized-input)
  206.                                 "error: incorrect syntax"))
  207.                            (newline)
  208.                            (mainloop))))))
  209.       (mainloop))))
Advertisement
Add Comment
Please, Sign In to add comment