Repeating a [while()], if possible?

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice

Post Reply
User avatar
Xaelvaen
Dragon
Posts: 498
Joined: Wed Aug 31, 2011 9:49 pm
Location: Somewhere between Heaven and Hell

Repeating a [while()], if possible?

Post by Xaelvaen »

I'm looking for a method to get a While loop to repeat itself based on an outside variable.

Code: Select all

[h: stuff=macro.args]

	[h: rollList=json.get(stuff,"rollList")]
	[h: token=json.get(stuff,"Token")]

[h: switchToken(token)]

[h: newRollList=""]
[h: howManyTimes=getProperty("Reflexes")]
[h: howManyTimes=howManyTimes+1]

[h: repeatCheck=1]

	[h, while(repeatCheck>0), CODE:{
		[h: roll=1d54]
		[h: repeatCheck=listContains(rollList,roll)]
	}]

[h: newRollList=listAppend(newRollList,roll)]
[h: sortedRollList=listSort(newRollList,"N-")]

[h: roll=listGet(sortedRollList,0)]

[h: macro.return=roll]
I'm looking for a way to get the while function to run a number of times equal to the reflexes property as determined above. I tried using while, for, and foreach all based on the variable, but it seems like the central while runs first, and once the variable is set, it won't run again. Any suggestions?

EDIT: To specify, I got it to run X number of times and create a list of variables, but the roll comes up the same. It would just get 29,29,29,29 into the newRollList, instead of 4 new rolls.
"An arrogant person considers himself perfect. This is the chief harm of arrogance. It interferes with a person's main task in life - becoming a better person." - Leo Tolstoy

User avatar
Xaelvaen
Dragon
Posts: 498
Joined: Wed Aug 31, 2011 9:49 pm
Location: Somewhere between Heaven and Hell

Re: Repeating a [while()], if possible?

Post by Xaelvaen »

Well, I found a work around:

Macro 1:

Code: Select all

[h: stuff=macro.args]

	[h: token=json.get(stuff,"Token")]
	[h: rollList=json.get(stuff,"rollList")]

[h: switchToken(token)]

[h: newRollList=""]
[h: howManyTimes=getProperty("Reflexes")]
[h: howManyTimes=howManyTimes+1]

[h: repeatCheck=1]

[h, for(n,0,howManyTimes), CODE:{

	[h, MACRO("initiative_roller2@Lib:Combat") : rollList]
	[h: newStuff=macro.return]
	[h: rollList=json.get(newStuff,"rollList")]
	[h: roll=json.get(newStuff,"Roll")]
	[h: newRollList=listAppend(newRollList,roll)]
}]

[h: sortedRollList=listSort(newRollList,"N-")]
[h: broadcast(sortedRollList)]

[h: roll=listGet(sortedRollList,0)]
[h: toSend=json.set("","Roll",roll,"rollList",rollList)]

[h: macro.return=toSend]
Macro 2:

Code: Select all

[h: rollList=macro.args]

[h: repeatCheck=1]

	[h, while(repeatCheck>0), CODE:{
		[h: roll=1d54]
		[h: repeatCheck=listContains(rollList,roll)]
	}]

[h: rollList=listAppend(rollList,roll)]
[h: toSend=json.set("","rollList",rollList,"Roll",roll)]

[h: macro.return=toSend]
"An arrogant person considers himself perfect. This is the chief harm of arrogance. It interferes with a person's main task in life - becoming a better person." - Leo Tolstoy

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: Repeating a [while()], if possible?

Post by wolph42 »

It helps if you describe what it is you want instead of asking for solution to a coding trick. Anyway, you already found the solution. Note that you dont need to split it up into two macros, you can also create a code block after the repeat. Also note that it might be easier to use [count:]

User avatar
Xaelvaen
Dragon
Posts: 498
Joined: Wed Aug 31, 2011 9:49 pm
Location: Somewhere between Heaven and Hell

Re: Repeating a [while()], if possible?

Post by Xaelvaen »

wolph42 wrote:It helps if you describe what it is you want instead of asking for solution to a coding trick.
I did describe what it was I wanted.
I'm looking for a way to get the while function to run a number of times equal to the reflexes property as determined above.
Outside of that, I'm not entirely sure what you mean by describe what I want.

As for count, haven't used that before, so I'll look into it, though I'm not sure what you mean by creating a code block after the repeat - that bit's over my head.

