Roll 4d6, drop lowest.

So, I can roll 4d6, and get it to tell me what each number is and the total, by using the following code:

params = NewDictionary()
dictionary add (params, "r1", DiceRoll("1d6"))
dictionary add (params, "r2", DiceRoll("1d6"))
dictionary add (params, "r3", DiceRoll("1d6"))
dictionary add (params, "r4", DiceRoll("1d6"))
msg (Eval ("r1", params))
msg (Eval ("r2", params))
msg (Eval ("r3", params))
msg (Eval ("r4", params))
msg (Eval ("r1 + r2 + r3 + r4", params))

Is there any way to get it to evaluate which number of the four is the minimum, ie the lowest? Ideally I would like to get it to tell me the lowest number, so that I can roll 4d6, and get it to drop the lowest.

After that I will work on getting it to do that 6 times.

If anyone can help, that would be cool. Thanks.


Not sure why you've decided to use Eval here rather than a straightforward expression; but I'll approach it in the same way.

(I'm replacing DiceRoll("1d6") with GetRandomInt(1, 6) because it's much more efficient, and not really any harder to read. If you're getting the string from somewhere else, then you can do the same with DiceRoll)

params = NewDictionary()
lowest = 6
for (roll, 1, 4) {
  this_die = GetRandomInt(1, 6)
  dictionary add (params, "r"+roll, this_die)
  if (this_die < lowest) {
    lowest = this_die
  }
}
dictionary add (params, "lowest", lowest)
msg ("First die: " + Eval ("r1", params))
msg ("Second die: " + Eval ("r2", params))
msg ("Third die: " + Eval ("r3", params))
msg ("Fourth die: " + Eval ("r4", params))
msg ("Total: " + Eval ("r1 + r2 + r3 + r4", params))
msg ("Total dropping lowest: " + Eval ("r1 + r2 + r3 + r4 - lowest", params))

as 'mrangel' already showed, you just iterate/cycle through a collection (via 'foreach' and/or 'for' and/or 'while'), comparing previous value (stored in a variable) to current value being checked, and storing the value (in the variable), if it's lower/higher than the previous value

(Important: for lists/arrays, the first value, uses the index number of '0' for its reference, they do NOT start with the index number of '1' -- this takes a bit to get used to, and thus the index number of the last value is: ListCount(LIST) - 1)

// creating a random collection of values:

// (for my example, the range of total sum of the values are: 0 to 100: 0x10 to 10x10)

// creating an Object:

create ("example_object")

// creating a new/blank collection (in this example, a string list -- a list and an array are nearly the same thing, quest doesn't have arrays, only lists and dictionaries) attribute:

example_object.example_stringlist_attribute = NewStringList ()

// generating the random values and storing them into the collection:

for (unused_iterator_variable, 0, 9) {
  list add (example_object.example_stringlist_attribute, ToString (GetRandomInt (0,10)))
}

// ----------------------------------------------------------------------------

// getting/finding the lowest and highest values:

// storing the first value in the collection into both the lowest and highest variables:

example_object.lowest_value_integer_attribute = ToInt (StringListItem (example_object.example_stringlist_attribute, 0))
example_object.highest_value_integer_attribute = example_object.lowest_value_integer_attribute

// starting with the next value in the collection, checking if its higher/lower, and storing it into its higher/lower variable if it is:

for (iterator_variable, 1, 9) {

  current_value_variable = ToInt (StringListItem (example_object.example_stringlist_attribute, iterator_variable))

  if (current_value_variable > example_object.highest_value_integer_attribute) {
    example_object.highest_value_integer_attribute = current_value_variable
  } else if (current_value_variable < example_object.lowest_value_integer_attribute) {
    example_object.lowest_value_integer_attribute = current_value_variable
  }

}

// displaying the highest and lowest values:

msg ("Highest Value: " + example_object.highest_value_integer_attribute)
msg ("Lowest Value: " + example_object.lowest_value_integer_attribute)

there's even more fancy/advanced designs you can do if you have a big collection (binary tree sorting) of values (using binary search):

https://en.wikipedia.org/wiki/Binary_search_algorithm (binary searching: requires collection to already be sorted from lowest to highest, or it could be done from highest to lowest too... I think... but easier to just do lowest to highest... unless for some reason its better to do highest to lowest, lol)

https://en.wikipedia.org/wiki/Binary_search_tree (binary tree sorting)


I've done this sort of thing in Basic all the time, just don't remember how I did it...
BUT, another option could be to use split in another way...
R1= DiceRoll("1d6")
R2= DiceRoll("1d6")
R3= DiceRoll("1d6")
R4= DiceRoll("1d6")
(I like caps for variables... personal choice)
Roll=split("0;0;0;0;0;0;0")
// skip 0 index...
I think the next part will work:
(I wanted to: select R1, add 1 to the R1 location in the list...)
IE:
R1=3, so add 1 to the position 3 in the list, so that:
Roll=split("0,0,0,1,0,0,0")
then just count up, and subtract 1 from the first non-zero value...
Then, as in programming, Ver. 2.0...
// Number of each die count
D1=0
D2=0
D3=0
D4=0
D5=0
D6=0
If (R1=1){
D1=D1+1
}
if (R1=2){
D2=D2+1
}
and so on for each number (1-6)
then again for each die (#1-#4)
(Yes, a function would be the best choice here)
Then count up from D1 to find the first non-zero value, subtract 1,
then count D1 to D6, adding up the count:
Total= (D11) + (D22) + (D33) + (D44) + (D55) + (D66)

OK, now you have 2 more ways to do it...


OR... option #3...
Like my first version but add the value of each die roll to the list.
(Not the count)
IE, you roll 4,2,6,1
add each to the list so that:
Roll=("4;2;6;1")
then use "ObjectListSort" to sort the list, then subtract the first item...
(Altho, I think ObjectListSort uses objects to sort in the list. so, make 4 objects called die with an attribute called number...)
OR... option #4:
as you roll each die, do a bubble sort to sort the dice so that the bottom value it the lowest, and drop that...


I can't update my first post, but the total line should have been:
Total= (D1*1) + (D2*2) + (D3*3) + (D4*4) + (D5*5) + (D6*6)


Awesome!!! Thank you very mrangel, that was incredibly helpful!!! Also thank you to hegemonkhan and DarkLizerd for your input as well!!!

I only started with Quest about two or three days ago, I have just been through the tutorial, so getting it to do a random roll and tell me what it rolled was an achievement, lol. All of your responses have helped a lot in helping me to understand how the code works, what it means, and what can be done with it! :)

[quote]Not sure why you've decided to use Eval here rather than a straightforward expression[/quote]

Mainly because I did not know how to get the same result without using Eval, lol. I mashed together two or three things I found in the tutorial and modified them to come up with the stuff from the original post.

Thanks again!!! :)


