Jump to content

Random() But biased


Recommended Posts

If the title isn't clear enough I need a way to make Random() favor certain numbers over other numbers.

In my specific situation I'm populating a 2D array of undefined dimensions with (essentially) 1's and 0's, 90% 0's and 10% 1's. However, I wish to avoid having all the 1's clustered together as is theoretically possible with Random(), especially with smaller dimensions to the array. To do this I planned on generating a single variable based on surrounding cells that would weight the outcome towards one way or another. This would be essentially as simple as add all the values of adjacent cells (undefined cells would be set to zero) and the higher that variable, the more likely you would get a 0  instead of a 1. I would have then looped through this process until I had the desired number of 1's.

At the end of all this planning I realized.

I have absolutely no clue as to how I would cause an effect on Random() with a variable.

Thank you for your time and any contributions you can make. I'm sorry if I missed an obvious solution.

Link to comment
Share on other sites

I may have solved my own problem, but I do not have the time to test it now so I'll post an update if this works.

Instead of Random(0,1,1)

I'd use Random($min,$max,1)

with $min likely being 0 and $max being many times 1, like 1000 or something

Then use something like

 

$min = 0

$max = 1

$mult = 1000

$modmax = ($mult*$max) - $bias

Round(Random($min,$maxmod,1)/$mult)

 

$bias would be the variable mentioned in my original question and how much weight it was given could be tweaked by adjusting the value of $mult

This should result in a "random" number that is less likely to be close to the $max value but could also be reversed to result in a number further from the $min value. This still isn't perfect as it needs methods to prevent $bias from being out of bounds. In my example out of bounds would be if $bias is less than $min or greater than $max.

As I said above I plan on posting the results of my tests and possibly a function that can do this operation. That is if one of you amazing forum members doesn't beat me to it while I sleep.

Link to comment
Share on other sites

3 hours ago, Funtime60 said:

90% 0's and 10% 1's

This requirement makes the use of Random difficult
Suggestion :

#Include <Array.au3>

; first populate the array with 90% 0 and 10% 1
Local $array[100]
For $i = 0 to 89
   $array[$i] = 0
Next
For $i = 89 to 99
   $array[$i] = 1
Next
; then shuffle the array
_ArrayShuffle($array)

_ArrayDisplay($array)

 

Link to comment
Share on other sites

4 hours ago, Funtime60 said:

I'm populating a 2D array of undefined dimensions with (essentially) 1's and 0's, 90% 0's and 10% 1's.

; Number of rows and counter of ones
Local $i_01 = Random(1000, 100000, 1), $i_1
; Declare 2D array with a number of columns
Local $a[$i_01][Random(1, 7, 1)]

; Populate 90% zeroes and 10% ones while counting ones
For $i = 0 To $i_01 - 1
    $a[$i][0] = Int(Random(0, 9, 1) / 9)
    If $a[$i][0] Then $i_1 += 1
Next

; check ratio
ConsoleWrite($i_01 & " entries: " & $i_01 - $i_1 & " zeroes and " & $i_1 & " ones (" & Round($i_1 * 100 / $i_01, 2) & "%)" & @LF)

 

4 hours ago, Funtime60 said:

However, I wish to avoid having all the 1's clustered together as is theoretically possible with Random()

Then this isn't [pseudo]random at all. Even with a 90/10 ratio (or 9999/1 or whatever ratio you can choose), a random array perfectly could have all 0 or all 1, without violating any randomness assumption. Same for any number of consecutive invokation to some PRNG.

If you want he "neighbourness" of 1's to follow some law you must make it somehow explicit for it to be modelisable by code. The bold part of the quotation is way too vague to represent anything close to a specification.

May I ask what's the use of this ad hoc distribution?

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

There are many ways to do this. Another way could be this: 

#include <Array.au3>

$i = random(1, 1000, 1)
local $array[$i]

for $x = 0 to ($i - 1)
   $p = Random(0, 1000, 1)
   if $p > 900 Then
      $array[$x] = 1
      $x = $x+1
      $array[$x] = 0
   else
      $array[$x] = 0
   EndIf
Next

_ArrayDisplay($array)

It gives 1s a 10% to show up but forces them to never be next to one another, but as jchd said, there still is a possibility of the array to be all 0s. Just what you get from pure randomness. 

Link to comment
Share on other sites

I just want to say that my potential solution IS a solution to my problem and I apologize for my delayed response.

I'm sorry I don't understand some of what you meant jchd.

My use for this is a Minefield generator for a Mine Sweeper clone that I decided to make because I was bored. I'm sorry if I didn't use the correct terminology, I hope this more precise target can clear up my goal.

I wish to reiterate that I have solved my own problem so try to come up with your solution only if you feel like that's how you want to spend your time.

This is what I came up with. It will us my "not actually random biased random" function to generate a minefield like those in minesweeper.

#include <Array.au3>

Local $outmask = _GenMask(10,10)
Local $outfield = _GenField($outmask)
_ArrayDisplay($outfield)

