mIRC Homepage
Posted By: trenzterra Random alphabets - 22/08/03 07:34 AM
Instead of using $read files, maybe $rand(aa,bz) or something like that should work too.

It will show anything between aa and bz, eg ab bd bg ak etc.

That would be nice apart from numbers.
Posted By: Hammer Re: Random alphabets - 22/08/03 08:50 AM
In order to overcome the limitation posed by $rand's failure to pick the first choice as often as it should, use $randletter instead:
Code:

alias randletter {
  [color:#006600]
  ;  Make sure the first character of each of the inputs are letters.
  ;  [/color]
  if $$1 !isletter || $$2 !isletter {
  [color:#006600]
    ;  Echo an appropriate error message patterned after mIRC's own error messages.
    ;  [/color]
    echo $color(info) -esti * Invalid parameters: $randletter
  [color:#006600]
    ;  Halt the script in the error condition
    ;  [/color]
    halt
  }
  [color:#006600]
  ;  Start with a known non-letter.
  ;  [/color]
  var %rand = 33
  [color:#006600]
  ;  Repeatedly pick random characters until one is in the range specified and a letter.
  ;  [/color]
  while $chr(%rand) !isletter { 
  [color:#006600]
    ;  Find a random value in the range specified (plus one for error correction).
    ;  [/color]
    var %rand = $rand($asc($1), $calc($asc($2) + 1)) }
  [color:#006600]
    ;  Correct for the $rand error, if necessary, if $2 is overshot by 1.
    ;  [/color]
    if %rand == $calc($asc($2) + 1) {
  [color:#006600]
      ;  Return the first character of the range if we overshoot.
      ;  [/color]
      return $1 
    }
  [color:#006600]
    ;  Repeat until a valid letter is found.  [/color]
  }
  [color:#006600]
  ;  Return the character found.
  ;  [/color]
  return $chr(%rand)
}

//echo -a * $randletter(a,b) $+ $randletter(A,z) $+ $randletter(A,Z) $+ $randletter(a,z)
Posted By: Raccoon Re: Random alphabets - 22/08/03 03:48 PM
What trenzterra was asking for is an alias that can choose double-digit letters, like AA through BZ, as you might find in a card index or spread sheet.

I dont see any problem with the consistancy a random letter or number is chosen by $rand. The following experiment tests the consistancy that $rand chooses a random letter from 'a' through 'z'.

The Code:
//var %n = 2600 | WHILE %n { hinc -m rand $r(a,z) | dec %n }

The Results, with 2600 loops (each letter should average 100 hits):
a 121, b 94, c 92, d 99, e 85, f 103, g 104, h 88, i 99, j 95, k 94, l 115, m 91,
n 99, o 101, p 118, q 105, r 95, s 96, t 92, u 93, v 107, w 99, x 110, y 102, z 103.

The Results, with 260000 loops:
a 10147, b 10130, c 10028, d 9815, e 9974, f 10080, g 9947, h 9983, i 9812,
j 9846, k 9965, l 9697, m 10057, n 10129, o 9964, p 10063, q 10054, r 10015,
s 10026, t 10016, u 10104, v 10028, w 9999, x 10009, y 10124, z 9988.

If anything, $rand is more likely to pick the first letter the most, not the least.
Otherwise, it's completely even distribution.

- Raccoon
Posted By: Doomstars Re: Random alphabets - 22/08/03 06:09 PM
Maybe $rand could be extended so it would work like the below.

$rand(a,z,1,999,A,Z,5,9) would return the same thing as below.

$rand(a,z) $+ $rand(1,999) $+ $rand(A,Z) $+ $rand(5,9)
Posted By: qwerty Re: Random alphabets - 22/08/03 06:18 PM
These incosistencies are apparent when you use $rand(number1,number2). In this case, the edge numbers appear half as often. I didn't know $rand(letter1,letter2) isn't affected, neither did Hammer probably.
Posted By: Raccoon Re: Random alphabets - 22/08/03 06:36 PM
Oh wow, I had no idea about that bug... but it's true!

Guess I'll be using something like this until it's fixed...

/r2 { :1 | if ($r($calc($1 -1),$calc($2 +1)) isnum $+($1,-,$2)) return $ifmatch | goto 1 }

does the trick... at nearly 1/3rd the speed.
Posted By: Doomstars Re: Random alphabets - 22/08/03 07:09 PM
That's an old bug I remember. $rand(1,3) will have 1 come about 25% of the time. 2 will come up 50% of the time. And 3 will come up 25% of the time.

If this ever does get fixed, do you think it would be worth it to have "$rand(1,10,a,z)" to replace "$rand(1,10) $rand(a,z)"? I was going to say "$rand(1,10) $+ $rand(a,z)" but then it's hard separating it since you don't know where the space should be all the time.
Posted By: Raccoon Re: Random alphabets - 22/08/03 07:47 PM
There are many different ways I would write a $rand function.
The difficulty is to preserve backward compatibility since $rand already exists.
If I didn't have to worry about that though, here are some of the ways I might do it.

1. Each parameter is a single character or range of characters to be selected randomly from.
The result will be a single character picked from the list.

$rand(0-9,A-F) which would generate a random hexidecimal character.
$rand(0-9,A-Z,a-z,_,^,`,\,|,[,],{,},-) which would generate a random nickname character.
$rand(0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,...etc) which would do the same.

2. Or like a regular expression class. Even include the []'s to help with backward compatibility.

$rand([][0-9A-Za-z_^`|{}\-]) generates a single nickname character.
$rand([][0-9A-Za-z_^`|{}\-]{9}) generates a string of 9 nickname characters.
$rand([][0-9A-Za-z_^`|{}\-]{1,9}) generates a string of $r(1,9) nickname characters.
Perhaps additional parameters could each have different ranges of characters.
$rand([][A-Za-z_^`|{}\], [][0-9A-Za-z_^`|{}\-]{8}) generates a real random nick. (no numbers or '-' for first character)

3. Dice roll syntex. Perhaps it's own $roll identifier.
$roll(5d20+4) == $calc($r(1,20) + $r(1,20) + $r(1,20) + $r(1,20) + $r(1,20) + 4)
There are too many varying roll syntex that exist, so I'll leave it with this simple example.

Just some of the ideas I had in mind anyway.
Posted By: Doomstars Re: Random alphabets - 22/08/03 07:57 PM
That seems complex and would probably break compatibility.

I would think "$rand(1,9,A,Z)" returning the same as "$rand(1,9) $rand(A,Z)" would be enough or a first step. Since it gets rid of the extra $rand identifiers. And "$remove($rand(1,9,A,Z),$chr(32))" would return it without the spaces inbetween.
Posted By: starbucks_mafia Re: Random alphabets - 22/08/03 08:11 PM
I think just support for what the original poster asked for would be fine, all that other stuff is largely unnecessary.

Slightly off-topic here but this alias is marginally faster than yours plus it can take letters (and it doesn't use a nasty goto).

Code:
my_rand {
  if ($+($1,$2) !isnum) return $rand($1,$2)
  if ($rand($1,$calc($2 + 1)) <= $2) return $ifmatch
  return $1
}
Posted By: Raccoon Re: Random alphabets - 22/08/03 09:19 PM
very cleaver.

$my_rand(1,100) == $rand(1,101)
if (101) then 1

since both are chosen only half the number of times they ought to be, their combined effort evens the odds... and no wasted mis-fires.

very cleaver indeed.
Posted By: qwerty Re: Random alphabets - 22/08/03 11:06 PM
does the trick... at nearly 1/3rd the speed.
Compared to what? I kinda lost you there.

Hammer's algorithm is faster (constant-time), as it takes advantage of the fact that edge numbers appear exactly half as often. Here's the r2 alias that implements this algorithm:

alias r2 if $rand($1,$calc($2 + 1)) <= $2 { return $ifmatch } | return $1

Your method could fix any edge-numbers problem, this one can only fix the current $rand().
Posted By: codemastr Re: Random alphabets - 22/08/03 11:37 PM
Someone should just make a dll to use mt_rand.
Posted By: Raccoon Re: Random alphabets - 22/08/03 11:55 PM
>>does the trick... at nearly 1/3rd the speed.
>Compared to what? I kinda lost you there.

My $r2 function compared to mIRC's $rand function. my $r2 is 3x slower than $rand.
I meant to phrase that "but at 1/3rd the speed."

>Hammer's algorithm is faster (constant-time), as it takes advantage of the fact that edge numbers appear exactly half as often. Here's the r2 alias that implements this algorithm:

I didn't completly deceminate the method he was using, because I was too busy disproving any bug with $rand(a,z). I do see now that his example, though it didn't support numbers, used the same logic as starbuck's-- so I shout praise in hammer's direction too.

> alias r2 if $rand($1,$calc($2 + 1)) <= $2 { return $ifmatch } | return $1
> Your method could fix any edge-numbers problem, this one can only fix the current $rand().

Agreed. But that's all we want to do, is fix the edge problem... isn't it?
And that looks exactly like starbuck's code, sans bounds checking for letters.

All I was doing is saluting starbuck's example.
I'm sorry I missed the method behind hammer's code.
Posted By: qwerty Re: Random alphabets - 23/08/03 12:25 AM
Oops, by the time I submitted my reply, starbucks and you had replied. I read the 2 replies only after I submitted. This is what happens when I do other things in the middle of the "preview post"...
Posted By: Hammer Re: Random alphabets - 23/08/03 10:18 AM
[color:00007F]qwerty[/color]:
I did know letters are unaffected, though I didn't really remember it until someone mentioned it; however, since I was using the the $asc() value of the letters, I had to take into account the edge number problem, which is why I did it the way I did. As I mentioned to you on EFnet, I did it this way to allow case sensitivity and omit intervening [\]^_` between upper and lower case (ASCII 91-96). $rand will allow $rand(A,Z) or $rand(a,z) but not $rand(A,z).

Raccoon:
It does not support number only because he did not ask for it to do so. That is why I specifically checked !isletter instead of !isalnum. Removing the check simplifies the code and you can specify any kind of range you wish, including not only letters but also punctuation or high ASCII as well. Here are my original results as posted to this forum for reference.

As far as the portion of the code to double (or more) the letters, I left that as an exercise for the poster for specific reasons.
  • There was no intented use specified and I can easily visualize ways this sort of thing can be used maliciously.
  • There would need to be some sort of formatting design decisions made which are not evident in the original post. For example, how will it handle $rand(a,ZZZZZ) or $rand(zzzz,a). Note that both are "backwards" in addition to being of differing lengths. Thus, they are interpretable in multiple ways, none of which were expressed in the original post.
  • No data validation was mentioned, which is why I only included the sole check indicated by that post. As I left it, it is possible to specify a backward range. Since $!rand(15,1) works (even though $!rand(z,a) doesn't) and my method converts to ASCII first, my version can handle backward ranges.
  • On another, more careful, reading of the original post, the first character of the first parameter is the lower bound and the first character of the second parameter is the upper bound for that character position in the result string. This would be simple enough to accomplish in an alias that wraps $randletter(), passing it $mid($1,%i,1) and $mid($2,%i,1) if you assume (or correct for, as below) that $1 and $2 will be of equal length; again, though, you might need data validation for each loop iteration.
    Code:
    
    alias multirand {
      var %result, %1 = $left($1,$len($$2)), %2 = $left($2,$len(%1)), %i = 1, %limit = $calc($len(%1) + 1)
      while %i &lt; %limit { var %result = $+(%result,$randletter($mid(%1,%i,1),$mid(%2,%i,1))), %i = %i + 1 }
      return %result
    }

    //echo -a * $multirand(aa,bz) $multirand(aaa,bft)
    * at bdj
  • Perhaps I erred in allowing upper-case letters to be mixed with lower-case letters and should have just $lower()'d the input, since that is how it was presented in the original suggestion.
These are my reasons for leaving the scripted reply in the state I did. The omissions were intentional.

Personally, if I were the one designing it, I would change the format entirely and use $multirand(<valid characters (ranges allowed)>, [length]) where $mutlirand(0-9A-Za-z,3) might return g3A, and the length parameter is optional, defaulting to 1. This would be even simpler to implement, since you just have two loops, the outer loop builds the string and var %re = /([ $+ $1 $+ ])/), then the inner loop is a simple while $regex($rand(%low,%high), %re) == 0 { continue } and then build %result = $+(%result,$regml(1)). The error checking and determining %low and %high would take longer to write than the actual meat of the code. This method will probably be slower, though, since it calls $regex.

If you've made it this far, kudos and cookies are at the table on the left. I hope I haven't left any questions you had about my code or the reasons behind it unaddressed.
Posted By: qwerty Re: Random alphabets - 23/08/03 01:46 PM
however, since I was using the the $asc() value of the letters, I had to take into account the edge number problem, which is why I did it the way I did.

You're right of course. Even though I did see $asc() in your code, I accidentally thought you were using $rand(letter1,letter2) (it's amazing how stupid mistakes I can make sometimes, isn't it).
Posted By: trenzterra Re: Random alphabets - 23/08/03 02:07 PM
Since you asked for the syntax, I will gladly post it.

$rand(zz,a) will show a letter from a to zz.

$rand(a,zz) will do the same too.

It would be good to have case sensitive too, and have ZZ superior to zz.

As another poster suggested, $rand(a,zz,2,33) etc is quite a good idea I reckon.
Posted By: Watchdog Re: Random alphabets - 23/08/03 02:40 PM
If you have one case superior to the other then the result is not random, is it?
Posted By: landonsandor Re: Random alphabets - 23/08/03 02:46 PM
what Id like to see is something like this:

$rand(1-100,151-200) where it picks a random number between 1 and 200 ignoring numbers 101 thru 150.
Posted By: Hammer Re: Random alphabets - 23/08/03 03:42 PM
Code:

;  Usage: $randrange(&lt;lower&gt;,&lt;upper&gt;,[exclude range][,...])
;
alias randrange {
  var %tries = 1, %maxtries = 100, %found = $false, %2 = $2 + 1, %r = $rand($1, %2)
  if (%r == %2) %r = $1
  while (!%found) {
    %found = $true
    if !$3 { break }
    var %i = 1
    while $gettok($3-, %i, 32) != $null { 
      if %r isnum $ifmatch {
        var %found = $false, %i = $numtok($3-, 32), %r = $rand($1, %2)
        if (%r == %2) %r = $1
      }
      inc %i
    }
    inc %tries
    if (%tries == %maxtries) return
  }
  return %r
}

//echo -a * $randrange(1,200, 10-25, 60-75, 110-125, 160-175)

* 97
* 87
* 42
* 33
* 190

EDIT:
  1. Fixed upper bound bug when the lower bound was excluded.
  2. Added MaxTries to prevent infinite loops if all valid values
    end up excluded. Now returns $null if unsuccessful.
Posted By: trenzterra Re: Random alphabets - 24/08/03 01:01 AM
Well, in the case of ZZ and zz, it will return any letter from ZZ to zz.

Like ZZ, aa, ab, ac ...... zz
Posted By: naki Re: Random alphabets - 24/08/03 11:45 AM
there is a bug in that script I've seen. I did $randrange(1,10, 1-5) and it returns 1 everynow and then

[07:42] <naki[afk]> $randrange(1,10 ,1,5)
[07:42] <naki[afk]> 1
[07:42] <naki[afk]> 1
[07:42] <naki[afk]> 10
[07:42] <naki[afk]> 6
[07:42] <naki[afk]> 7
[07:42] <naki[afk]> 6
[07:42] <naki[afk]> 6
[07:42] <naki[afk]> 1
© mIRC Discussion Forums