Using eval here is pretty weird. There are situations where it could be useful, but they're pretty rare and complex.

This is how I'd expect it to look in a usual beginner's code:

params = NewDictionary()
r1 = GetRandomInt(1, 6)
lowest = r1
r2 = GetRandomInt(1, 6)
if (r2 < lowest) {
  lowest = r2
}
r3 = GetRandomInt(1, 6)
if (r3 < lowest) {
  lowest = r3
}
r4 = GetRandomInt(1, 6)
if (r4 < lowest) {
  lowest = r4
}

msg ("First die: " + r1)
msg ("Second die: " + r2)
msg ("Third die: " + r3)
msg ("Fourth die: " + r4)
msg ("Total: " + (r1 + r2 + r3 + r4))
msg ("Total dropping lowest: " + (r1 + r2 + r3 + r4 - lowest))

And how a programmer would probably approach it:

results = NewStringList()
total = 0
lowest = 6
for (i, 1, 4) {
  roll = GetRandomInt (1, 6)
  total = total + roll
  if (roll < lowest) {
    lowest = roll
  }
  list add (results, ToWords(roll))
}
msg ("Dice: " + Join (results, ", "))
msg ("Result: " + ToWords(total-lowest))

(When outputting numbers, you can use ToString to get output like "2"; or ToWords if you want it to say "three" in the output. If you don't include one of those functions it will use ToString by default. I believe there's also a ToRoman, if you prefer it to look like that.

If you ever use decimals, you should explicitly specify ToString, because implicit conversion behaves oddly depending on the user's language settings)


Why??? What does Popeyes have to do this finding out the lowest number of rolling 4 dice???
Altho, I like the Roll a die, and check if it is the lowest one... and updating it if it is...
(But it's too simple to work without 95 more lines written assembly to make sure it works for every
combination of 4 dice!!! 🤣🤣🤣 )


dalogumix seems to either be a bot, or someone who is posting random links to things, if you check the other recent threads in this forum.

Cool, thanks mrangel! Good to know about ToString and ToWords! And I see what you mean about it being weird to use eval in this situation, now that I have seen the alternatives.

And DarkLizerd, I like that approach as well, pretty elegant and not one that I would have known how to do on my own. :)


I removed the Popeyes post from dalogumix.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums