自动元代码高尔夫球


13

您已经厌倦了所有的代码高尔夫挑战。因此,您决定编写一个程序,该程序将自动为您编写一些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自由文档许可1.2http://rosettacode.org/ 获得的



3
这是一个供人们尝试的奖金测试用例,请耐心等待。
Sp3000 2015年

4
您如何确定输出“ [以与原始源代码相同的方式运行 ”?例如,对于第二个示例,我相信删除if __name__ == '__main__':会在某些情况下影响行为,但在其他情况下不会。再举一个例子,如果非高尔夫输入假设它从stdin读取一个int值,并且在给出其他东西的情况下抛出一种异常,那么,如果高尔夫输入使用了非整数的输入,它会抛出另一种异常吗?
彼得·泰勒

2
像这样的程序random_long_variable=0;print locals()呢?
贾斯汀

Answers:


4

Python 2.7、794

我一直想为Python构建一个简化程序,所以这是研究问题的好机会。

该程序混合使用正则表达式分析和Python解析器操作。最小化空白。用户定义的变量将替换为单个字母变量(未使用!)。最后,该while True声明应节制饮食。

这三个测试用例均验证运行正常。我可以想象一些病理示例,这些示例可能会导致生成的代码出错,但是该算法在大多数情况下应该很健壮。

结果

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
$ 

您不需要检查多行字符串,但是您的最后两个肯定需要更新。
内森·美林

@NathanMerrill是的。运算符的前导/尾随空格现在好一点了,但是缩进一个将很难概括-这就是我获得大约2/3的增益的地方。
Digital Trauma 2015年

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的超级奖励计划,已优化:

优化版本仅关闭.001%的时间。

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

1
我敢肯定,除了和之外argv,还有其他外部效果会破坏您的代码。;)inputrandom
Martin Ender 2015年

2
哈哈 也许我应该添加一些不确定性-这print id(0)是一个很好的选择。
Sp3000

@Martin固定(大部分)。:)
TheNumberOne 2015年


嘿,很有创造力。
内森·美林
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.