TheManaDrain.com
September 25, 2025, 06:44:51 pm *
Welcome, Guest. Please login or register.

Login with username, password and session length
News:
 
   Home   Help Search Calendar Login Register  
Poll
Question: Will you...  (Voting closed: February 15, 2004, 11:00:28 pm)
use this only as an user - 5 (62.5%)
also help development - 0 (0%)
never touch this thing, even with a ten foot pole - 3 (37.5%)
Total Voters: 7

Pages: [1]
  Print  
Author Topic: A Statistical Analysis Tool for MtG  (Read 1574 times)
Sylvester
Full Members
Basic User
***
Posts: 68

29847563
View Profile
« on: February 15, 2004, 11:00:28 pm »

Having a little too much time on my hands, i wrote this stub of an usable tool while watching a horrid show with my sister. Smile It's written in Common Lisp, though porting it to Scheme should be trivial. A fairly easy to use CL compiler (bytecode) can be found at http://clisp.cons.org. It is relatively slow, being compiled to a VM, but is available on many platforms. Of course, other implementations can be used on other platforms, and they'll almost always be much more efficient (google for CMUCL, or SBCL - there are also a couple proprietary implementations).

It currently isn't very usable, but i intend to add user-friendliness (UI and macros) later. What we DO have are the functions above which it will be added. As usual in many Lisp applications, we simply define our own application-specific mini language on top of Lisp.

I'm not quite sure of the style, but even if i have to change that, the basic architecture of the thing should remain constant. I will also read at least one book on stochastic analysis (since it's somewhere in my basement), to make sure i'm not making any kind of mistake that could introduce bias, find places for improvement, etc.

Code:

--------mtg-montecarlo.lisp--------
(defun lstdesc2lst (alist)
  "List Description To List: Transform an alist list description to a flat list"
  (mapcan #'(lambda (pair) (make-list (cdr pair) :initial-element (car pair))) alist))

(defun swap (lst a b)
  "Swap a list's a'th and b'th elements *0-indexing* . Rewrite so as not to walk list twice."
  (labels ((fn (lst value rank acc)
 (if (= 0 rank)
     (append (nreverse acc) (list value) (cdr lst))
   (fn (cdr lst) value (1- rank) (push (car lst) acc)))))
 (let ((valuea (nth a lst))
(valueb (nth b lst)))
   (fn (fn lst valueb a nil) valuea b nil))))

(defun shuffle (lst n)
  "Shuffles a list n times by swapping 2 random elements"
  (labels ((fn (lst len n)
      (if (= 0 n)
  lst
(fn (swap lst (random len) (random len)) len (1- n)))))
    (fn lst (length lst) n)))

(defun upd-or-ins (alist key &key init upd)
  "Update or Insert : If key in alist, update its cdr w/ fn, else insert new couple (key . init).
   init is inserted as a value. fn is funcall'ed w/ the current value as argument."
  (let ((cpl (assoc key alist)))
    (if cpl
(setf (cdr couple) (funcall fn (cdr couple)))
      (setq alist (acons key init alist)))
    alist))

(defun calc2 (deck n &key score shuffle init-res)
  "score: scoring fxn (score deck res) returns result and deck;
   shuffle: shuffling fxn (shuffle deck) returns a deck;
   init-res: initial result value."
  (let ((res init-res))
    (dotimes (i n res)
      (multiple-value-bind (inner-res inner-deck)
 (funcall score (funcall shuffle deck) res)
(setq res inner-res)
(unless (null inner-deck) (setq deck inner-deck))))))

;------end of the application part/beginning of the test----

(defun score (lst res)
  "Res++ if the first card is 'a'"
  (if (eq 'a (car lst))
      (1+ res)
    res))


(defun test ()
  (calc2 (lstdesc2lst '((a . 1) (b . 19))) 1000 :score #'score :shuffle #'(lambda (lst) (shuffle lst 100)) :init-res 0))
;;;Usually returns something between 47 and 52 (ideally returns 50)

-------end of file-------



Now, most of the applications should be sort of well described, but i understand that more details are needed Smile

Decks are described as an associative list:
((CardName . Count) (CardName . Count) ...)
Where Count is the number of "CardName" in the deck.

Thus, (lstdesc2lst '((a . 1) (b . 19))) returns (A B B B B B B B B B B B B B B B B B B B), ie, a list composed of 1 A and 19 B.

-> This will need to be made easier. I'll probably have a text-based interface to output  the deck description.

Shuffle is a function that takes a deck (a list) and randomly swaps two elements in it n times. 66% of the time spent in the test function is actually spent shuffling - it obviously needs to be optimized, or, rather, the swap function must be optimised. As it is, it traverses the deck TWICE, but it's only a kludge until i understand why the normal way of making it doesn'T wanna work Smile I must also make sure its shuffling doesn't introduce any bias. If anyone can find me a simpler shuffler, please tell me Smile

upd-or-ins will be used for more complex scoring, i'll have examples later.

calc2 is the heart of the tool. It's actually a quite simple function that is there only for convenience's sake, since, after all, our application itself is simple. See the comments for a description of its arguments. It also needs a new name.

The other place where user-friendliness could be added is in building scoring functions. A scoring function could look like:
Code:

(lambda (deck res)
  (let ((hand (nbutlast deck (- 7 (length deck)))))
     (cond ((and (member 'CardA hand) (member 'CardB hand)) (upd-or-ins res 'Combo1 :init 1 :upd #'1+))
              ((and (member 'CardC hand) (member 'CardD hand)) (upd-or-ins res 'Combo2 :init 2 :upd #'1+))
              (T res))))


Note, untested, and badly hand-formatted Smile It looks at the 7 top-most cards of the deck. If at least one of both CardA and CardB are there, it adds one to the current count of Combo1 occuring, initialising it to 1 if it doesn't already exist. If not, then it does the same for Combo2 if both CardC and CardD are present. It doesn't return a deck, so it is assumed the deck isn't modified... I'm not even sure what i'd use this feature of permanently modifying the deck for. It'll probably be removed in the next iteration.

Comments? Suggestions for a couple changes to function names?
Logged
Matt
Post like a butterfly, Mod like a bee.
Adepts
Basic User
****
Posts: 2297


King of the Jews!


View Profile
« Reply #1 on: February 15, 2004, 11:35:55 pm »

How is this different from the statistical tools MWS comes with?
Logged

http://www.goodgamery.com/pmo/c025.GIF
----------------------
SpenceForHire2k7: Its unessisary
SpenceForHire2k7: only spelled right
SpenceForHire2k7: <= world english teach evar
----------------------
noitcelfeRmaeT
{Team Hindsight}
Sylvester
Full Members
Basic User
***
Posts: 68

29847563
View Profile
« Reply #2 on: February 15, 2004, 11:46:05 pm »

Much more powerful. For example, i can easily make it work with mulligans or even that card which alters mulligans.
Logged
rvs
cybernetically enhanced
Full Members
Basic User
***
Posts: 2083


You can never have enough Fling!

morfling@chello.nl MoreFling1983NL
View Profile WWW Email
« Reply #3 on: February 16, 2004, 03:04:44 am »

hmm... maybe with an eleven-foot pole, I could try it .... :p
Logged

I can break chairs, therefore I am greater than you.

Team ISP: And as a finishing touch, god created The Dutch!
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.316 seconds with 21 queries.