SR

From Esolang
Jump to navigation Jump to search

SR (Seeded Random) is an esolang invented by User:None1 and inspired by Seed.

Every program in SR consists of 5 numbers separated by spaces. Let's say that these numbers are A B C D and E.

When executing an SR program, first output A as character using the charset !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\n (\n is the line feed). Then let A be (A*B+C)%D. This process is repeated E times.

Examples

Print hello

72 48588 120650 484115 5

Nope. interpreter

46 63241 17783 257074 5

Print hi

72 40 127 258 2

Print fuck

70 28842 30961 68260 4

Implementations

This is a Python implementation, along with a genetic algorithm to generate programs (the examples are all generated using this program), you may need to change the argument when using the algorithm.

import json,gc
from secrets import randbelow
from json import *
def sri(a,b,c,d,e):
    res=''
    strtbl=''.join(map(chr,range(32,127)))+'\n'
    for i in range(e):
        res+=strtbl[a%len(strtbl)]
        a=(a*b+c)%d
    return res
def sr(x):
    return sri(*map(int,x.split()))
def srscore(a,b,c,d,e,s):
    cc=sri(a,b,c,d,e)
    res=1
    for i,j in enumerate(cc):
        res+=256-abs(ord(j)-ord(s[i]))
    return res
def gen(s,m):
    strtbl = ''.join(map(chr, range(32, 127))) + '\n'
    d=randbelow(m-1)+1
    return strtbl.index(s[0]),randbelow(min(m,d)),randbelow(min(m,d)),d,len(s)
GENERATIONS=100000 # Maximum number of generations
CANDIDATES=1000 # Number of genomes
MUTATE_NUM=60 # Bits to XOR when mutating
SHOW=50 # Show every SHOW generations
genomes=[]
scores=[]
pref_sum=[]
new_genomes=[]
temp_genomes=[]
result=None
max_score=-1
def save(s):
    with open('temp.json','w') as f:
        json.dump({'string':s,'genome':genomes,'maxscore':max_score,'result':result},f)
def read(s):
    global genomes,max_score,result
    try:
        with open('temp.json','r') as f:
            t=json.load(f)
            if t['string']!=s:
                return False
            genomes=t['genome']
            max_score=t['maxscore']
            result=t['result']
    except:
        return False
    return True
def select(pref_sum):
    pos=randbelow(pref_sum[-1]+1)
    l,r,ans=0,len(pref_sum)-1,0
    while l<=r:
        mid=(l+r)>>1
        if pref_sum[mid]>=pos:
            ans=mid
            r=mid-1
        else:
            l=mid+1
    return ans
def init(s,m):
    global genomes,new_genomes,pref_sum
    for i in range(CANDIDATES):
        genomes.append(gen(s,m))
def merge_(x,y):
    k=randbelow(4)
    a,b,c,d,e=x
    A,B,C,D,E=y
    return ((a,)+(b,c,d)[:k]+(B,C,D)[k:]+(e,),(a,)+(B,C,D)[:k]+(b,c,d)[k:]+(e,))
def mutate_num(x):
    # return randbelow(MUTATE_NUM*2+1)-MUTATE_NUM+x
    return (x^(1<<randbelow(MUTATE_NUM)) if randbelow(2) else x)
def mutate_(x,m):
    a,b,c,d,e=x
    return a,mutate_num(b)%m,mutate_num(c)%m,mutate_num(d)%m+1,e
def merge():
    global new_genomes
    new_genomes=[]
    fittest = None
    maxscore = -1
    for i, j in enumerate(scores):
        a, b, c, d, e = genomes[i]
        if fittest:
            A, B, C, D, E = fittest
        if (maxscore < j) or (not fittest) or (
                maxscore == j and len(str(a)) + len(str(b)) + len(str(c)) + len(str(d)) + len(str(e)) < len(
                str(A)) + len(str(B)) + len(str(C)) + len(str(D)) + len(str(E))):
            fittest = (a, b, c, d, e)
            maxscore=j
    new_genomes.append(fittest)
    for i in range(CANDIDATES):
        x,y=select(pref_sum),select(pref_sum)
        a,b=merge_(genomes[x],genomes[y])
        new_genomes.append(a),new_genomes.append(b)
def mutate(m):
    global temp_genomes,new_genomes
    temp_genomes=[]
    for i in new_genomes:
        temp_genomes.append(mutate_(i,m))
    new_genomes=temp_genomes[:]
def get_pref_sum(s):
    global scores,genomes,pref_sum
    scores=[]
    pref_sum=[]
    for i in genomes:
        scores.append(srscore(*i,s))
    k=0
    for i in scores:
        k+=i
        pref_sum.append(k)
def record():
    global max_score,result
    sc=max(scores)
    if (not result) or max_score<sc:
        result=genomes[scores.index(sc)]
        max_score=sc
def one_generation(s,m):
    global genomes
    get_pref_sum(s)
    record()
    merge()
    mutate(m)
    genomes=new_genomes[:]
def generate(s,m): # s: target string m: maximum value used
    if not read(s):
        init(s,m)
    for i in range(GENERATIONS):
        one_generation(s, m)
        if (i+1)%50==0:
            print(f'Generation: {i+1}\tMaximum score: {max_score}\tCode: {result}')
            save(s)
            gc.collect()
        if max_score==256*len(s)+1:
            break
    print(f'Generation: {i + 1}\tMaximum score: {max_score}\tCode: {result}')
    print(f'Code: {result}\tScore: {max_score}')

Note

It is guessed but not proved that this esolang can produce any output in the charset.