Open a random file batch

Discussion in 'Software' started by brunchmiracle, Jan 26, 2012.

  1. brunchmiracle

    brunchmiracle Private E-2

    I really need help creating a batch file that would select a random line from a .txt containing files and their paths and open it.

    The text file reads as follows:
    C:\Users\Pictures\asdf.gif
    C:\Users\sdfasdf\Pictures\Art\Animation\asdfad.jpg
    C:\Users\AppData\Local\Microsoft\sound\asda.wav
    etc...

    Any ideas of how this can be done?
     
  2. GermanOne

    GermanOne Guest

    Untested:
    Code:
    @echo off
    :: name of the txt file
    set "txtfile=xyz.txt"
    
    :: count the lines of the txt file
    for /f %%i in ('type "%txtfile%"^|find /c /v ""') do set /a "n = %%i"
    
    :: quit if the file was empty
    if !n!==0 goto :eof
    
    :: calculate a random number between 1 and the number of lines
    set /a "n = %random% %% %n% + 1"
    
    :: read line n
    <"%txtfile%" (
      for /l %%i in (1 1 %n%) do set /p "ln="
    )
    
    :: open the file
    start "" "%ln%"
    
    Regards
    GermanOne
     
  3. brunchmiracle

    brunchmiracle Private E-2

    Thanks GermanOne, your code works great!
    The only problem I'm having is that when I rerun the batch on the same .txt file it always gives me a file that is between 20 and 200 lines after the one it just opened.
    For example, if it opens line 11024, the next time i run it it opens line 11161.
    Do you know if there is any way to switch it up some more?
    Thanks again
     
    Last edited: Jan 27, 2012
  4. GermanOne

    GermanOne Guest

    Well, normally this should not happen because of the modulo operation. But the value in %random% is calculated from the current system time. For that reason %random% stays similar as long as the time has changed only slightly. My own experience is that it differs much more if it is used twice in a batch file. Include that line in the beginning of the code:
    Code:
    >nul echo %random%
    
    Hope that helps.

    Regards
    GermanOne
     
  5. brunchmiracle

    brunchmiracle Private E-2

    you're the best - that both explains and helps my problem, if i wait about 2-3 minutes i get a completely different file so that definitely goes along with the current system time you were talking about. Also, the code i entered at the beginning of the batch helps with this
     
  6. GermanOne

    GermanOne Guest

    Another possible way is to multiply two random numbers before you apply the modulo operation. That could be a good choice especially if there is a high amount of lines in the txt file.
    Some information for your understanding:
    - the value in %random% will expand to a value between 0 and 32767
    - the greatest positive number batch can calculate with is 2^31 - 1 (2147483647)
    - %random% * %random% equals a value between 0 and 1073676289 (which is always less than the greatest numeric value)

    What is this information good for?
    Well, the modulo operation (operator % in a command line or %% in a batch file) returns the remainder of a divission. That means 5 %% 3 = 2 (because 5 / 3 = 1, remainder 2). So far obviously clear. But if the first operator is less than the second then the remainder is alwais the same as the first operator. 3 %% 5 = 3 (because 3 / 5 = 0, remainder 3).
    In your case that means
    - the random number should reach a greater value than the number of lines in your file to NOT getting exactly the random number
    - %random% * %random% means that you use the variable twice. For that reason you don't need my former suggestion.
    Code:
    :: calculate a random number between 1 and the number of lines
    set /a "n = (%random% * %random%) %% %n% + 1"
    
    Regards
    GermanOne
     
  7. PC-XT

    PC-XT Master Sergeant

    GermanOne is a total master of batch files, and I hate to critique him, (as he usually pwns me,) but I thought I should mention that to get the purest randomness (most evenly distributed probabilities) out of the equation, (using modulus,) it should be:
    Code:
    :: calculate a random number between 1 and the number of lines
    set /a "n = (%random% * 32768 + %random%) %% %n% + 1"
    Besides having a slightly larger random range to help choose from many items more randomly, this will also keep probabilities more even than using multiplication. For instance, with multiplying the random numbers, the worst case is between the first two entries, which have about 65536:1 ratio in their probabilities of being chosen. Most of the others vary by much smaller ratios in a sort of wave pattern (somewhat similar to my avatar, btw.) Some primes over 32,768 may never be chosen, but this is rare and can be minimized by increasing randomness or limiting the number of items to choose from. In contrast, the method given here simply concatenates (glues) the bits together, meaning one random number has no effect on the other in the combining, preserving even distribution.

    I recommend the following:
    You can double the input range by taking one bit from another %random% variable:
    Code:
    :: calculate a random number between 1 and the number of lines
    set /a "n = (((%random% & 1) * 1073741824) + (%random% * 32768) + %random%) %% %n% + 1"
    This uses only 1 bit from the first number, so if there is some problem with the numbers being close, it will largely be ignored. (The only information used from the first number is whether it is odd or even.) The method also has a range of 2147483647 possibilities, which, as GermanOne said above, is the limit. Trying to go further will just make the numbers uselessly negative or something, unless you use more than one variable to hold it, and make your own methods to go beyond what the system supports.

    Modulus may vary probabilities, too, but so does any other choosing method, given the same input range (entropy.) All equal probability choosing methods divide the probability as evenly. Their differences are in how they distribute any remainder. Modulus gives it to the lowest numbers. Many try to space it evenly among the choices, but it all boils down to the order the choices happen to be in. The higher the fraction (random number range/things to choose from) the less significant this is. The purest randomness happens when that fraction equates to a positive whole number. If the fraction is less than 1, some things will never be chosen, no matter which method is used, (unless that method gains more entropy to increase the fraction.)
     
    Last edited: Jan 28, 2012
  8. GermanOne

    GermanOne Guest

    Hi PC-XT.

    My example above was a simplified calculation to reach a bigger range. You're absolutely right that some of the primes are never calculated. I like the way you enlarged it to the greatest possible value in your 2nd example.
    Another possibility could be the bitwise calculation in a loop ...
    Code:
    :: calculate a random number between 1 and the number of lines
    setlocal EnableDelayedExpansion
    for /l %%i in (0,1,30) do set /a "i = (i << 1) + (!random! & 1)"
    endlocal &set /a "n = %i% %% %n% + 1"
    
    ... but I assume yours is faster and easier to understand.

    Regards
    GermanOne
     
  9. brunchmiracle

    brunchmiracle Private E-2

    I am eternally indebted to you guys,
    all 4 of these methods work perfectly, and as you said, the two that maximize the random range give me the most varied results. I think I can grasp the concept of random number multiplication before the modulo that GermanOne was talking about, as much as I am struggling to understand your code PC-XT, I can definitely see the implications of allowing for a larger range of choices through dissolution of the random numbers involved in the equation. Thanks again to both of you for helping me with the code and helping me understand how it works!
     
  10. PC-XT

    PC-XT Master Sergeant

    You might understand my code better written this way:
    Code:
    :: calculate a random number between 1 and the number of lines
    set /a "n = (((%random% & 1) << 30) | (%random% << 15) | %random%) %% %n% + 1"
    The multiplications in the other equation are equivalent to these shifts, and the additions to these ORs. (One binary left shift is equivalent to multiplying by 2, so the first large number is 2 to the 30th power and the other is 2 raised to the 15th.) I was using the numbers working with probabilities, but this is more intuitive of how the bits are joined.
     

MajorGeeks.Com Menu

Downloads All In One Tweaks \ Android \ Anti-Malware \ Anti-Virus \ Appearance \ Backup \ Browsers \ CD\DVD\Blu-Ray \ Covert Ops \ Drive Utilities \ Drivers \ Graphics \ Internet Tools \ Multimedia \ Networking \ Office Tools \ PC Games \ System Tools \ Mac/Apple/Ipad Downloads

Other News: Top Downloads \ News (Tech) \ Off Base (Other Websites News) \ Way Off Base (Offbeat Stories and Pics)

Social: Facebook \ YouTube \ Twitter \ Tumblr \ Pintrest \ RSS Feeds