Func _GenMask($xsiz, $ysiz, $count = "Default")
    Local $mask[$xsiz][$ysiz]
    Local $masksize = $xsiz * $ysiz
    If $count = "Default" Then
        Local $minepop = Round($masksize * .1)
    Else
        Local $minepop = $count
    EndIf
    Local $minecount = 0
    Local $tmpminecount = 0
    While $minecount < $minepop
        For $xcount = 0 To $xsiz - 1
            For $ycount = 0 To $ysiz - 1
                If $minecount < $minepop Then
                    If $ycount = 0 Then
                        If $xcount = 0 Then
                            Local $minesurround = 0
                        Else
                            Local $minesurround = $mask[$xcount-1][$ycount]
                        EndIf
                    Else
                        If $xcount = 0 Then
                            Local $minesurround = $mask[$xcount][$ycount-1]+$mask[$xcount+1][$ycount-1]
                        ElseIf $xcount = $xsiz - 1 Then
                            Local $minesurround = $mask[$xcount-1][$ycount-1]+$mask[$xcount][$ycount-1]+$mask[$xcount-1][$ycount]
                        Else
                            Local $minesurround = $mask[$xcount-1][$ycount-1]+$mask[$xcount][$ycount-1]+$mask[$xcount+1][$ycount-1]+$mask[$xcount-1][$ycount]
                        EndIf
                    EndIf
                    If _RandBias(0,1,$minesurround+$tmpminecount,100,6) <> 0 Then
                        $mask[$xcount][$ycount] = 1
                        $minecount += 1
                        $tmpminecount += 1
                    Else
                        $tmpminecount -= 0.1
                    EndIf
                EndIf
            Next
        Next
    WEnd
    Return($mask)
EndFunc

Func _GenField($amask)
    Local $xsiz = UBound($amask, 1)
    Local $ysiz = UBound($amask, 2)
    Local $afield[$xsiz][$ysiz]
    For $xcount = 0 To $xsiz - 1
        For $ycount = 0 To $ysiz - 1
            If $amask[$xcount][$ycount] = 1 Then
                $afield[$xcount][$ycount] = "*"
            Else
                If $ycount = 0 Then
                    If $xcount = 0 Then
                        Local $minesurround = $amask[$xcount+1][$ycount]+$amask[$xcount][$ycount+1]+$amask[$xcount+1][$ycount+1]
                    ElseIf $xcount = $xsiz - 1 Then
                        Local $minesurround = $amask[$xcount-1][$ycount]+$amask[$xcount-1][$ycount+1]+$amask[$xcount][$ycount+1]
                    Else
                        Local $minesurround = $amask[$xcount-1][$ycount]+$amask[$xcount+1][$ycount]+$amask[$xcount-1][$ycount+1]+$amask[$xcount][$ycount+1]+$amask[$xcount+1][$ycount+1]
                    EndIf
                ElseIf $ycount = $ysiz - 1 Then
                    If $xcount = 0 Then
                        Local $minesurround = $amask[$xcount][$ycount-1]+$amask[$xcount+1][$ycount-1]+$amask[$xcount+1][$ycount]
                    ElseIf $xcount = $xsiz - 1 Then
                        Local $minesurround = $amask[$xcount-1][$ycount-1]+$amask[$xcount][$ycount-1]+$amask[$xcount-1][$ycount]
                    Else
                        Local $minesurround = $amask[$xcount-1][$ycount-1]+$amask[$xcount][$ycount-1]+$amask[$xcount+1][$ycount-1]+$amask[$xcount-1][$ycount]+$amask[$xcount+1][$ycount]
                    EndIf
                Else
                    If $xcount = 0 Then
                        Local $minesurround = $amask[$xcount][$ycount-1]+$amask[$xcount+1][$ycount-1]+$amask[$xcount+1][$ycount]+$amask[$xcount][$ycount+1]+$amask[$xcount+1][$ycount+1]
                    ElseIf $xcount = $xsiz - 1 Then
                        Local $minesurround = $amask[$xcount-1][$ycount-1]+$amask[$xcount][$ycount-1]+$amask[$xcount-1][$ycount]+$amask[$xcount-1][$ycount+1]+$amask[$xcount][$ycount+1]
                    Else
                        Local $minesurround = $amask[$xcount-1][$ycount-1]+$amask[$xcount][$ycount-1]+$amask[$xcount+1][$ycount-1]+$amask[$xcount-1][$ycount]+$amask[$xcount+1][$ycount]+$amask[$xcount-1][$ycount+1]+$amask[$xcount][$ycount+1]+$amask[$xcount+1][$ycount+1]
                    EndIf
                EndIf
                If $minesurround > 0 Then
                    $afield[$xcount][$ycount] = $minesurround
                EndIf
            EndIf
        Next
    Next
    Return($afield)
EndFunc

Func _RandBias($min, $max, $bias = 0, $mult = 100, $AvoExp = 1)
    Local $modmax = ($mult*$max) - $bias^$AvoExp
    Return(Round(Random($min,$modmax)/$mult))
EndFunc

 

Edited by Funtime60
Poor choice of words, Defined Word1 using Word1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...