# ENIGMA Development Environment

 Pages: 1
 Author Topic: "Choose" statement  (Read 5610 times)
fredcobain
 Posted on: July 03, 2011, 04:15:35 PM

Location: Brazil
Joined: Apr 2011
Posts: 40

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
 Logged
IsmAvatar
 Reply #1 Posted on: July 03, 2011, 04:36:24 PM

LateralGM Developer

Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 886

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.
 Logged
fredcobain
 Reply #2 Posted on: July 03, 2011, 04:59:37 PM

Location: Brazil
Joined: Apr 2011
Posts: 40

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) ?

 Logged
Josh @ Dreamland
 Reply #3 Posted on: July 03, 2011, 05:13:10 PM

Prince of all Goldfish

Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

ENIGMA will have one shortly. I need to make modifications to the syntax checker to allow functions to accept enigma::varargs.
 Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
RetroX
 Reply #4 Posted on: July 04, 2011, 11:53:55 AM

Master of all things Linux

Location: US
Joined: Apr 2008
Posts: 1055

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.
 Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars?
IsmAvatar
 Reply #5 Posted on: July 06, 2011, 04:45:02 PM

LateralGM Developer

Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 886

I suppose, yes, pigeonholing, if done right, would be no less efficient than inlines.
 Logged
TheExDeus
 Reply #6 Posted on: July 08, 2011, 10:25:03 AM

Joined: Apr 2008
Posts: 1872

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.
 « Last Edit: July 08, 2011, 10:31:45 AM by HaRRiKiRi » Logged
Josh @ Dreamland
 Reply #7 Posted on: July 08, 2011, 11:39:23 AM

Prince of all Goldfish

Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

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.
 Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
TheExDeus
 Reply #8 Posted on: July 08, 2011, 02:14:12 PM

Joined: Apr 2008
Posts: 1872

Quote
stdargs.h will kill the program if you pass it a var or a variant.
Yeah, that is what I meant.
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.
 « Last Edit: July 08, 2011, 04:23:56 PM by HaRRiKiRi » Logged
Josh @ Dreamland
 Reply #9 Posted on: July 08, 2011, 02:27:42 PM

Prince of all Goldfish

Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

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.
 Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
TheExDeus
 Reply #10 Posted on: July 08, 2011, 03:10:15 PM

Joined: Apr 2008
Posts: 1872

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. 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.
 « Last Edit: July 08, 2011, 04:24:08 PM by HaRRiKiRi » Logged
Josh @ Dreamland
 Reply #11 Posted on: July 08, 2011, 03:16:40 PM

Prince of all Goldfish

Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

Ah; you've stumbled on a way to make ENIGMA honor max() having unlimited parameters.
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().
 « Last Edit: July 08, 2011, 03:23:51 PM by Josh @ Dreamland » Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
RetroX
 Reply #12 Posted on: July 08, 2011, 09:03:13 PM

Master of all things Linux

Location: US
Joined: Apr 2008
Posts: 1055

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.
 « Last Edit: July 08, 2011, 09:05:15 PM by RetroX » Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars?
RetroX
 Reply #13 Posted on: July 11, 2011, 12:45:07 PM

Master of all things Linux

Location: US
Joined: Apr 2008
Posts: 1055

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. :/
 Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars?
 Pages: 1