Auto-meta-codice-golf


13

Sei stufo di tutte le sfide di codegolf. Quindi decidi di scrivere un programma che eseguirà automaticamente il golf del codice Python per te. Esistono 3 casi di test:

print quickSort([0,7,3,-1,8,10,57,2])
def quickSort(arr):
    less = []
    pivotList = []
    more = []
    if len(arr) <= 1:
        return arr
    else:
        pivot = arr[0]
        for i in arr:
            if i < pivot:
                less.append(i)
            elif i > pivot:
                more.append(i)
            else:
                pivotList.append(i)
        less = quickSort(less)
        more = quickSort(more)
        return less + pivotList + more

for i in xrange(1, 101):
    if i % 15 == 0:
        print "FizzBuzz"
    elif i % 3 == 0:
        print "Fizz"
    elif i % 5 == 0:
        print "Buzz"
    else:
        print i

from sys import argv

def randomGenerator(seed=1):
    max_int32 = (1 << 31) - 1
    seed = seed & max_int32

    while True:
        seed = (seed * 214013 + 2531011) & max_int32
        yield seed >> 16

def deal(seed):
    nc = 52
    cards = range(nc - 1, -1, -1)
    rnd = randomGenerator(seed)
    for i, r in zip(range(nc), rnd):
        j = (nc - 1) - r % (nc - i)
        cards[i], cards[j] = cards[j], cards[i]
    return cards

def show(cards):
    l = ["A23456789TJQK"[c / 4] + "CDHS"[c % 4] for c in cards]
    for i in range(0, len(cards), 8):
        print " ", " ".join(l[i : i+8])

if __name__ == '__main__':
    seed = int(argv[1]) if len(argv) == 2 else 11982
    print "Hand", seed
    deck = deal(seed)
    show(deck)

Regole:

  1. Il tuo programma non deve avere come target il codice che ho pubblicato in modo specifico e dovrebbe funzionare con qualsiasi codice Python 2. Mi riservo il diritto di modificare il codice sorgente in fase di codegolf. Puoi presumere che non ci siano stringhe multilinea (quindi non hai creato un parser completo) e che i locali () non vengono chiamati.

  2. L'output del programma dovrebbe essere eseguito in modo identico al codice sorgente originale. (Vale a dire, deve produrre lo stesso output. I nomi delle variabili e i costrutti della lingua possono essere modificati, purché l'output rimanga lo stesso)

  3. È possibile utilizzare STDIO o un file per eseguire l'input / output del codice sorgente.

Il tuo punteggio sarà la somma dei byte dell'output del tuo programma.

