Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Native Vim Random number script

Tags:

vim

random

I know that there are various ways to get random numbers, eg, from the shell. However, I'm running vim on an android phone with very little compiled in. Also, it does not have to be rigorously random. The point is, what's an interesting, or concise, or fast (that is, with vim native functions), or short way to get a sequence of reasonably good random numbers in Vim?

like image 902
q335r49 Avatar asked Oct 05 '12 00:10

q335r49


3 Answers

Try something like

function Rand()
    return str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:])
endfunction

. I know no better option then using some of the time functions (there are two of them: reltime() and localtime(), but the latter is updated only each second). I would prefer to either avoid random numbers or use pyeval('random.randint(1, 10)') (preceded by python import random), because shell is slow and I don’t trust time-based solutions.

Note: documentation says that format of the item returned by reltime() depends on the system, thus I am using reltimestr(), not doing something with reltime()[1] which looks like if it contains nanoseconds.

like image 128
ZyX Avatar answered Oct 21 '22 14:10

ZyX


I've recently played around with random numbers in Vim script myself. Here are some resources that I found in the process.

No Vim script

By all means, use an external random number generator if you can. As a rule, they are better and faster than anything that could be done in Vim script.

For example, try

  • :python import random; print random.randrange(1, 7)
  • :echo system('echo $RANDOM')
  • another scripting language, for example Ruby

Libraries

Vim script libraries. These hopefully strive to provide decent quality RNG implementations.

  • vital.vim is an excellent and comprehensive library created by the vim-jp user group. Their random number generator sports an impressive array of functionality and is the best pure Vim script RNG I know of. vital.vim uses an Xorshift algorithm. Check it out!

    Rolling a die with vital.vim:

    let Random = vital#of('vital').import('Random')
    echo Random.range(1, 7)
    
  • vim-rng is a small random number generator plugin. It exports a couple of global functions that rely on a multiply-with-carry algorithm. This project seems to be a work in progress.

    Rolling a die with rng:

    echo RandomNumber(1, 6)
    
  • magnum.vim is my own little big integer library. I've recently added a random number generator that generates integers of any size. It uses the XORSHIFT-ADD algorithm.

    Rolling a die with magnum.vim:

    let six = magnum#Int(6)
    echo magnum#random#NextInt(six).Add(magnum#ONE).Number()
    
  • Rndm has been around for much longer than the other libraries. Its functionality is exposed as a couple of global functions. Rolling a die with Rndm:

    echo Urndm(1, 6)
    

Discussion and snippets

Finally, a few links to insightful discussion and Vim script snippets.

  • ZyX's reltime snippet on this page.

  • loreb's vimprng project on GitHub has an impressive number of RNG implementations in Vim script. Very useful.

  • This old mailing list discussion has a couple of Vim script snippets. The first one given by Bee-9 is limited to 16 bit but I found it quite effective. Here it is:

    let g:rnd = localtime() % 0x10000
    
    function! Random(n) abort
      let g:rnd = (g:rnd * 31421 + 6927) % 0x10000
      return g:rnd * a:n / 0x10000
    endfunction
    
  • Another script, found in a person named Bart's personal config files.

  • Episode 57 on Vimcasts.org discusses Vim's 'expression register' and refers to random number examples throughout. Refers to this Stackoverflow question and ZyX's snippet. Recommended.

  • The Vim wiki on wikia has an article 'Jump to a random line' that has a few resources not mentioned yet.

like image 28
glts Avatar answered Oct 21 '22 15:10

glts


Based on others' answers and other resources from the internet, I have written two functions to generate a random integer in the given range [Low, High].

Both the two functions receive two arguments: Low and High and return a random number in this range.

Combine Python and Vim script

The first function combines Python and Vim script.

" generate a random integer from range [Low, High] using Python
function! RandInt(Low, High) abort
" if you use Python 3, the python block should start with `python3` instead of
" `python`, see https://github.com/neovim/neovim/issues/9927
python3 << EOF
import vim
import random

# using vim.eval to import variable outside Python script to python
idx = random.randint(int(vim.eval('a:Low')), int(vim.eval('a:High')))

# using vim.command to export variable inside Python script to vim script so
# we can return its value in vim script
vim.command("let index = {}".format(idx))
EOF

return index
endfunction

Pure Vim script

The second function I propose uses pure vim script:

function! RandInt(Low, High) abort
    let l:milisec = str2nr(matchstr(reltimestr(reltime()), '\v\.\zs\d+'))
    return l:milisec % (a:High - a:Low + 1) + a:Low
endfunction

Use luaeval() (Neovim only)

The third way to generate random number is to use lua via luaeval().

" math.randomseed() is need to make the random() function generate different numbers 
" on each use. Otherwise, the first number it generate seems same all the time.
luaeval('math.randomseed(os.time())')
let num = luaeval('math.random(1, 10)')

If you want to generate random number in non-serious occasions, you may use the these methods as a starter.

like image 2
jdhao Avatar answered Oct 21 '22 15:10

jdhao