自動メタコードゴルフ


13

あなたはすべてのcodegolfの課題にうんざりしています。そのため、Pythonコードを自動的にゴルフするプログラムを作成することにします。3つのテストケースがあります。

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)

ルール:

  1. あなたのプログラムは、私が特別に投稿したコードをターゲットにしてはならず、Python 2コードで動作するはずです。コードゴルフされているソースコードを変更する権利を留保します。複数行の文字列は存在せず(したがって、本格的なパーサーを構築していない)、locals()は呼び出されないと想定することができます。

  2. プログラムの出力は、元のソースコードと同じ方法で実行する必要があります。(つまり、同じ出力を生成する必要があります。出力が同じである限り、変数名と言語構成は変更できます)

  3. STDIOまたはファイルを使用して、ソースコードの入出力を行うことができます。

スコアは、プログラムの出力のバイトの合計になります。

(上記のコードは、GNU Free Documentation License 1.2の下でhttp://rosettacode.org/から取られています)



3
不正行為をするための、試用するボーナステストケースを以下に示します。
Sp3000

4
出力が元のソースコードと同じ方法で[[実行]されるかどうかを判断するためのモデルは何ですか?たとえば、2番目の例では、削除if __name__ == '__main__':は一部のコンテキストの動作に影響を与えるが、他のコンテキストには影響を及ぼさないと考えています。別の例として、ungolfed入力がstdinからintを読み取り、他の何かが与えられた場合に1つのタイプの例外をスローすると仮定した場合、非整数が与えられた場合、golfed入力は異なるタイプの例外をスローできますか?
ピーターテイラー

2
このようなプログラムはどうrandom_long_variable=0;print locals()ですか?
ジャスティン

回答:


4

Python 2.7、794

私はしばらくの間Pythonのミニファイアーを構築するつもりでしたので、これは問題を調査する良い機会です。

このプログラムは、正規表現分析とPythonパーサー操作の組み合わせを使用します。空白は最小限に抑えられます。ユーザーが定義した変数は、1文字の変数(使用されていない!)に置き換えられます。最後に、while True声明はダイエットされます。

3つのテストケースはすべて、正常に実行されていることを確認します。生成されたコードにエラーを引き起こす可能性のある病理学的な例を想像できますが、ほとんどの状況でアルゴリズムは堅牢であるはずです。

結果

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

出力

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)

コード

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(1390から減少)

ボールを転がすための非常にマイルドで、ぶら下がりのフルーツタイプの回答:

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

<--TAB-->本物と交換TABキャラクターに

明らかな欠点:

  • 入力コードでは、インデントはちょうど4つのスペースであると想定されます。

複数行の文字列は想定できないため、指定された行がない'場合"、または指定された行にある場合にのみ、演算子から先頭/末尾のスペースを削除します。これは改善できますが、 <sed regexが常に貪欲であることについてつぶやく>

次のようにテストします。

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

複数行の文字列をチェックする必要はありませんが、最後の2つは間違いなく更新する必要があります。
ネイサンメリル

@NathanMerrillうん。演算子の先頭/末尾のスペースはもう少し良くなりましたが、インデントのスペースは一般化するのがはるかに難しくなります。
デジタル外傷

3

Python 3.4、1134

このプログラムは、ほとんどのプログラムで問題なく動作するはずです。奇妙なことに、Sp3000テストケースは、プログラムよりも私のプログラムの最適化がはるかに簡単です。入力は、最初の引数で指定されたファイルを介して受け入れられます。実際のファイルが変更されます。

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)

使い方:

まず、このプログラムは、プログラムがユーザーと対話するか、ランダムを使用するかどうかを確認します。存在する場合、プログラムは変更されていません。次に、プログラムが実行されます。その後、プログラムはに置き換えられprint "output"ます。最後に、プログラムが出力より短い場合、変更されません。

最適化されたSp3000のプログラム:

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'

最適化されたSp3000のスーパーボーナスプログラム:

最適化されたバージョンは、時間の0.001%だけオフです。

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

1
argvinputおよび以外の外部効果があると確信してrandomいます。これらの効果により、コードが破損します。;)
マーティン・エンダー

2
うん たぶん私はいくつかの非決定論を入れるべきだった- print id(0)良いものです。
Sp3000

@Martin修正(主に)。:)
TheNumberOne


へえ、非常に創造的です。
ネイサンメリル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.