Say I’ve got six named numbers, and I wanted to find out which three were the highest… I can only think of really longwinded ways of doing this. My intuition is that I could do this with some kind of loop, but the only ways that come to mind are even more complicated.
I’d want it to set as true oranges, kiwis and then one of but not both of pineapples and bananas (for my purposes I’d just arbitrarily decide which one takes precedent when writing the check). Any suggestions?
Maybe you think this is inelegant or too complicated, but this is what I’ve done as a gosub routine. I’m not sure there’s another, less simple way to do this. I played around with a different option, but although it seemed like it would be less complicated originally, it ended up being more complicated and less intuitive and readable. One weakness in this routine is that if two variables have the same value, the code has to pick one and it gives preference to the variable being tested that comes alphabetically last. There’s not really a way to solve this though without player input. I could, of course, randomize selection in the case of two highest variables, but it amounts to the same problem.
Code
*if (((((b_rom = 0) and (g_rom = 0)) and (r_rom = 0)) and (t_rom = 0)) and (z_rom = 0))
*set partner "none"
*else_if ((((b_rom >= g_rom) and ((b_rom >= r_rom)) and (b_rom >= t_rom)) and (b_rom >= z_rom))
*set partner "b"
*else_if ((((g_rom >= b_rom) and ((g_rom >= r_rom)) and (g_rom >= t_rom)) and (g_rom >= z_rom))
*set partner "g"
*else_if ((((r_rom >= b_rom) and ((r_rom >= g_rom)) and (r_rom >= t_rom)) and (r_rom >= z_rom))
*set partner "r"
*else_if ((((t_rom >= b_rom) and ((t_rom >= g_rom)) and (t_rom >= r_rom)) and (t_rom >= z_rom))
*set partner "t"
*else_if ((((z_rom >= b_rom) and ((z_rom >= g_rom)) and (z_rom >= r_rom)) and (z_rom >= t_rom))
*set partner "z"
*else
*bug
Edit: I totally missed the “three out of six” like a complete dumbass, and now I’m frantically trying to figure out a way that I can edit my post to make it actually relevant to this question! Will do some thinking and try not to jump the gun again
Hah, no problem. Yes, finding the absolute highest is straightforward.
My current best approach is running something like this, then running the same code again (with a flag to ignore the highest value already picked) to find the second highest and so on. It’s just that it ends up with excessive conditionals.
For my current project, the real answer is “stop trying to do something fancy the players won’t ever notice or will at worst appear random to them, and just handcraft a simpler solution that’ll be adequately satisfying”.
I might have a solution? I haven’t tested this, but I think it could work.
Explanation:
So the 6 variables here are u, v, w, x, y, and z, and they all have corresponding temp variables within the gosub routine. You could of course create permanent variables in your startup.txt as long as you *set their value to their corresponding stat in the gosub routine.
The first time the code cycles through the routine, it will determine the highest stat and trip that boolean. It will also set the test variable of that stat to zero so that in subsequent cycles the code ignores that state. After going through the cycle three times, you should have your three highest variables. There is still a weakness that for variables that have the same value, the code is making a decision without input from either the player or the coder. Another weakness is if fewer than three variables are greater than 0. In that case, after selecting the variables that are greater than zero, the code will assign one of the other stats a “highest stat” status regardless. Please do let me know what you think of this code!
*temp u_test u
*temp v_test v
*temp w_test w
*temp x_test x
*temp y_test y
*temp z_test z
*label highest_three
*if ((((((u_test >= v_test) and (u_test >= w_test)) and (u_test >= x_test)) and (u_test >= y_test)) and (u_test >= z_test))
*set u_high true
*set u_test 0
*set counter +1
*elseif ((((((v_test >= u_test) and (v_test >= w_test)) and (v_test >= x_test)) and (v_test >= y_test)) and (v_test >= z_test))
*set v_high true
*set v_test 0
*set counter +1
*elseif ((((((w_test >= u_test) and (w_test >= v_test)) and (w_test >= x_test)) and (w_test >= y_test)) and (w_test >= z_test))
*set w_high true
*set w_test 0
*set counter +1
*elseif ((((((x_test >= u_test) and (x_test >= v_test)) and (x_test >= w_test)) and (x_test >= y_test)) and (x_test >= z_test))
*set x_high true
*set x_test 0
*set counter +1
*elseif ((((((y_test >= u_test) and (y_test >= v_test)) and (y_test >= w_test)) and (y_test >= x_test)) and (y_test >= z_test))
*set y_high true
*set y_test 0
*set counter +1
*else
*set z_high true
*z_test 0
*set counter +1
*if (counter < 3)
*goto highest_three
*else
*return
Edit: this likely has typos (just found one!), but I think you’ll be able to find/fix them easily enough
Looking at it, I think this does it, just testing now.
I fixed the errors in the above, but the solution was essentially correct, and solved it with a straightforward loop which is what I originally had in mind. Nice!
*temp u_test 9
*temp v_test 9
*temp w_test 11
*temp x_test 9
*temp y_test 1
*temp z_test 2
*temp u_high false
*temp v_high false
*temp w_high false
*temp x_high false
*temp y_high false
*temp z_high false
*temp counter 0
*label highest_three
*if (((((u_test >= v_test) and (u_test >= w_test)) and (u_test >= x_test)) and (u_test >= y_test)) and (u_test >= z_test))
*set u_high true
*set u_test 0
*set counter + 1
*goto countcheck
*elseif (((((v_test >= u_test) and (v_test >= w_test)) and (v_test >= x_test)) and (v_test >= y_test)) and (v_test >= z_test))
*set v_high true
*set v_test 0
*set counter + 1
*goto countcheck
*elseif (((((w_test >= u_test) and (w_test >= v_test)) and (w_test >= x_test)) and (w_test >= y_test)) and (w_test >= z_test))
*set w_high true
*set w_test 0
*set counter + 1
*goto countcheck
*elseif (((((x_test >= u_test) and (x_test >= v_test)) and (x_test >= w_test)) and (x_test >= y_test)) and (x_test >= z_test))
*set x_high true
*set x_test 0
*set counter + 1
*goto countcheck
*elseif (((((y_test >= u_test) and (y_test >= v_test)) and (y_test >= w_test)) and (y_test >= x_test)) and (y_test >= z_test))
*set y_high true
*set y_test 0
*set counter + 1
*goto countcheck
*else
*set z_high true
*set z_test 0
*set counter + 1
*goto countcheck
*label countcheck
*if (counter < 3)
*goto highest_three
*if z_high = true
z highest
*if u_high = true
u highest
*if y_high = true
y highest
*if v_high = true
v highest
*if w_high = true
w highest
*if x_high = true
x highest
This is a solution using a for loop. I’m supposing the variables are global but if they are local, then the sub-routine should be kept in the same file as the variables.
I’ve never used arrays (I didn’t know until today that choicescript even supported them). Is there any documentation on using them? I had a search but couldn’t find anything.
Unfortunately, CS lacks proper documentation. The wiki helps but it’s somewhat out-of-date. I found out about arrays the same way you just did, when someone used it in their script. Then I began to experiment with it.
They’re not arrays, properly speaking. It’s just that CS simulates arrays by allowing you to call on a variable using “index syntax” (using brackets). But you have to preemptively create all slots of the array as single variables. Indices can also be strings, e.g:
*temp character_name "John"
*temp character_surname "Smith"
*temp character_age 29
*temp character_strength 75
The character's name is: ${ character[ "name" ] } ${ character[ "surname" ] }
Etc.
Also, dunno if you know, but you can pass arguments to subroutines on the signature.