mIRC Homepage
shuffle a list to join channels - 30/11/12 01:11 AM
Hello Forum,

Notwithstanding my recent threads in the 'Feature Suggestions' forum, I have a challenge for you.

I would like to join 3 channels in a random order. The trivial solution is to enumerate the possible orders of the list, and pick a random integer 1..6. [untested]

Code:
```var %rand0 \$rand(1,6)
if (%rand0 == 1)
join A B C
elseif (%rand0 == 2)
join A C B
elseif (%rand0 == 3)
join B A C
elseif (%rand0 == 4)
join B C A
elseif (%rand0 == 5)
join C A B
elseif (%rand0 == 6)
join C B A```

But this is unwieldy, and inconvenient for a list of 4 channels, let alone 5 channels with 120 permutations or 6 with 720.

How do you shuffle a list in MSL?
Re: shuffle a list to join channels - 30/11/12 03:32 AM
Theres probably a better solution but...
Code:
```  var %chans = #1 #2 #3 #4 #5 #6
var %a,%b
while %chans { var %a = \$gettok(%chans,\$r(1,\$numtok(%chans,32)),32),%b = \$addtok(%b,%a,44),%chans = \$remtok(%chans,%a,1,32) }
Join %b
```

Re: shuffle a list to join channels - 02/12/12 06:20 AM
You can use /filter -a to sort a hidden window. Presumably you're not hardcoding the channels, so they're coming from a list anyway, which means you can /filter from some "channels.txt" input file.

Code:
```alias filtersort.rand { return \$calc(\$rand(0,2) - 1) }
alias joinrand {
var %i = 1, %channels = ""
window -h @joinrand
filter -afw channels.txt @joinrand filtersort.rand *
while (\$line(@joinrand,%i)) {
inc %i
}
join %channels
window -c @joinrand
}```
Re: shuffle a list to join channels - 02/12/12 09:11 AM
Originally Posted By: argv0
You can use /filter -a to sort a hidden window. Presumably you're not hardcoding the channels, so they're coming from a list anyway, which means you can /filter from some "channels.txt" input file.

This is sort of a cool trick, but it won't give you a uniform distribution. (For example, the first channel in the list will be more likely to appear first after the "sort" than other channels.) I wouldn't recommend this method if you're looking for unbiased results.
Re: shuffle a list to join channels - 03/12/12 12:20 AM
Originally Posted By: drum
but it won't give you a uniform distribution.

How is this any different from any use of \$rand in mIRC? You're pointing out a flaw with mIRC's random number generator, not with the methodology.

Do you have a better solution?
Re: shuffle a list to join channels - 03/12/12 01:25 AM
Originally Posted By: argv0
Originally Posted By: drum
but it won't give you a uniform distribution.

How is this any different from any use of \$rand in mIRC? You're pointing out a flaw with mIRC's random number generator, not with the methodology.

No, it's not an issue with \$rand. It's because sorting algorithms work on the assumption that if A comes before B, and B comes before C, then A must come before C. However that isn't true with \$filtersort.rand. I can't really get into more detail that than without knowing the exact algorithm that mIRC uses for sorting with /filter, but I ran a trial with your method and there was a clear bias.

Quote:
Do you have a better solution?

Deega's method (or any method not relying on a sorting algorithm) is fine.
Re: shuffle a list to join channels - 06/12/12 01:11 PM
I didn't state whether I needed "uniform" random numbers, or just shake it up a little. But it wouldn't be long until I encountered Mr. Drum's concerns in other applications, especially something like cryptography.

If the \$rand routine is uniform, Mr. Argv0's solution will be skewed. Otherwise, both are skewed and you might need to implement your own.

MSL only has one data structure, hash tables, just like PHP. But according to the docs, entries can be accessed with integer indices, therefore a random item can be used and removed.

I tinkered around with hash tables a bit; I haven't used them much. I'm having problems accessing the data associated with an item, but the script is successful this far.
Code:
```alias test {
if (!\$hget(testhash)) hmake testhash
var %k 5
while (%k) {
hadd -s testhash item \$+ %k data \$+ %k
dec %k
}
echo -s size: \$hget(testhash, 0).item
while (\$hget(testhash, 0).item) {
var %r \$rand(1, \$hget(testhash, 0).item)
var %i \$hget(testhash, %r).item
var %d %hget(testhash, %r).data
var %d2 %hget(testhash, %r)
var %d3 %hget(testhash, %i).data
var %d4 %hget(testhash, %i)
echo -s r %r i %i d %d %d2 %d3 %d4
hdel testhash %i
}
echo -s testhash
hfree testhash
}
```

The expected output is:
Code:
```size: 5
r 4 i item3 d data3
r 4 i item1 d data1
r 3 i item2 d data2
r 1 i item4 d data4
r 1 i item5 d data5
testhash```

But the observed output is:
Code:
```size: 5
r 4 i item3 d
r 4 i item1 d
r 3 i item2 d
r 1 i item4 d
r 1 i item5 d
testhash```

Any ideas?
Re: shuffle a list to join channels - 06/12/12 01:40 PM
You accidentally used %hget in a few places instead of \$hget. That method should work otherwise.
Re: shuffle a list to join channels - 08/12/12 08:07 AM
That is rather subtle. I want a hammer that is less easy to drop on my foot. Not to mix metaphors.

Replacing the script command:
Code:
```    echo -s r %r i %i d %d d2 %d2 d3 %d3 d4 %d4
```

Gives the output:
Code:
```size: 5
r 5 i item1 d data1 d2 d3 5 d4 data1
r 3 i item2 d data2 d2 d3 4 d4 data2
r 2 i item5 d data5 d2 d3 3 d4 data5
r 2 i item3 d data3 d2 d3 2 d4 data3
r 1 i item4 d data4 d2 d3 1 d4 data4
testhash```

That means that "\$hget(testhash, %r).data" and "\$hget(testhash, %i)" do what I want but "\$hget(testhash, %r)" and "\$hget(testhash, %i).data" don't.

Why is there a "\$gettok(.., 44)" in Deega's solution? Would Join operate correctly on more channels than the network target max?