Thank you for the reply.
"An arrogant person considers himself perfect. This is the chief harm of arrogance. It interferes with a person's main task in life - becoming a better person." - Leo Tolstoy

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: Repeating a [while()], if possible?

Post by wolph42 »

what i meant is that forum users often talk in terms of code that they're stuck on and not what they actually want.

E.g. someone wants 5 random numbers in a list but instead of saying that they say 'I have issues with this count loop and I want it to loop and roll a d6'. Another way of saying this: instead of 'I have this problem I need to solve' you say 'I have this solution that does not work and I need some help with solving my solution'

anyway as its still not really clear to me what the end goal is, here an update of you given code (untested)

Code: Select all

[h: stuff=macro.args]

   [h: token=json.get(stuff,"Token")]
   [h: rollList=json.get(stuff,"rollList")]

[h: switchToken(token)]

[h: newRollList=""]
[h: howManyTimes=getProperty("Reflexes")]
[h: howManyTimes=howManyTimes+1]

[h: repeatCheck=1]

[h, count(howManyTimes), CODE:{
    [repeatCheck=1]
      [while(repeatCheck>0), CODE:{
          [roll=1d54]
          [repeatCheck=listContains(rollList,roll)]
    }]

    [rollList=listAppend(rollList,roll)]
    [toSend=json.set("","rollList",rollList,"Roll",roll)]
    [newStuff=toSend]
    [rollList=json.get(newStuff,"rollList")]
    [roll=json.get(newStuff,"Roll")]
    [newRollList=listAppend(newRollList,roll)]
}]

[h: sortedRollList=listSort(newRollList,"N-")]
[h: broadcast(sortedRollList)]

[h: roll=listGet(sortedRollList,0)]
[h: toSend=json.set("","Roll",roll,"rollList",rollList)]

[h: macro.return=toSend]

 
note that if your solutions works, you can consider it to be a good solution ;-)

User avatar
Xaelvaen
Dragon
Posts: 498
Joined: Wed Aug 31, 2011 9:49 pm
Location: Somewhere between Heaven and Hell

Re: Repeating a [while()], if possible?

Post by Xaelvaen »

I apologize for my inability to express my thoughts easily - comes with the territory. My original code looked identical to yours, except instead of count, I tried for, foreach, and another while, but for some reason, the second [while] that checks for the repeatCheck, kept spitting the same result into the list.

Example: With a 'Reflexes' property of 3, it would put 4 numbers in the list (3+1), but each number would come up the exact same from the while() loop, say 13,13,13,13. It seemed as though the inner nested WHILE ran first, and then completed before the repeat, thus filling the list with the same number over and over.

To clarify in the way you mentioned, this macro is emulating a card deck with 2 jokers (1d54). I send a list (rollList) so that no two cards can ever repeat themselves, which is what the while() was for. I just couldn't find the right code to make the while() work for players who got to take the 'best' of multiple draws. The While wouldn't function multiple times until I put it into a second macro, but I'll now try 'Count' and see if that fixes it.

Thanks for your time - I really don't intend to be vague, I just don't really know what to explain without trying to get you guys to write an entire bit of code for me, I feel like that's not really learning or trying to improve, but rather just have people do it for me. I'll try to be more concise.

EDIT: I tried it with COUNT instead, and got the same results.

Code: Select all

[h, COUNT(howManyTimes), CODE:{

	[h, while(repeatCheck>0), CODE:{
		[h: roll=1d54]
		[h: repeatCheck=listContains(rollList,roll)]
	}]

[h: newRollList=listAppend(newRollList,roll)]
}]
This returns a list with the exact same roll repeated n times. So yeah, for now, I'll keep my two macro approach, which works - it just seems a bit slow, but that's probably just my perception from how huge the initiative macro is, anyway.
"An arrogant person considers himself perfect. This is the chief harm of arrogance. It interferes with a person's main task in life - becoming a better person." - Leo Tolstoy

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: Repeating a [while()], if possible?

Post by Azhrei »

Xaelvaen wrote:Thanks for your time - I really don't intend to be vague, I just don't really know what to explain without trying to get you guys to write an entire bit of code for me, I feel like that's not really learning or trying to improve, but rather just have people do it for me. I'll try to be more concise.
Don't worry about it. It's something you'll catch on to over time.

My brother will often ask me for help with PHP. His question will be something like, "How do I look through a list of strings and find all the ones that end in '.txt'?" So I'll give him the answer. Then he'll ask, "Now, how do I eliminate the strings that contain uppercase characters?" So then he gets another code snippet. And so on. Until at the end of five or six emails back and forth, he has a working piece of code that does everything he wants, but it has five loops in it, each one processing a list of strings.

