mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
generate-alt-random-writes: use python random, allow setting a seed
Using Python's own PRNG should make the code cleaner and allow for
reproducible stimulus files if that is desired via setting --seed (at
least for the same versions of the script, changing the kind and/or
order of the random calls will of course impact the output in the
future).
I did the following substitutions:
* rand.read(1)[0] % n and struct.unpack('@H', rand.read(2))[0] % n →
random.randrange(n)
* rand.read(1)[0] → random.randrange(256)
* rand.read(n) → [random.randrange(256) for _ in range(n)]
(better alternative would have been random.randbytes(n), but is only
available for Python >= 3.9, switching to this in the future will
impact output)
* list[rand.read(1) % len(list)] → random.choice(list)
This commit is contained in:
parent
339acc57cf
commit
050da302b8
1 changed files with 101 additions and 99 deletions
|
|
@ -3,6 +3,7 @@ import argparse
|
|||
import enum
|
||||
import fcntl
|
||||
import struct
|
||||
import random
|
||||
import sys
|
||||
import termios
|
||||
|
||||
|
|
@ -31,6 +32,7 @@ def main():
|
|||
parser.add_argument('--attr-italic', action='store_true')
|
||||
parser.add_argument('--attr-underline', action='store_true')
|
||||
parser.add_argument('--sixel', action='store_true')
|
||||
parser.add_argument('--seed', type=int)
|
||||
|
||||
opts = parser.parse_args()
|
||||
out = opts.out if opts.out is not None else sys.stdout
|
||||
|
|
@ -61,133 +63,133 @@ def main():
|
|||
# Enter alt screen
|
||||
out.write('\033[?1049h')
|
||||
|
||||
with open('/dev/urandom', 'rb') as rand:
|
||||
for _ in range(count):
|
||||
if opts.scroll and rand.read(1)[0] == 0:
|
||||
out.write('\033[m')
|
||||
# uses system time or /dev/urandom if available if opt.seed == None
|
||||
# pin seeding method to make seeding stable across future versions
|
||||
random.seed(a=opts.seed, version=2)
|
||||
|
||||
if opts.scroll_region and rand.read(1)[0] == 0:
|
||||
top = rand.read(1)[0] % 3
|
||||
bottom = rand.read(1)[0] % 3
|
||||
out.write(f'\033[{top};{lines - bottom}r')
|
||||
for _ in range(count):
|
||||
if opts.scroll and random.randrange(256) == 0:
|
||||
out.write('\033[m')
|
||||
|
||||
lines_to_scroll = rand.read(1)[0] % (lines - 1)
|
||||
rev = rand.read(1)[0] % 2
|
||||
if not rev and rand.read(1)[0] % 2:
|
||||
out.write(f'\033[{lines};{cols}H')
|
||||
out.write('\n' * lines_to_scroll)
|
||||
else:
|
||||
out.write(f'\033[{lines_to_scroll + 1}{"T" if rev == 1 else "S"}')
|
||||
continue
|
||||
if opts.scroll_region and random.randrange(256) == 0:
|
||||
top = random.randrange(3)
|
||||
bottom = random.randrange(3)
|
||||
out.write(f'\033[{top};{lines - bottom}r')
|
||||
|
||||
# Generate a random location and a random character
|
||||
row = rand.read(1)[0] % lines
|
||||
col = rand.read(1)[0] % cols
|
||||
c = alphabet[rand.read(1)[0] % len(alphabet)]
|
||||
lines_to_scroll = random.randrange(lines - 1)
|
||||
rev = random.randrange(2)
|
||||
if not rev and random.randrange(2):
|
||||
out.write(f'\033[{lines};{cols}H')
|
||||
out.write('\n' * lines_to_scroll)
|
||||
else:
|
||||
out.write(f'\033[{lines_to_scroll + 1}{"T" if rev == 1 else "S"}')
|
||||
continue
|
||||
|
||||
repeat = rand.read(1)[0] % (cols - col) + 1
|
||||
assert col + repeat <= cols
|
||||
# Generate a random location and a random character
|
||||
row = random.randrange(lines)
|
||||
col = random.randrange(cols)
|
||||
c = random.choice(alphabet)
|
||||
|
||||
color_variant = color_variants[rand.read(1)[0] % len(color_variants)]
|
||||
repeat = random.randrange((cols - col) + 1)
|
||||
assert col + repeat <= cols
|
||||
|
||||
# Position cursor
|
||||
out.write(f'\033[{row + 1};{col + 1}H')
|
||||
color_variant = random.choice(color_variants)
|
||||
|
||||
if color_variant in [ColorVariant.REGULAR, ColorVariant.BRIGHT]:
|
||||
do_bg = rand.read(1)[0] % 2
|
||||
base = 40 if do_bg else 30
|
||||
base += 60 if color_variant == ColorVariant.BRIGHT else 0
|
||||
# Position cursor
|
||||
out.write(f'\033[{row + 1};{col + 1}H')
|
||||
|
||||
idx = rand.read(1)[0] % 8
|
||||
out.write(f'\033[{base + idx}m')
|
||||
if color_variant in [ColorVariant.REGULAR, ColorVariant.BRIGHT]:
|
||||
do_bg = random.randrange(2)
|
||||
base = 40 if do_bg else 30
|
||||
base += 60 if color_variant == ColorVariant.BRIGHT else 0
|
||||
|
||||
elif color_variant == ColorVariant.CUBE:
|
||||
do_bg = rand.read(1)[0] % 2
|
||||
base = 48 if do_bg else 38
|
||||
idx = random.randrange(8)
|
||||
out.write(f'\033[{base + idx}m')
|
||||
|
||||
idx = rand.read(1)[0] % 256
|
||||
if rand.read(1)[0] % 2:
|
||||
# Old-style
|
||||
out.write(f'\033[{base};5;{idx}m')
|
||||
else:
|
||||
# New-style (sub-parameter based)
|
||||
out.write(f'\033[{base}:2:5:{idx}m')
|
||||
elif color_variant == ColorVariant.CUBE:
|
||||
do_bg = random.randrange(2)
|
||||
base = 48 if do_bg else 38
|
||||
|
||||
elif color_variant == ColorVariant.RGB:
|
||||
do_bg = rand.read(1)[0] % 2
|
||||
base = 48 if do_bg else 38
|
||||
rgb = rand.read(3)
|
||||
idx = random.randrange(256)
|
||||
if random.randrange(2):
|
||||
# Old-style
|
||||
out.write(f'\033[{base};5;{idx}m')
|
||||
else:
|
||||
# New-style (sub-parameter based)
|
||||
out.write(f'\033[{base}:2:5:{idx}m')
|
||||
|
||||
if rand.read(1)[0] % 2:
|
||||
# Old-style
|
||||
out.write(f'\033[{base};2;{rgb[0]};{rgb[1]};{rgb[2]}m')
|
||||
else:
|
||||
# New-style (sub-parameter based)
|
||||
out.write(f'\033[{base}:2::{rgb[0]}:{rgb[1]}:{rgb[2]}m')
|
||||
elif color_variant == ColorVariant.RGB:
|
||||
do_bg = random.randrange(2)
|
||||
base = 48 if do_bg else 38
|
||||
|
||||
if opts.attr_bold and rand.read(1)[0] % 5 == 0:
|
||||
out.write('\033[1m')
|
||||
if opts.attr_italic and rand.read(1)[0] % 5 == 0:
|
||||
out.write('\033[3m')
|
||||
if opts.attr_underline and rand.read(1)[0] % 5 == 0:
|
||||
out.write('\033[4m')
|
||||
# use list comprehension in favor of randbytes(n)
|
||||
# which is only available for Python >= 3.9
|
||||
rgb = [random.randrange(256) for _ in range(3)]
|
||||
|
||||
out.write(c * repeat)
|
||||
if random.randrange(2):
|
||||
# Old-style
|
||||
out.write(f'\033[{base};2;{rgb[0]};{rgb[1]};{rgb[2]}m')
|
||||
else:
|
||||
# New-style (sub-parameter based)
|
||||
out.write(f'\033[{base}:2::{rgb[0]}:{rgb[1]}:{rgb[2]}m')
|
||||
|
||||
do_sgr_reset = rand.read(1)[0] % 2
|
||||
if do_sgr_reset:
|
||||
reset_actions = ['\033[m', '\033[39m', '\033[49m']
|
||||
idx = rand.read(1)[0] % len(reset_actions)
|
||||
out.write(reset_actions[idx])
|
||||
if opts.attr_bold and random.randrange(5) == 0:
|
||||
out.write('\033[1m')
|
||||
if opts.attr_italic and random.randrange(5) == 0:
|
||||
out.write('\033[3m')
|
||||
if opts.attr_underline and random.randrange(5) == 0:
|
||||
out.write('\033[4m')
|
||||
|
||||
out.write(c * repeat)
|
||||
|
||||
do_sgr_reset = random.randrange(2)
|
||||
if do_sgr_reset:
|
||||
reset_actions = ['\033[m', '\033[39m', '\033[49m']
|
||||
out.write(random.choice(reset_actions))
|
||||
|
||||
# Leave alt screen
|
||||
out.write('\033[m\033[r\033[?1049l')
|
||||
|
||||
with open('/dev/urandom', 'rb') as rand:
|
||||
if opts.sixel:
|
||||
# The sixel 'alphabet'
|
||||
sixels = '?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
|
||||
if opts.sixel:
|
||||
# The sixel 'alphabet'
|
||||
sixels = '?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
|
||||
|
||||
for _ in range(200):
|
||||
# Offset image
|
||||
out.write(' ' * (rand.read(1)[0] % (cols // 2)))
|
||||
for _ in range(200):
|
||||
# Offset image
|
||||
out.write(' ' * (random.randrange(cols // 2)))
|
||||
|
||||
# Begin sixel
|
||||
out.write('\033Pq')
|
||||
# Begin sixel
|
||||
out.write('\033Pq')
|
||||
|
||||
# Set up 256 random colors
|
||||
for idx in range(256):
|
||||
# param 2: 1=HLS, 2=RGB.
|
||||
# param 3/4/5: HLS/RGB values in range 0-100
|
||||
# (except 'hue' which is 0..360)
|
||||
out.write(f'#{idx};2;{rand.read(1)[0] % 101};{rand.read(1)[0] % 101};{rand.read(1)[0] % 101}')
|
||||
# Set up 256 random colors
|
||||
for idx in range(256):
|
||||
# param 2: 1=HLS, 2=RGB.
|
||||
# param 3/4/5: HLS/RGB values in range 0-100
|
||||
# (except 'hue' which is 0..360)
|
||||
out.write(f'#{idx};2;{random.randrange(101)};{random.randrange(101)};{random.randrange(101)}')
|
||||
|
||||
# Randomize image width/height
|
||||
six_height = struct.unpack('@H', rand.read(2))[0] % (height // 2)
|
||||
six_width = struct.unpack('@H', rand.read(2))[0] % (width // 2)
|
||||
# Randomize image width/height
|
||||
six_height = random.randrange(height // 2)
|
||||
six_width = random.randrange(width // 2)
|
||||
|
||||
# Sixel size. Without this, sixels will be
|
||||
# auto-resized on cell-boundaries. We expect programs
|
||||
# to emit this sequence since otherwise you cannot get
|
||||
# correctly sized images.
|
||||
out.write(f'"0;0;{six_width};{six_height}')
|
||||
# Sixel size. Without this, sixels will be
|
||||
# auto-resized on cell-boundaries. We expect programs
|
||||
# to emit this sequence since otherwise you cannot get
|
||||
# correctly sized images.
|
||||
out.write(f'"0;0;{six_width};{six_height}')
|
||||
|
||||
for row in range(six_height // 6): # Each sixel is 6 pixels
|
||||
# Choose a random color
|
||||
out.write(f'#{rand.read(1)[0] % 256}')
|
||||
for row in range(six_height // 6): # Each sixel is 6 pixels
|
||||
# Choose a random color
|
||||
out.write(f'#{random.randrange(256)}')
|
||||
|
||||
if rand.read(1)[0] == 999999999999:
|
||||
assert False
|
||||
out.write(f'!{six_width}{sixels[rand.read(1)[0] % len(sixels)]}')
|
||||
else:
|
||||
for col in range(six_width):
|
||||
out.write(f'{sixels[rand.read(1)[0] % len(sixels)]}')
|
||||
for col in range(six_width):
|
||||
out.write(f'{random.choice(sixels)}')
|
||||
|
||||
# Next line
|
||||
out.write('-')
|
||||
# Next line
|
||||
out.write('-')
|
||||
|
||||
# End sixel
|
||||
out.write('\033\\')
|
||||
# End sixel
|
||||
out.write('\033\\')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue