# ENIGMA Forums

## Contributing to ENIGMA => Function Peer Review => Topic started by: fredcobain on July 03, 2011, 04:15:35 pm

Title: "Choose" statement
Post by: fredcobain on July 03, 2011, 04:15:35 pm
Guys, in GM we have a very usefull built-in function called "choose()";

From GM Help: choose(val1,val2,val3,...) Returns one of the arguments choosen randomly. The function can have up to 16 arguments

I'd like to see some suggestions to perform the same results in Enigma.

Thanks

Fred
Title: Re: "Choose" statement
Post by: IsmAvatar on July 03, 2011, 04:36:24 pm
pigeonhole each of the options, then choose one with random(n). This is a simple but somewhat inefficient way to do it.

A more efficient way to do it would be the same way we plan on implementing max, which also isn't implemented at this point.

max(a) = a
max(a,b) = a > b ? a : b;
max(a,b,c) = max(a,max(b,c));
max(a,b,c,d) = max(a,max(b,max(c,d)))

likewise, instead of doing the > comparator for the secondary base case, you'd simply do a random() > 0.5 type of thing.
Title: Re: "Choose" statement
Post by: fredcobain on July 03, 2011, 04:59:37 pm
pigeonhole each of the options, then choose one with random(n). This is a simple but somewhat inefficient way to do it.

A more efficient way to do it would be the same way we plan on implementing max, which also isn't implemented at this point.

max(a) = a
max(a,b) = a > b ? a : b;
max(a,b,c) = max(a,max(b,c));
max(a,b,c,d) = max(a,max(b,max(c,d)))

likewise, instead of doing the > comparator for the secondary base case, you'd simply do a random() > 0.5 type of thing.

mmm... interesting...

does the functions round() and random() are  is implemented in enigma  (built in) ?

Title: Re: "Choose" statement
Post by: Josh @ Dreamland on July 03, 2011, 05:13:10 pm
ENIGMA will have one shortly. I need to make modifications to the syntax checker to allow functions to accept enigma::varargs.
Title: Re: "Choose" statement
Post by: RetroX on July 04, 2011, 11:53:55 am
pigeonhole each of the options, then choose one with random(n). This is a simple but somewhat inefficient way to do it.

A more efficient way to do it would be the same way we plan on implementing max, which also isn't implemented at this point.

max(a) = a
max(a,b) = a > b ? a : b;
max(a,b,c) = max(a,max(b,c));
max(a,b,c,d) = max(a,max(b,max(c,d)))

likewise, instead of doing the > comparator for the secondary base case, you'd simply do a random() > 0.5 type of thing.
I don't get how this is more efficient.
Title: Re: "Choose" statement
Post by: IsmAvatar on July 06, 2011, 04:45:02 pm
I suppose, yes, pigeonholing, if done right, would be no less efficient than inlines.
Title: Re: "Choose" statement
Post by: TheExDeus on July 08, 2011, 10:25:03 am
Why can't we use stdarg.h? Is this nested max() is really better than this:
Code: [Select]
`double max(int n, ...){        double max, tmp;        va_list ap;        va_start(ap, n);        max = va_arg(ap, double);        for(int i = 2; i <= n_args; i++) {                if((tmp = va_arg(ap, double)) > max)                        max = tmp;        }        va_end(ap);        return max;}`
edit: Didn't see this:
Quote
ENIGMA will have one shortly. I need to make modifications to the syntax checker to allow functions to accept enigma::varargs.
And whats the difference exactly between this and stdarg.h provided functionality? I guess its that Josh's thing uses variants, so I don't need to cast to double or something. So max like this:
max(int 5, double 3.14) would return integer, while this:
max(int 5, double 6) would return a double. Using the simple stdarg would only return doubles or integers.

edit: Also, if doesn't really do what I think it does, then can we finally implement them with stdarg? Its like 10min of work to implement max, min, average, median and so on. Thous are some basic functions I really need.
Title: Re: "Choose" statement
Post by: Josh @ Dreamland on July 08, 2011, 11:39:23 am
For starters, HaRRi, stdargs.h will kill the program if you pass it a var or a variant.
Also, good luck getting the argument count.
Title: Re: "Choose" statement
Post by: TheExDeus on July 08, 2011, 02:14:12 pm
Quote
stdargs.h will kill the program if you pass it a var or a variant.
Yeah, that is what I meant. :D
Quote
Also, good luck getting the argument count.
Indeed, though if you made compiler parse this:
Quote
max(10,25,34.2);
into this:
Quote
max(4,10,25,34.2);
where the first argument is the argument number, then stdargs.h could be used. You already parse that string into this:
Code: [Select]
`max(varargs(), (varargs(), 10, 25, 34.2));`, so it seems that you can do it (and arguments are counted anyway for error reporting purposes, but I guess GCC is the one that does it).
Also, it seems that you have implemented the max function, but its chaotic in that definitions in mathc.h and .cpp are not used, but required. So if I delete max(double x,double y){ return fmax(x,y);   }, I will get an error, while the function itself isn't called. Also, it will take only 3 arguments if its written like that. I still need to change it into:
Code: [Select]
`double max(double numbers, ...){}` to take any number of arguments and still work.

edit: Also, if max(10,25,34.2) is called then it will return 34, not 34.2.
edit2: And I would want to study your method on how you implemented max, so I can add median and others.
edit3: Also, if it seems I'm just mumbling then ignore me. I'm in a habit of not explaining myself clearly.
Title: Re: "Choose" statement
Post by: Josh @ Dreamland on July 08, 2011, 02:27:42 pm
max(varargs(), (varargs(), 10, 25, 34.2)); is incorrect; the string should come out as
max((varargs(), 10, 25, 34.2));

But I don't parse that.
#define max(x...) max((varargs(),x))

and #define won't give me the number of arguments passed.

Again, double max(double numbers, ...){} won't work. It will kill the program as soon as the user calls max(somevar,someothervar). That wasn't a joke. It's possible that C++0x offers a functionality to overload an stdargs pass, but I don't know how well it is supported.
Title: Re: "Choose" statement
Post by: TheExDeus on July 08, 2011, 03:10:15 pm
Quote
is incorrect; the string should come out as
It still works though.

Quote
Again, double max(double numbers, ...){} won't work.
That was actually the whole working code. :D I have this in mathnc.h:
Code: [Select]
`double max(double n, ...);`And this in mathnc.cpp:
Code: [Select]
`#include "stdarg.h"double max(double n, ...){}`So nothing inside the function. And when I do this in EDL:
Code: [Select]
`draw_text(100,100,string(max(12,329,21,343,1000,2981)));`It correctly draws 2981. And IDE_EDIT_objectfunctionality.h has it parsed like this:
Code: [Select]
`draw_text(100, 100, toString(max(varargs(), (varargs(), 12, 329, 21, 343, 1000, 2981))));`That is why its weird. I don't have any code inside that would actually do the comparing, but it still works. On the other hand if I deleted the code from mathnc.cpp it would trow an error saying that the function max is undefined.
Title: Re: "Choose" statement
Post by: Josh @ Dreamland on July 08, 2011, 03:16:40 pm
Ah; you've stumbled on a way to make ENIGMA honor max() having unlimited parameters. :P
That's... typically kind of dangerous, but I guess it's as good a hack as any. For the time being, you can implement those functions like this:

Code: (C++) [Select]
`variant choose(...);int choose(const enigma::varargs& args) {   return args.get(rand() % args.argc);}#define choose(x...) choose((varargs(), x))`
You must declare and implement choose before defining it. In the source, you may be wise to #undef choose, then implement it. DO NOT implement choose(...); it's too segfault-prone. This way, worst-case scenario is link error, not random abort().
Title: Re: "Choose" statement
Post by: RetroX on July 08, 2011, 09:03:13 pm
It is possible to do choose() with variadic templates, but probably not very efficiently:

Code: [Select]
`template<typename... types>  double choose(types... vals)  {    return choose_impl(random(sizeof...(vals)), vals...);  }template<typename... types>  double choose_impl(unsigned counter, double head, types... vals)  {    return counter == 0 ? head : choose_impl(counter - 1, vals...);  }`
Untested, but should work.  And requires the -std=gnu++0x flag.  Also will give very odd errors if you have arguments that can't cast to double.
Title: Re: "Choose" statement
Post by: RetroX on July 11, 2011, 12:45:07 pm
Bump because I thought of a better idea.

Parse choose(x, y, z...) to choose({x, y, z...}).

And have some code:
Code: [Select]
`template<unsigned n> inline double choose(double vals[n]){  return vals[random(n)];}`
EDIT: Fix the [tt] tag. :/