If he could take a step back and say, "I've got this kind of input and I want this kind of output. What's a good approach for that?" then I would be able to give him a cleaner solution on the first email exchange, in this case it might be a single loop that processes one string completely before going on to the next one. Meaning that all of that other time spent on the back-and-forth could've been spent explaining how I came up with the solution I did or why I chose to use a particular technique, thus teaching him to fish instead of giving him a fish. (Okay, lousy analogy perhaps, but the idea is the same.)

It takes awhile to learn how to ask questions in a way that make your question generic enough to be solved by a generic answer, thus allowing you to use the same or similar answer in the future when a similar question comes up.

The joy of programming, as it were. :D

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: Repeating a [while()], if possible?

Post by wolph42 »

what he said :D
Xaelvaen wrote:To clarify in the way you mentioned, this macro is emulating a card deck with 2 jokers (1d54). I send a list (rollList) so that no two cards can ever repeat themselves, which is what the while() was for. I just couldn't find the right code to make the while() work for players who got to take the 'best' of multiple draws. The While wouldn't function multiple times until I put it into a second macro, but I'll now try 'Count' and see if that fixes it.
Well with that you just gave the perfect opportunity to clarify what I tried to convey that Azh put better in words. Interestingly enough it was also Azhrei who teached me the below code trick that can be used with what you want. When using 'cards' which usually have the property that they can be drawn only once: use Wiki: json.shuffle() Wiki: json.remove() and Wiki: json.get().

Code: Select all

<!-- build the deck of cards, you can do that anyway you want but lets 
just create 54 numbers, but you could also build a deck out of json objects, 
strings, pieces of code and whatnot. -->
[h:deck = "[]"]
<!-- roll.count give the current number that is up in count() -->
[h,count(54):deck = json.append(deck, roll.count)] 
<!-- shuffle the deck -->
[h:deck = json.shuffle(deck)] 

<!-- draw 5 cards -->
[h:cards = ""]
[h,count(5), CODE:{
    <!-- get top card -->
    [card = json.get(deck,0)]
    <!-- add to drawn cards -->
    [cards = listAppend(cards, card)]
    <!-- remove top card from deck -->
    [deck = json.remove(deck,0)]
}]

[r:cards] 
this method is much faster and more robust then the solution you're opting for.
Xaelvaen wrote:This returns a list with the exact same roll repeated n times.
Obviously it does as you never reset the repeatCheck back to 1, hence the while loop only runs once resulting in the same roll being added each count loop.

I tested my version of your solution and that one works!!
just copy paste into chat window and run

Code: Select all

[h: newRollList=""]
[h: rollList=""]
[h: howManyTimes=10]
[h: howManyTimes=howManyTimes+1]

[h: repeatCheck=1]

[h, count(howManyTimes), CODE:{
    [repeatCheck=1]
      [while(repeatCheck>0), CODE:{
          [roll=1d54]
          [repeatCheck=listContains(rollList,roll)]
    }]

    [rollList=listAppend(rollList,roll)]
    [toSend=json.set("","rollList",rollList,"Roll",roll)]
    [newStuff=toSend]
    [rollList=json.get(newStuff,"rollList")]
    [roll=json.get(newStuff,"Roll")]
    [newRollList=listAppend(newRollList,roll)]
}]

[h: sortedRollList=listSort(newRollList,"N-")]
[h: broadcast(sortedRollList)]

[h: roll=listGet(sortedRollList,0)]
[h: toSend=json.set("","Roll",roll,"rollList",rollList)]

[r: toSend] 
Next time pay a little bit more attention to the code that I provide, note that I've made several changes to your solution in that code section, not one change as you assumed.

User avatar
Xaelvaen
Dragon
Posts: 498
Joined: Wed Aug 31, 2011 9:49 pm
Location: Somewhere between Heaven and Hell

Re: Repeating a [while()], if possible?

Post by Xaelvaen »

Thanks Az, I'll try a more direct approach in the future =)

@Wolph42: As for the coding of the deck, that's very elegant and sophisticated, I'll give it a try. I use a string list with the actual cards, that is 0 - 53, so I should just be able to use the card variable you set to get the card from that string list without much further work. With that in mind, I'm still very thankful for understanding the While loop a lot better (like resetting the variable!) thanks to your efforts, and now I have two new bits of coding to help me in the future. I truly do appreciate it.
"An arrogant person considers himself perfect. This is the chief harm of arrogance. It interferes with a person's main task in life - becoming a better person." - Leo Tolstoy


