mIRC Home    About    Download    Register    News    Help

Print Thread
Joined: Apr 2010
Posts: 59
A
Babel fish
OP Offline
Babel fish
A
Joined: Apr 2010
Posts: 59
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?

Joined: Oct 2012
Posts: 164
D
Vogon poet
Offline
Vogon poet
D
Joined: Oct 2012
Posts: 164
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


Joined: Oct 2003
Posts: 3,918
A
Hoopy frood
Offline
Hoopy frood
A
Joined: Oct 2003
Posts: 3,918
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
}


- argv[0] on EFnet #mIRC
- "Life is a pointer to an integer without a cast"
Joined: Dec 2002
Posts: 344
D
Pan-dimensional mouse
Offline
Pan-dimensional mouse
D
Joined: Dec 2002
Posts: 344
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.

Joined: Oct 2003
Posts: 3,918
A
Hoopy frood
Offline
Hoopy frood
A
Joined: Oct 2003
Posts: 3,918
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?


- argv[0] on EFnet #mIRC
- "Life is a pointer to an integer without a cast"
Joined: Dec 2002
Posts: 344
D
Pan-dimensional mouse
Offline
Pan-dimensional mouse
D
Joined: Dec 2002
Posts: 344
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.

Joined: Apr 2010
Posts: 59
A
Babel fish
OP Offline
Babel fish
A
Joined: Apr 2010
Posts: 59
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?

Joined: Dec 2002
Posts: 344
D
Pan-dimensional mouse
Offline
Pan-dimensional mouse
D
Joined: Dec 2002
Posts: 344
You accidentally used %hget in a few places instead of $hget. That method should work otherwise.

Joined: Apr 2010
Posts: 59
A
Babel fish
OP Offline
Babel fish
A
Joined: Apr 2010
Posts: 59
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?


Link Copied to Clipboard