Python的非引用式“参考实现”
更新:快得多(按数量级)
查看交互式外壳!
编辑文件并将其设置interactive
为True
,然后执行以下操作之一:
polygon numberOfPoints numeratorOfWeight denominatorOfWeight startX startY numberOfSides
生成,保存并显示多边形。
points numberOfPoints numeratorOfWeight denominatorOfWeight startX startY point1X point1Y point2X point2Y ...
满足规格要求。
import matplotlib.pyplot as plt
import numpy as np
from fractions import Fraction as F
import random
from matplotlib.colors import ColorConverter
from time import sleep
import math
import sys
import cmd
import time
def plot_saved(n, r, start, points, filetype='png', barsize=30, dpi=100, poly=True, show=False):
printed_len = 0
plt.figure(figsize=(6,6))
plt.axis('off')
start_time = time.clock()
f = F.from_float(r).limit_denominator()
spts = []
for i in range(len(points)):
spts.append(tuple([round(points[i].real,1), round(points[i].imag,1)]))
if poly:
s = "{}-gon ({}, r = {}|{})".format(len(points), n, f.numerator, f.denominator)
else:
s = "{} ({}, r = {}|{})".format(spts, n, f.numerator, f.denominator)
step = math.floor(n / 50)
for i in range(len(points)):
plt.scatter(points[i].real, points[i].imag, color='#ff2222', s=50, alpha=0.7)
point = start
t = time.clock()
xs = []
ys = []
for i in range(n+1):
elapsed = time.clock() - t
#Extrapolation
eta = (n+1-i)*(elapsed/(i+1))
printed_len = rewrite("{:>29}: {} of {} ({:.3f}%) ETA: {:.3f}s".format(
s, i, n, i*100/n, eta), printed_len)
xs.append(point.real)
ys.append(point.imag)
point = point * r + random.choice(points) * (1 - r)
printed_len = rewrite("{:>29}: plotting...".format(s), printed_len)
plt.scatter(xs, ys, s=0.5, marker=',', alpha=0.3)
presave = time.clock()
printed_len = rewrite("{:>29}: saving...".format(s), printed_len)
plt.savefig(s + "." + filetype, bbox_inches='tight', dpi=dpi)
postsave = time.clock()
printed_len = rewrite("{:>29}: done in {:.3f}s (save took {:.3f}s)".format(
s, postsave - start_time, postsave - presave),
printed_len)
if show:
plt.show()
print()
plt.clf()
def rewrite(s, prev):
spaces = prev - len(s)
sys.stdout.write('\r')
sys.stdout.write(s + ' '*(0 if spaces < 0 else spaces))
sys.stdout.flush()
return len(s)
class InteractiveChaosGame(cmd.Cmd):
def do_polygon(self, args):
(n, num, den, sx, sy, deg) = map(int, args.split())
plot_saved(n, (num + 0.0)/den, np.complex(sx, sy), list(np.roots([1] + [0]*(deg - 1) + [-1])), show=True)
def do_points(self, args):
l = list(map(int, args.split()))
(n, num, den, sx, sy) = tuple(l[:5])
l = l[5:]
points = []
for i in range(len(l)//2):
points.append(complex(*tuple([l[2*i], l[2*i + 1]])))
plot_saved(n, (num + 0.0)/den, np.complex(sx, sy), points, poly=False, show=True)
def do_pointsdpi(self, args):
l = list(map(int, args.split()))
(dpi, n, num, den, sx, sy) = tuple(l[:6])
l = l[6:]
points = []
for i in range(len(l)//2):
points.append(complex(*tuple([l[2*i], l[2*i + 1]])))
plot_saved(n, (num + 0.0)/den, np.complex(sx, sy), points, poly=False, show=True, dpi=dpi)
def do_default(self, args):
do_generate(self, args)
def do_EOF(self):
return True
if __name__ == '__main__':
interactive = False
if interactive:
i = InteractiveChaosGame()
i.prompt = ": "
i.completekey='tab'
i.cmdloop()
else:
rs = [1/2, 1/3, 2/3, 3/8, 5/8, 5/6, 9/10]
for i in range(3, 15):
for r in rs:
plot_saved(20000, r, np.complex(0,0),
list(np.roots([1] + [0] * (i - 1) + [-1])),
filetype='png', dpi=300)