User avatar
Xaelvaen
Dragon
Posts: 498
Joined: Wed Aug 31, 2011 9:49 pm
Location: Somewhere between Heaven and Hell

Re: Repeating a [while()], if possible?

Post by Xaelvaen »

I'm trying to figure out how to do what I did with my old code for your 'card deck' macro as you showed me. My old macro did as follows:
  • Initiative macro ran a foreach() on each token to the macro that rolled the 1d54. So in this case, it sends to the card deck macro.
  • When a token would draw multiple cards, it only kept the best. I used a listSort(list,"N-"), and then listGet(list,0) to choose the best.
  • Only the card KEPT would be removed from the deck, the rest replaced in the deck so another token could draw them, except for the kept card.
  • This list of cards already kept was passed back to the initiative macro and thus back into the card deck macro, so the list would keep getting bigger.
  • Each time initiative would be rolled anew, the list would be reset, so that each time tokens rolled initiative, all 54 cards would be present.
My question is, how would I try to accomplish the same goals above, with your card deck macro? What method/codes would you use? I ask in more broad terms, because perhaps the way I did it was far more complicated than necessary, heh. I hope I was precise enough.

Here's what I did for the 'keep the best' part, perhaps you can critique:

Code: Select all


[h:deck = "[]"]
[h,count(54):deck = json.append(deck, roll.count)] 

[h:deck = json.shuffle(deck)]

[h:cards = ""]
[h: tokenName=getName(json.get(macro.args,"Token"))]
[h, token(tokenName) : howManyCards=getProperty("Reflexes")]

[h,count(howManyCards+1), CODE:{

    [card = json.get(deck,0)]

    [cards = listAppend(cards, card)]
    [deck = json.remove(deck,0)]
}]

[h: sortedCards=listSort(cards,"N-")]
[h: chosenCard=listGet(sortedCards,0)]
[h: macro.return=chosenCard]
"An arrogant person considers himself perfect. This is the chief harm of arrogance. It interferes with a person's main task in life - becoming a better person." - Leo Tolstoy

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: Repeating a [while()], if possible?

Post by wolph42 »

well, I guess I wouldn't do it much more differently than you provided. It looks good. You can consider creating one function of it instead of several... main thing is the 'deck'. If you start removing cards than you either need to keep track of it by use of global variables or store it temporarily on a lib:token...or just do initiative in one macro:

Code: Select all

[h:deck        = "[]"]
[h,count(54):deck = json.append(deck, roll.count)] 
[h:deck        = json.shuffle(deck)]
[h:toks        = getSelectedNames()]
[h:assert(listCount(toks), "Make sure at least one token is selected",0)]

[h,foreacht(tok, toks), CODE:{
    <!-- could also use lists, but json allows more freedom to operate, so as a habit I mostly use json -->
    [cards            = "[]"]
    [howManyCards    = getProperty("Reflexes", tok)]

    [count(howManyCards+1), CODE:{
        [card    = json.get(deck,0)]
        [cards    = json.append(cards, card)]
        [deck    = json.remove(deck,0)]
    }]

    [sortedCards    = listSort(cards,"N-")]
    [chosenCard        = json.get(sortedCards,0)]
    [deck            = json.difference(deck, json.set("[]", chosenCard))]
    
    <!-- i dont know what you do with the chosencard so store it on the current token... -->
    [setProperty("initiative", chosenCard, tok)]
}] 
UNTESTED

edit: I can imagine that the initiative might be dynamic (e.g. new adversaries join the fight in a later stage) in that case it might be prudent to store the deck so you can keep using it e.g. setLibProperty("deck", deck, "lib:token") and then eacht time you require/update the deck retrieve it from the lib and save it there.

User avatar
Xaelvaen
Dragon
Posts: 498
Joined: Wed Aug 31, 2011 9:49 pm
Location: Somewhere between Heaven and Hell

Re: Repeating a [while()], if possible?

Post by Xaelvaen »

Thank you once again. Took some heavy stripping and reworking of my initiative macro, but it seems considerably more stable, and has left me more room to control state durations and handle ongoing damage and similar effects and still keep it clean. Once again, MT proves its community to be above and beyond.
"An arrogant person considers himself perfect. This is the chief harm of arrogance. It interferes with a person's main task in life - becoming a better person." - Leo Tolstoy

Post Reply

Return to “Macros”