Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Creating a function to pull random color of ball in lisp

9 REPLIES 9
SOLVED
Reply
Message 1 of 10
FrescoVivir
1768 Views, 9 Replies

Creating a function to pull random color of ball in lisp

Hello everyone,

 

So I just started learning lisp and I really don't have a lot of resources to do so. I have this problem that I'm trying to solve: the idea of the program is having a box with balls someone will pull a ball randomly each ball has a color the program will show the color of the ball until the box is empty it will show NIL:

 

I started working on it but due to the lack on knowledge I'm stuck in the begging this is what I wrote so far

 

    (defun get-ball (list) 

    (random (list)))    // I'm not sure if this is right or wrong I think this should return random color but it won't take the color off the list

 

    (defvar *color-of-ball*

    '("Red" "Blue" "Green" "Indigo" "white"))  // also not sure if this is the right way to define list of strings to be used later with another function or not

 

 

so when this app run it should be something like this: 

 

[1]> (get-ball *color-of-ball*) BLUE

 

[1]> (get-ball *color-of-ball*) Red

 

[1]> (get-ball *color-of-ball*) Indigo

 

[1]> (get-ball *color-of-ball*) White

 

[1]> (get-ball *color-of-ball*) Green

 

[1]> (get-ball *color-of-ball*) NIL  //since the box is empty now 

 

I'll bd thankful for any help regard solving this. 

 

 

9 REPLIES 9
Message 2 of 10
Kent1Cooper
in reply to: FrescoVivir

It would be better not to use "list" as the name of your list, since that is an AutoLISP function name.

 

Post the definition of your (random) function.  I suspect that in using it, the name of the variable containing the list should not be in parentheses.

 

Making the list looks right except for the function name, which should be (setq) rather than (defvar) [unless, perhaps, you have a defined (defvar) function that does something different from what (setq) does -- post it if you do].

Kent Cooper, AIA
Message 3 of 10
FrescoVivir
in reply to: Kent1Cooper

well I thought that Defvar *name-of-list is the way to define list of strings in Lisp. 

 

and I didn't define a function to select random color this is what I'm trying to solve here. I read somehwere that (random) infont of list can slsect random member of the list. 

 

so to define a list of strings I should use SetQ ?  can you show me how to do that in code like define a list of strings has red blue and green

 

thank you for the replay

 

 

Message 4 of 10
Kent1Cooper
in reply to: FrescoVivir

AutoLISP does not have either a (defvar) or a (random) function.  [Help will reveal whether any term is a function name.]  The functionality of the former is done by (setq), but for the latter you would have to define something, or find the somewhere you read about it and get their function definition.  If you Search these Forums you will find various routines that generate random numbers, and if one of them can generate a random integer within a specified range, it should be adaptable to help with what you're trying to do, making use of the (nth) function.

 

The (setq) function is what is used to store anything [whether a list, a text string, a number (real or integer), etc.] into a variable.  To make your list of color names, just use the correct function name in the same way you were doing it with (defvar):

 

(setq *color-of-ball* '("Red" "Blue" "Green" "Indigo" "white"))

Kent Cooper, AIA
Message 5 of 10
Lee_Mac
in reply to: FrescoVivir

Here is a function to generate a (pseudo) random number in a given range - in your case you would supply the range bounds to be 0 and the number of items in your list minus 1.

 

You would then pass the random integer returned by the function to the nth function in order to select a random colour from your list of possible colours, e.g.:

 

(defun getrandomitem ( lst )
    (nth (LM:randrange 0 (1- (length lst))) lst)
)

;; Random in Range  -  Lee Mac
;; Returns a pseudo-random integral number in a given range (inclusive)

(defun LM:randrange ( a b )
    (fix (+ a (* (LM:rand) (- b a -1))))
)

;; Rand  -  Lee Mac
;; PRNG implementing a linear congruential generator with
;; parameters derived from the book 'Numerical Recipes'

(defun LM:rand ( / a c m )
    (setq m   4294967296.0
          a   1664525.0
          c   1013904223.0
          $xn (rem (+ c (* a (cond ($xn) ((getvar 'date))))) m)
    )
    (/ $xn m)
)

 

_$ (getrandomitem '("Red" "Blue" "Green" "Indigo" "white"))
"Green"

 

As for 'defvar' et al, please note: AutoLISP =/= Common LISP!

Message 6 of 10
FrescoVivir
in reply to: Lee_Mac

thank you for the great support 

Message 7 of 10
Lee_Mac
in reply to: FrescoVivir

You're most welcome! 

Message 8 of 10
Kent1Cooper
in reply to: FrescoVivir


@FrescoVivir wrote:

....having a box with balls someone will pull a ball randomly each ball has a color the program will show the color of the ball until the box is empty it will show NIL:

.... 

    (defvar *color-of-ball*

    '("Red" "Blue" "Green" "Indigo" "white"))  // also not sure if this is the right way to define list of strings .... 

so when this app run it should be something like this: 

[1]> (get-ball *color-of-ball*) BLUE

[1]> (get-ball *color-of-ball*) Red

[1]> (get-ball *color-of-ball*) Indigo

[1]> (get-ball *color-of-ball*) White

[1]> (get-ball *color-of-ball*) Green

[1]> (get-ball *color-of-ball*) NIL  //since the box is empty now 

.... 


Here's a way to do it [with a less mathematically sophisticated randomization, but I think adequate for the purpose] including the removal of the randomly-selected item with each pass, and the nil return when the "box is empty."  It requires that their not be duplicates within the list.  The original list remains intact [it works on its own temporary copy that it truncates with each pass, until that runs out], and you can run another sequence of draws on that without re-setq'ing that list.

 

(defun grir (lst / item); = Get Random Item and Remove it from list
  (if (not *grir) ; first time
    (setq
      *grir T ; "into the system"
      *grirtr lst ; initial list for TRuncating with each run
    ); setq
  ); if
  (if *grirtr ; still anything left in it
    (setq ; then
      item (nth (rem (atoi (substr (rtos (rem (getvar 'cdate) 1) 2 17) 18 2)) (length *grirtr)) *grirtr)
      *grirtr (vl-remove item *grirtr)
    ); setq
    (setq *grir nil); reset for another series

  ); if
  item
); defun

 

I ran it, thus:

 

(setq *color-of-ball* '("Red" "Blue" "Green" "Indigo" "White"))

 

Command: (grir *color-of-ball*)
"Red"

Command: (grir *color-of-ball*)
"Green"

Command: (grir *color-of-ball*)
"Indigo"

Command: (grir *color-of-ball*)
"White"

Command: (grir *color-of-ball*)
"Blue"

Command: (grir *color-of-ball*)
nil

 

I did it again, and it returned Blue/Green/Indigo/Red/White/nil, and again, and it returned Red/Blue/White/Green/Indigo/nil, and again, Indigo/Red/Blue/Green/White/nil.

 

I ran it on a list of the integers from 1 to 13, and it returned successively 3/2/11/12/8/9/13/5/4/1/10/7/6/nil.

 

It will work on a list of up to 100 items.  [It will "work" on a longer list, but the randomization will be skewed at first -- it won't take things from past the first 100 as long as the truncated list is still longer than that.]  If you want it to work on lists of up to 1000 items, change the ... 18 2)) to ... 17 3)).

Kent Cooper, AIA
Message 9 of 10
Kent1Cooper
in reply to: Kent1Cooper


@Kent1Cooper wrote:
....Here's a way to do it .....

....

    (setq ; then
      item (nth (rem (atoi (substr (rtos (rem (getvar 'cdate) 1) 2 17) 18 2)) (length *grirtr)) *grirtr)
....

 

It will work on a list of up to 100 items.  ....  If you want it to work on lists of up to 1000 items, change the ... 18 2)) to ... 17 3)).


Mis-counted something [and didn't really need a length-of-substring argument]....  It only yields 16 decimal places.  Change this line:

 

  item (nth (rem (atoi (substr (rtos (rem (getvar 'cdate) 1) 2 17) 18 2)) (length *grirtr)) *grirtr)

 

to this instead:

 

  item (nth (rem (atoi (substr (rtos (rem (getvar 'cdate) 1) 2 16) 17)) (length *grirtr)) *grirtr)

 

and if you want it to work with lists up to 1000 items, change that 17 to 16.

 

EDIT:  But come to think of it, that depends on the DIMZIN System Variable being set to something other than 4 or 12.  Rather than force a DIMZIN setting, let's do this, so it doesn't matter whether the leading 0 is suppressed in what (rtos) returns:

  item (nth (rem (atoi (substr (rtos (rem (getvar 'cdate) 1) 2 16) 16 2)) (length *grirtr)) *grirtr)

 

and for lists of up to 1000 items, change the ... 16 2)) to ... 15 3)).

Kent Cooper, AIA
Message 10 of 10

Thanks Lee Mac, wrote one of these a decade a go, misplaced it, now it's nice to find another already written.  Shane Sparks

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

”Boost