(Il codice sopra elencato è stato preso da http://rosettacode.org/ sotto la GNU Free Documentation License 1.2 )



3
Ecco un caso di prova bonus per le persone da provare, per essere subdoli.
Sp3000,

4
Qual è il tuo modello per determinare se l'output " [funziona] in modo identico al codice sorgente originale "? Ad esempio per il secondo esempio, ritengo che la rimozione if __name__ == '__main__':influirebbe sul comportamento in alcuni contesti ma non in altri. Per un altro esempio, se l'input non golfizzato presuppone che legga un int da stdin e genera un tipo di eccezione se viene fornito qualcos'altro, l'input golfizzato può generare un diverso tipo di eccezione se viene assegnato un numero intero?
Peter Taylor,

2
Che dire di un programma come questo random_long_variable=0;print locals():?
Justin

Risposte:


4

Python 2.7, 794

Ho intenzione di costruire un minificatore per Python per un po ', quindi questa è una buona opportunità per indagare sul problema.

Il programma utilizza un mix di analisi di espressioni regolari e operazioni di analisi Python. Lo spazio bianco è ridotto al minimo. Le variabili definite dall'utente vengono sostituite da una variabile a lettera singola (che non è in uso!). Finalmente ilwhile True dichiarazione viene messa a dieta.

I tre casi di test si verificano tutti correttamente. Potrei immaginare alcuni esempi patologici che potrebbero causare errori nel codice generato ma l'algoritmo dovrebbe essere robusto nella maggior parte dei casi.

risultati

228 t1.py
128 t2.py
438 t3.py
794 total

Produzione

def c(a):
 b=[]
 d=[]
 f=[]
 if len(a)<=1:
  return a
 else:
  e=a[0]
  for i in a:
   if i<e:
    b.append(i)
   elif i>e:
    f.append(i)
   else:
    d.append(i)
  b=c(b)
  f=c(f)
  return b+d+f
print c([0,7,3,-1,8,10,57,2])


for i in xrange(1,101):
 if i%15==0:
  print"FizzBuzz"
 elif i%3==0:
  print"Fizz"
 elif i%5==0:
  print"Buzz"
 else:
  print i


from sys import argv
def a(k=1):
 b=(1<<31)-1
 k=k&b
 while 1:
  k=(k*214013+2531011)&b
  yield k>>16
def d(k):
 f=52
 h=range(f-1,-1,-1)
 g=a(k)
 for i,r in zip(range(f),g):
  j=(f-1)-r%(f-i)
  h[i],h[j]=h[j],h[i]
 return h
def m(h):
 l=["A23456789TJQK"[c/4]+"CDHS"[c%4]for c in h]
 for i in range(0,len(h),8):
  print" "," ".join(l[i:i+8])
if __name__=='__main__':
 k=int(argv[1])if len(argv)==2 else 11982
 print"Hand",k
 e=d(k)
 m(e)

Codice

import sys
import re
from tokenize import generate_tokens
from token import tok_name
from keyword import iskeyword

wr = sys.stdout.write

def pyparse(text):
    'Return [TYPE,TOKEN] pair list'
    # Use KEYWORD,NAME,NUMBER,OP,STRING,NL,NEWLINE,COMMENT,INDENT,DEDENT
    rawtokens = generate_tokens(text.readline)
    tokens = [[tok_name[n], t] for n,t,p1,p2,dx in rawtokens]
    for tpair in tokens:
        if tpair[0] == 'NAME' and iskeyword(tpair[1]):
            tpair[0] = 'KEYWORD'
    return tokens

def finduservars(filename):
    'Return a set of user variables that we can replace with a-zA-Z'
    varset = set()
    for line in open(filename):
        line = line.strip()
        match = re.match(r'def\s+(\w+)\s*\((.*)\)\s*:', line)
        if match:
            func, args = match.groups()
            varset.add(func)
            arglist = re.findall(r'(\w+|=)', args)
            for a in arglist:
                if a == '=':
                    break  # keyword args follow - too hard to parse
                varset.add(a)
            continue
        match = re.match(r'(\w+)\s*=.+', line)
        if match:
            assigned = match.group(1)
            varset.add(assigned)
            continue
    return set(v for v in list(varset) if len(v) > 1)

filename = sys.argv[1]
tokenlist = pyparse(open(filename))

# Build map for var->char conversion:
varset = finduservars(filename)
singles = [text for tok,text in tokenlist if tok=='NAME' and len(text)==1]
allvar = [chr(n) for n in range(97,123)+range(65,91)]
charvar = [c for c in allvar if c not in singles]
varreplaced = list(varset)[:len(charvar)]
varmap = dict((v, charvar.pop(0)) for v in varreplaced)

prev = 'NONE'
indent = ['']
output = []
add = output.append
for tok, text in tokenlist:
    if tok == 'NL':
        continue
    elif tok == 'INDENT':
        indent.append( text.replace('    ', ' ') )
        output[-1] = indent[-1]
    elif tok == 'DEDENT':
        indent.pop(-1)
        output[-1] = indent[-1]
    elif tok == 'NEWLINE':
        add(text)
        add(indent[-1])
    elif tok in 'KEYWORD,NAME,NUMBER':
        if prev in 'KEYWORD,NAME,NUMBER':
            add(' ')
        if tok == 'NAME':
            if output[-2] == 'while' and text == 'True':
                add('1') # common verbose idiom
            else:
                add(varmap.get(text, text))
        else:
            add(text)
    else:
        add(text)
    prev = tok

wr(''.join(output))

4

sed, 1074 (giù dal 1390)

Tipo di risposta molto mite, a basso contenuto di frutta, per far rotolare la palla:

/^$/d                  # Remove empty lines
/^[ <--TAB-->]*#/d     # Remove whole-line comments
s/    /<--TAB-->/g     # Replace 4 spaces with tabs
/^[^'"]*$/s/ *([|&:,<>=*/%+-]) */\1/g  # Remove spaces before/after operators

Sostituisci <--TAB-->con realeTAB personaggi

Ovvio difetto:

  • I rientri presuppongono che siano esattamente 4 spazi nel codice di input.

Dal momento che non possiamo assumere stringhe su più righe, quindi eliminiamo gli spazi iniziali / finali dagli operatori solo se non ci sono 'o "sulla linea data. Questo potrebbe essere migliorato, ma <borbotta qualcosa su sed regex sempre avido> .

Prova come segue:

$ cat qs.py fizzbuzz.py cards.py | wc -c
1390
$ sed -rf pygolf.sed qs.py fizzbuzz.py cards.py | wc -c
1074
$ sed -rf pygolf.sed qs.py fizzbuzz.py cards.py | python
[-1, 0, 2, 3, 7, 8, 10, 57]
1
2
Fizz
...
98
Fizz
Buzz
Hand 11982
  AH AS 4H AC 2D 6S TS JS
  3D 3H QS QC 8S 7H AD KS
  KD 6H 5S 4D 9H JH 9S 3C
  JC 5D 5C 8C 9D TD KH 7C
  6C 2C TH QH 6D TC 4S 7S
  JD 7D 8H 9C 2H QD 4C 5H
  KC 8D 2S 3S
$ 

Non è necessario controllare le stringhe multilinea, ma le ultime due devono essere aggiornate.
Nathan Merrill,

@NathanMerrill yup. L'operatore che guida / trascina uno spazio ora è un po 'meglio, ma quello di rientro sarà molto più difficile da generalizzare - ed è dove ottengo circa i 2/3 del guadagno.
Trauma digitale

3

Python 3.4, 1134

Questo programma dovrebbe funzionare bene per la maggior parte dei programmi. Stranamente, il test case Sp3000 è molto più facile da ottimizzare per il mio programma rispetto ai tuoi programmi. L'input è accettato attraverso il file specificato nel primo argomento. Il file effettivo viene modificato.

import subprocess
from sys import argv

progamtext = open(argv[1]).read()

if 'argv' in progamtext or 'input' in progamtext or 'open' in programtext:#Make sure the program always produces the same results.
    exit(0)

program = subprocess.Popen(['C:\Python27\python', argv[1]], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
program.wait()
erroroutput1 = str(program.stderr.read())
output1 = str(program.stdout.read())
program = subprocess.Popen(['C:\Python27\python', argv[1]], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
program.wait()
erroroutput2 = str(program.stderr.read())
output2 = str(program.stdout.read())
if erroroutput1 != erroroutput2 or output1 != output2:#Make sure the program always produces the same results.
    exit(0)

newprog = ''
if erroroutput1:
    newprog += "import sys\n" + "sys.stderr.write("+ erroroutput1 + ')'
    if output1:
        newprog += "\n"
if output1:
    newprog += 'print ' + output1

if len(newprog) > len(progamtext):
    exit(0)

open(argv[1],mode='w').write(newprog)

Come funziona:

Innanzitutto, questo programma verifica se il tuo programma interagisce con l'utente o usa casualmente. In tal caso, il programma non è modificato. Successivamente, viene eseguito il programma. Il programma viene quindi sostituito conprint "output" . Infine, se il programma è più corto del suo output, non è modificato.

Programma Sp3000, ottimizzato:

import sys
sys.stderr.write(b'')
print b'0.540377721372\r\n3\r\n1\r\n7\r\n99\r\nf\r\n[5, 5]\r\n53\r\n53\r\n53\r\n'

Il programma super bonus di Sp3000, ottimizzato:

La versione ottimizzata è solo disattivata .001% delle volte.

import sys
sys.stderr.write(b'')
print b'B\r\n'

1
Sono sicuro che ci sono altri effetti esterni rispetto a argv, inpute random, che il tuo codice potrebbe violare. ;)
Martin Ender l'

2
Hah. Forse avrei dovuto mettere un po 'di non determinismo - print id(0)è buono.
Sp3000,

@Martin Risolto (principalmente). :)
TheNumberOne


Heh, molto creativo.
Nathan Merrill
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.