Re: do-random-weighted macro



I am in the process of learning lisp.

Welcome to c.l.l.

It all started with a function to calculate how many hits
a side gets in the Attack! combat system.

So presumably a player rolls the dice, and something happens
depending on the value.

I was just trying to learn lisp and see how simple
I could make this problem.

Good idea.

I ended up writing a function that, given an indefinite number of
pairs, where the first item in the pair is the weight, and the second
item is a function representing the action, select one of the items
randomly and do it.

(do-random-weighted (1 nil) (1 :s) (1 :a) (1 :t) (2 :p))
=> :p shows up 2/6 of the time, nil, :s, :a, and :t 1/6 each.

Separate the search from the randomization:

(defun weighted-nth (n-trigr pairs)
(let ((n-accum 0))
(dolist (pair pairs)
(if (>= n-accum n-trigr)
(return-from weighted-nth (cdr pair))
(incf n-accum (car pair))))))

(defmacro do-randoms ((n max num-vals) &body body)
(let ((_ (gensym)))
`(dotimes (,_ ,num-vals)
(let ((,n (random ,max))) ,@body))))

Since this function required me to write a lot of
lambda expressions, I thought maybe there was a better
way to do it. So I started to learn how to do macros.

(1 (print "Rolled soldier")
(when (plusp soldiers)
(print " ...hit")
(incf hits)
(decf soldiers)))
...

There's a lot of duplication here. You might as well
wrap the code in a function and the data in some
variables:

(defun process-roll (symbol string countable)
(cond ((plusp (symbol-value symbol))
(format t "You hit ~:[a~;~] ~A!~%" countable string)
(incf *hits*)
(decf (symbol-value symbol)))
(t
(if countable
(format t "Sorry, there are no ~As left.~%" string)
(format t "Sorry, there's no ~A left.~%" string)))))

(defvar *hits*)
(setf *hits* 0)
(defvar *weighted-forces*)
(setf *weighted-forces*
'((1 soldiers "soldier" t )
(1 tanks "tank" t )
(1 artillery "artillery" nil)
(2 planes "plane" t )))

(roll-hits 1 1 1 1)
(roll-hits 2 0 2 0)

Now you can have the program generate random numbers
for you, and feed them to the function that uses them:

(defun init-forces ()
(setf *hits* 0)
(set 'soldiers 10)
(set 'tanks 1)
(set 'artillery 2)
(set 'planes 1))

(defun total-weight (pairs) (reduce #'+ pairs :key #'car))

(defun multiroll (num-rolls pairs)
(do-randoms (n (total-weight pairs) num-rolls)
(let ((val (weighted-nth n pairs)))
(if val
(process-roll (car val) (cadr val) (caddr val))
(write-line "Sorry, no dice.")))))

And test the code:

(defun mr ()
(init-forces)
(multiroll 20 *weighted-forces*))

CL-USER> (mr)
You hit a tank!
You hit a plane!
You hit artillery!
Sorry, there are no tanks left.
You hit artillery!
Sorry, there's no artillery left.
Sorry, there are no tanks left.
Sorry, there's no artillery left.
Sorry, there are no planes left.
Sorry, there are no planes left.
Sorry, there are no planes left.
Sorry, there are no planes left.
Sorry, there are no planes left.
You hit a soldier!
You hit a soldier!
Sorry, there are no planes left.
Sorry, there are no tanks left.
You hit a soldier!
You hit a soldier!
Sorry, there are no tanks left.

Comments? Suggestions?

Don't use macros to operate on data. If the code you want
to call varies enough, and isn't selected until runtime, use
lambdas and funcall to call the right function. Macros are used
to hide code patterns that you would otherwise have to type
or paste repeatedly into your source file(s).

Note that I couldn't see a way around eval.
Is this a legitimate use of eval or do I need to do
something else?

Something else. EVAL is almost never necessary.

--Dan

------------------------------------------------
Dan Bensen
http://www.prairienet.org/~dsb/
.



Relevant Pages

  • RGP LONER 9-11?
    ... What happened to all the people on all the planes that did not hit WTC? ... Why has not one single piece of demolition equipment or residue been found ... If a missile hit Pentagon, how did the wreckage of a plane engine get to ...
    (rec.gambling.poker)
  • Re: Scientists for 9/11 Truth
    ... A plane hit the Pentagon. ... The "Hijackers" were electronic. ... So you claim that there were no hijackers on any of the planes? ...
    (sci.physics)
  • Re: Pentagon Flight 77 on 9/11/01 Where did all the people/plane/wreckage go?
    ... of their targets and were on track to hit 100% of their targets. ... planes, it wasn't like a group of terrorists found themselves on the ... it seems more likely that these rookies would have gotten lost then ...
    (rec.music.gdead)
  • Re: France shoots down Libyan plane
    ... Darkness isn't really much protection any more, ... attack planes usually have FLIR. ... Especially tanks, who retain their heat for a long time, after the sun goes ... destruction has led to a recovery of the rebel forces. ...
    (soc.retirement)
  • Re: Sherman tank engines
    ... I'd just assumed most tanks were diesel. ... Were Shermans death traps ... when hit? ... Also recall that most German tanks were petrol engined. ...
    (sci.military.naval)