Delegate that returns a range of numbers

jdpjdpjdp
30 Dec 2014, 05:18
Looking at the example from the wiki (http://docs.textadventures.co.uk/quest/types/using_delegates.html), we have a delegate that uses an integer as its parameter, and then two different verbs -- hit and kick -- have different integers they return. What I want to do is replace the single integer parameter for a range of values parameter, like you'd get with GetRandomInt. That way instead of "hit" always doing 4 damage and "kick" always doing 7, "hit" could do anywhere from 1-4 and "kick" from 5-8 (just examples, obviously). Can this be done? SHOULD this be done (by which I mean, is using delegates the best way to accomplish this at all)?

HegemonKhan
30 Dec 2014, 07:54
I still don't really understand delegates (when I first started quest, I think I kinda understood them, but I haven't studied them since then, lol), but a way (at least conceptually) of doing this (ignoring delegates completely, lol):

create a list based upon (for example):

x = 50
x + 5
x - 5

list: 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55

then use 'GetRandomInt' upon that list, for your damage

(I'm not sure if a list can be returned or not, such as with Function's 'return:type' capability, so you may have to do the list outside of the Function, and~or as, aka within, another Function)

Edit: whoa... I'm way overthinking this... laughs...

------------

actually.... there's a TOTALLY easier way to do what you want !!!!!!

DiceRoll ("#d#') ~ ( http://docs.textadventures.co.uk/quest/ ... eroll.html )

first~left #: number of dice rolled
second~right #: number of sides on the die~dice

normal dice: 6 sides (1,2,3,4,5,6): DiceRoll ("1d6")

1 x (1,2,3,4,5, or 6) = 1, 2, 3, 4, 5, or 6

"2d9" -> 2 x (1,2,3,4,5,6,7,8, or 9) = (eep... too many combinations... lol)

--------

Edit: not overthinking this (lol):

or... you could just do this too (for example):

base: x = 50
max: A = x + GetRandomInt (0,3)
min: B = x - GetRandomInt (0,8)

damage = GetRandomInt (B,A)

jaynabonne
30 Dec 2014, 10:49
(jdp)*, I don't completely understand your question, but I'll take a stab at it. What I'm struggling with is whether you're just trying to make sense of the wiki or whether you have an application in mind and want to morph the wiki into that. Either way, I'm not sure of the big picture.

Also, your topic is about a delegate that *returns* a range of numbers, but your specific question doesn't seem to be about that as such. So... more confusion.

The direct answer to your question (I believe!) is that you can replace this code:

        <hit type="script">
rundelegate (this, "attack", 4)
</hit>
<kick type="script">
rundelegate (this, "attack", 7)
</kick>


with:

        <hit type="script">
rundelegate (this, "attack", GetRandomInt(1,4))
</hit>
<kick type="script">
rundelegate (this, "attack", GetRandomInt(5,8))
</kick>

using the numbers you gave as examples. That's one way to do it. The other is to replace the single input value with min and max values and do the GetRandomInt in the "attack" handler - but then every attack handler needs to do it. It all depends on your design and what you're trying to do.

SHOULD this be done (by which I mean, is using delegates the best way to accomplish this at all)?


This is where I got a bit confused. "Should" is up to you. :) It's straightforward to incrementally modify the existing code in the way you described (so the "can" answer is "yes".) Whether you want to or not...

Whether delegates is the right solution is a different question. For the example shown, delegates were a good solution. Delegates are really just more capable scripts. Delegates are what (I think) the original scripts probably should have been, in that they can easily take parameters and return values. Generic scipts in Quest can't return values and you have to set up a dictionary to pass parameters in. The latter is doable (but more work) and the former is a deal breaker. So just look at delegates as being scripts with more natural inputs and outputs. Unfortunately, you can't work with them in the GUI...

You would use delegates in the same way you'd use script attributes on objects - either as a way to attach functionality to an object or as a way to have different objects have different behaviors. (In the example, the "attack" script could have different behaviors for different classes of enemies.) I'd say that if you need delegates, you'll know (or you'll have a problem where the suggested solution involves them).

I have used delegates a few times, but it's not common. Just where I want to be able to dispatch to different behaviors through a single attribute. Hope that helps!

jdpjdpjdp
30 Dec 2014, 18:51
@HK- Some very interesting ideas, especially the dice roll, which I didn't know was implemented but can see lots of possible uses for. Lots to think about. Thank you.

@jaynabonne- My apologies for the lack of clarity. Looking back, it's a badly written post. Mea culpa. Regardless, you did manage to answer my question, so thank you.

jaynabonne wrote:What I'm struggling with is whether you're just trying to make sense of the wiki or whether you have an application in mind and want to morph the wiki into that.


Both, really. I always want a better understanding, but yes, I do have an application in mind that's pretty much in line with the example from the wiki -- namely, different verbs (hit vs. kick in the example) kicking out different numbers, but across a range rather than a single, fixed integer. And your solution seems to accomplish that quite elegantly.

Also, your topic is about a delegate that *returns* a range of numbers, but your specific question doesn't seem to be about that as such.



One of many ways my lack of programming knowledge works against me: I don't always use the correct terminology. Clearly I've misused the word "returns" in this context. For my continuing education, what does "returns" mean in this context, as opposed to how I (mis)used it?

"Should" is up to you. :) It's straightforward to incrementally modify the existing code in the way you described (so the "can" answer is "yes".) Whether you want to or not...



Again, me being unclear: I was just trying to ask if delegates were a good solution to the issue presented, and if not, what might be a better one.

The rest of your post does a pretty good job explaining the virtues of delegates, which adds to my understanding of them. You seem to favor them over generic scripts, which has me curious about what else they might be able to do (he said, hoping the wise programmer would share more of his knowledge :D ).

Thank you yet again! You're a good teacher, Jay!

Silver
30 Dec 2014, 19:02
I have no idea what situation these would be used for..?

jaynabonne
30 Dec 2014, 20:17
I would say delegates are more advanced. Most of the users of Quest provide script implementations for already defined interfaces in the Quest core - for example, you implement a script to handle "take" or "drop" or an object's description or a room's "on enter", etc. But the Quest core only has one user-facing delegate that I can see (one for "addscript" when putting an object). The point: there aren't really any normal use cases for *implementing* a delegate to satisfy something in the core.

So that leaves the use cases where you are defining *your own* interfaces, which is definitely not common, unless you're writing libraries or doing something more advanced. By that, I mean cases where you would define a script attribute for your own use.

When would you want to define a script or delegate attribute of your own? You typically want to do that in the case of "dynamic dispatch", which is just a fancy name for letting objects define their own behaviors. If you always want to call the same code, you use a function. If you want the code called to change depending on the object, then you define a script attribute, have your code invoke that script attribute, and then let each object decide how to implement it. It provides a level of indirection.

A good example is a combat library, where attack and defense behaviors will likely change for each kind of monster you'll be battling. Your monster might have a "doattack" script that is invoked by the combat engine when it's the monster's turn to fight. An orc might bludgeon. An asp might try to bite and poision you. A spider might swing at you with its spear-like legs. A wizard might cast a spell. Rather than try to encapsulate all in one script ("if type is elf, do this; if type is spider, do that;" etc, which would cause most programmers to want to upchuck), you say "each object will have a doattack script attribute that I will call." It encapsulates the behavior in the object itself.

So then, when would you use delegates over scripts?

There are two advantages to delegates over scripts:
1) You can return a value to the caller.
2) Passing arguments is easier. With scripts, you have to create a dictionary, shove all the parameters in, and then hand that off to "do" or "invoke". With delegates, you just call rundelegate or RunDelegateFunction and pass the arguments as you normally would to a function. If you need to call a script with parameters in multiple places, it can be easier to use a delegate.

The disadvantages to using delegates:
1) You need to define a function signature (delegate type) for the delegate, listing any parameters and the return type. Of course, once you define it, then it's a snap to use it (just set the type to the delegate type instead of "script").
2) You can't use delegates through the Quest GUI.

I've used delegates typically for the first case, returning a value. As an example, I had a "verb" type, with a "conjugate" delegate that took the tense, person, etc and returned the appropriate conjugated verb. I was able to then invoke that "conjugate" delegate on any verb object I had. I had a separate Verb object for "attack", "beat", "charge", "claw", etc - this was used in some dungeon combat code - and the same verb could be used for either you or a monster. A template might be "{attacker} {Verb:attack} {target}", and it had to work out the correct conjugation for "attack" depending on what "attacker" was. If it was for you, it might be "You attack the spider", whereas if it was a monster, you might get "The spider attacks you." The verb has to morph in those cases, from "attack" to "attacks". It was simple using a delegate to allow "dynamic dispatch", to allow varying behavior, but still return a value.

HegemonKhan
30 Dec 2014, 20:47
Thanks Jay, that was a super useful post!
(AND THANKS Silver, for invoking Jay's post, lol, thanks for asking the question, hehe)

Jay wrote:Rather than try to encapsulate all in one script ("if type is elf, do this; if type is spider, do that;" etc, which would cause most programmers to want to upchuck), you say "each object will have a doattack script attribute that I will call." It encapsulates the behavior in the object itself.


that would be me... now I just need to learn delegates... lol... :D

--------

P.S.

also, your dynamic dialogue~conversation library with the 'callers, and etc' was fascinating... such a higher level of design... I'm having trouble making the transition from the basics that I know, to more advanced level of code designing. So, I really appreciate that library, it'll definately be something I'll study intensely, at some point (I really need to get a new computer, sighs).

Silver
30 Dec 2014, 21:32
So waaay beyond my level, then. But something to aim for understanding some day.

jaynabonne
30 Dec 2014, 22:31
If it helps, in all my time coding Quest, I can count on one hand (with room to spare) the number of times I've used delegates. But, as always, when you need 'em, nothing else will do. :)