mIRC Homepage

shuffle a list to join channels

Posted By: ascription

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?
Posted By: Deega

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

Posted By: argv0

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)) {
    %channels = $addtok(%channels,$v1,44)
    inc %i
  }
  join %channels
  window -c @joinrand
}
Posted By: drum

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.
Posted By: argv0

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?
Posted By: drum

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.
Posted By: ascription

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?
Posted By: drum

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.
Posted By: ascription

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?
© 2020 mIRC Discussion Forums