Auto-meta-code-golf

13

Anda muak dengan semua tantangan codegolf. Karenanya, Anda memutuskan untuk menulis sebuah program yang secara otomatis golf beberapa kode Python untuk Anda. Ada 3 kasus uji:

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)

Aturan:

  1. Program Anda tidak boleh menargetkan kode yang saya poskan secara khusus, dan harus bekerja dengan kode Python 2 apa pun. Saya berhak untuk mengubah kode sumber menjadi codegolfed. Anda dapat berasumsi bahwa tidak ada string multi-line (jadi Anda tidak perlu membuat parser full-blown), dan bahwa penduduk lokal () tidak dipanggil.

  2. Output dari program Anda harus dijalankan dengan cara yang sama dengan kode sumber asli. (Yaitu, itu harus menghasilkan output yang sama. Nama variabel dan konstruksi bahasa dapat diubah, selama output tetap sama)

  3. Anda dapat menggunakan STDIO atau File untuk melakukan input / output kode sumber Anda.

Skor Anda akan menjadi jumlah byte dari output program Anda.

(Kode yang tercantum di atas diambil dari http://rosettacode.org/ di bawah Lisensi Dokumentasi Bebas GNU 1.2 )

Nathan Merrill
sumber
3
Berikut ini adalah contoh uji bonus bagi orang untuk dicoba, untuk dibohongi.
Sp3000
4
Apa model Anda untuk menentukan apakah output " [berjalan] dengan cara yang identik dengan kode sumber asli "? Misalnya untuk contoh kedua, saya percaya bahwa menghapus if __name__ == '__main__':akan memengaruhi perilaku dalam beberapa konteks tetapi tidak yang lain. Sebagai contoh lain, jika input yang tidak disatukan mengasumsikan bahwa ia membaca int dari stdin dan melempar satu jenis pengecualian jika diberi sesuatu yang lain, dapatkah input yang golf melemparkan jenis pengecualian yang berbeda jika diberikan non-integer?
Peter Taylor
2
Bagaimana dengan program seperti ini random_long_variable=0;print locals():?
Justin

Jawaban:

4

Python 2.7, 794

Saya bermaksud membangun minifier untuk Python untuk sementara waktu, jadi ini adalah kesempatan yang baik untuk menyelidiki masalahnya.

Program ini menggunakan campuran analisis ekspresi reguler, dan operasi parser Python. Ruang putih diminimalkan. Variabel yang didefinisikan oleh pengguna digantikan oleh variabel huruf tunggal (yang tidak digunakan!). Akhirnya while Truepernyataan itu dimasukkan ke dalam diet.

Ketiga test case semuanya memverifikasi berjalan dengan benar. Saya bisa membayangkan beberapa contoh patologis yang dapat mengakibatkan kesalahan dalam kode yang dihasilkan tetapi algoritma harus kuat dalam sebagian besar keadaan.

Hasil

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

Keluaran

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)

Kode

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))
Ksatria Logika
sumber
4

sed, 1074 (turun dari 1390)

Jenis jawaban yang sangat ringan, rendah tergantung buah, untuk membuat bola menggelinding:

/^$/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

Ganti <--TAB-->dengan TABkarakter asli

Kelemahan yang jelas:

  • Indentasi diasumsikan persis 4 spasi dalam kode input.

Karena kita dapat mengasumsikan tidak ada string multi-garis, maka kita hanya menghapus spasi di depan / belakang dari operator jika tidak ada 'atau "pada jalur yang diberikan. Ini bisa ditingkatkan, tetapi <bergumam tentang sed regex selalu menjadi serakah> .

Tes sebagai berikut:

$ 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
$ 
Trauma Digital
sumber
Anda tidak perlu memeriksa string multi-line, tetapi dua string terakhir Anda pasti perlu diperbarui.
Nathan Merrill
@NathanMerrill ya. Ruang operator terkemuka / tertinggal sedikit lebih baik sekarang, tapi indentasi akan lebih sulit untuk digeneralisasi - dan di sinilah saya mendapatkan sekitar 2/3 dari keuntungan.
Trauma Digital
3

Python 3.4, 1134

Program ini seharusnya bekerja dengan baik untuk sebagian besar program. Anehnya, test case Sp3000 jauh lebih mudah dioptimalkan untuk program saya daripada program Anda. Input diterima melalui file yang ditentukan dalam argumen pertama. File aktual dimodifikasi.

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)

Bagaimana itu bekerja:

Pertama, program ini memeriksa untuk melihat apakah program Anda berinteraksi dengan pengguna sama sekali atau menggunakan acak. Jika ya, program tidak dimodifikasi. Selanjutnya, program dijalankan. Program ini kemudian diganti denganprint "output" . Akhirnya, jika program lebih pendek dari outputnya, itu tidak dimodifikasi.

Program Sp3000, dioptimalkan:

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'

Program bonus super Sp3000, dioptimalkan:

Versi yang dioptimalkan hanya mematikan 0,001% dari waktu.

import sys
sys.stderr.write(b'')
print b'B\r\n'
TheNumberOne
sumber
1
Saya yakin ada efek eksternal selain argv, inputdan randomyang akan dipecahkan oleh kode Anda. ;)
Martin Ender
2
Hah. Mungkin saya harus memasukkan non-determinisme - print id(0)itu bagus.
Sp3000
@ Martin Diperbaiki (kebanyakan). :)
TheNumberOne
Heh, sangat kreatif.
Nathan Merrill