Spirograph Thời gian!


14

Spirograph là một món đồ chơi thu hút hypotrochoids và epitrochoids. Đối với thử thách này, chúng ta sẽ chỉ tập trung vào các thuốc giảm đau.

Từ Wikipedia :

Một hypotrochoid là một roulette được theo dõi bởi một điểm gắn liền với một vòng tròn bán kính r lăn quanh bên trong một vòng tròn cố định bán kính R , trong đó điểm là một khoảng cách d từ tâm của vòng tròn bên trong.

Các phương trình tham số cho chúng có thể được định nghĩa là:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Trong đó θ là góc tạo bởi phương ngang và tâm của đường tròn lăn.


Nhiệm vụ của bạn là viết một chương trình sẽ vẽ đường dẫn được vạch ra bởi điểm được xác định ở trên. Là đầu vào, bạn sẽ được cấp R , rd , tất cả các số nguyên nằm trong khoảng từ 1 đến 200.

Bạn có thể nhận đầu vào này từ stdin, đối số hoặc đầu vào của người dùng, nhưng nó không thể được mã hóa cứng vào chương trình. Bạn có thể chấp nhận nó dưới bất kỳ hình thức nào thuận tiện nhất cho bạn; như chuỗi, số nguyên, vv

Giả định:

  • Đơn vị đầu vào được đưa ra bằng pixel.
  • R > = r

Đầu ra phải là một biểu diễn đồ họa của hypotrochoid được xác định bởi đầu vào. Không cho phép ASCII- hoặc đầu ra dựa trên văn bản khác. Hình ảnh này có thể được lưu vào một tập tin hoặc hiển thị trên màn hình. Bao gồm một ảnh chụp màn hình hoặc hình ảnh của đầu ra cho đầu vào của sự lựa chọn của bạn.

Bạn có thể chọn bất kỳ màu nào bạn thích cho đường dẫn / nền, theo giới hạn tương phản. Hai màu phải có thành phần 'Giá trị' HSV cách nhau ít nhất một nửa tỷ lệ. Chẳng hạn, nếu bạn đang đo HSV từ [0...1]đó, nên có ít nhất 0.5sự khác biệt. Giữa [0...255]nên có một 128sự khác biệt tối thiểu .


Đây là một mã golf, kích thước tối thiểu của mã nguồn tính bằng byte thắng.


Chúng ta có thể giả định R > rhay R ≥ rkhông? (Tương tự cho rd.)
Martin Ender

10
Chúc mừng bạn đã đăng câu hỏi thứ 2000! ;-)
Doorknob

@ m.buettner R>=r, nhưng dkhông bị hạn chế rvà có thể ở bất kỳ đâu trong phạm vi 1-200.
Geobits

Chúng ta đang nói về loại giải pháp nào?
Kyle Kanos

@KyleKanos Vì đầu vào tính bằng pixel và mỗi pixel có giới hạn 200, nên không bao giờ lớn hơn 798x798 R=200, r=1, d=200. Bạn có thể kích thước hình ảnh thành đầu vào nếu bạn muốn hoặc giữ nó ở kích thước không đổi, miễn là nó hiển thị.
Geobits

Câu trả lời:


8

Toán học, 120 byte

f[R_,r_,d_]:=ParametricPlot[p#@t+#[-p*t/r]d&/@{Cos,Sin},{t,0,2r/GCD[p=R-r,r]Pi},PlotRange->400,ImageSize->800,Axes->0>1]

Mã không được mã hóa và đầu ra ví dụ: nhập mô tả hình ảnh ở đây

Nếu tôi có thể bao gồm các trục trong cốt truyện, tôi có thể lưu thêm 9 ký tự.


5

JavaScript (ECMAScript 6) - 312 314 Ký tự

document.body.appendChild(e=document.createElement("canvas"))
v=e.getContext("2d")
n=(e.width=e.height=800)/2
M=Math
P=2*M.PI
t=0
p=prompt
r=p('r')
R=p('R')-r
d=p('d')
X=x=>n+R*M.cos(t)+d*M.cos(R/r*t)
Y=x=>n+R*M.sin(t)-d*M.sin(R/r*t)
v.beginPath()
v.moveTo(X(),Y())
for(;t<R*P;v.lineTo(X(),Y()))t+=P/2e4
v.stroke()

NHANH CHÓNG

Ví dụ đầu ra

r = 1, R = 200, d = 30

nhập mô tả hình ảnh ở đây


Tôi thích nó, nhưng ikt bị hỏng bằng cách nào đó. Hãy thử các ví dụ trong R.
edc65

Dòng cuối cùng có thể dành cho (; t <R * P; v.lineTo (X (), Y ())) t + = P / R
edc65

@ edc65 Nó không bị hỏng, nó chỉ không thực hiện đủ số lần lặp để thực hiện một vòng quay đầy đủ trong các ví dụ đó. Tôi đã tăng số lần lặp từ 9 * PI lên R * 2 * PI và nó sẽ tốt hơn (tuy nhiên, tôi đã để lại mức tăng ở PI / 1000 vì nếu không nó sẽ phá vỡ các giá trị nhỏ của R).
MT0

3

Con trăn: 579

Tóm lược

Điều này hoàn toàn không cạnh tranh khi đưa ra câu trả lời Mathicala, nhưng tôi đã quyết định đăng nó vì dù sao những bức ảnh này rất đẹp và nó có thể truyền cảm hứng cho ai đó hoặc hữu ích cho ai đó. Bởi vì nó lớn hơn nhiều, về cơ bản, tôi đã bỏ mặc nó. Chương trình mong đợi đầu vào dòng lệnh của R, r, d.

Ảnh chụp màn hình

Đây là hai ví dụ, một cho (5,3,5) và một cho (10,1,7) ví dụ 5-3-5 ví dụ 10-1-7

import math
import matplotlib.pyplot as P
from matplotlib.path import Path as H
import matplotlib.patches as S
import sys
a=sys.argv
(R,r,d)=int(a[1]),int(a[2]),int(a[3])
v=[]
c=[]
c.append(H.MOVETO)
t=0
while(len(v)<3 or v.count(v[-1])+v.count(v[-2])<3):
 p=t*math.pi/1000
 t+=1
 z=(R-r)*p/r
 v.append((round((R-r)*math.cos(p)+d*math.cos(z),3),round((R-r)*math.sin(p)-d*math.sin(z),3)))
 c.append(H.LINETO)
c.pop()
v.append((0,0))
c.append(H.CLOSEPOLY)
f=P.figure()
x=f.add_subplot(111)
x.add_patch(S.PathPatch(H(v,c)))
l=R+d-r
x.set_xlim(-l-1,l+1)
x.set_ylim(-l-1,l+1)
P.show()

2
Bạn có thể điều chỉnh tỷ lệ? Có vẻ như hình ảnh được nén theo chiều dọc.
AL

3

Perl / Tk - 239 227

use Tk;($R,$r,$d)=@ARGV;$R-=$r;$s=$R+$d;$c=tkinit->Canvas(-width=>2*$s,-height=>2*$s)->pack;map{$a=$x;$b=$y;$x=$s+$R*cos($_/=100)+$d*cos$_*$R/$r;$y=$s+$R*sin($_)-$d*sin$_*$R/$r;$c->createLine($a,$b,$x,$y)if$a}0..628*$s;MainLoop

R = 120, r = 20, d = 40:

R = 120, r = 20, d = 40

R = 128, r = 90, d = 128:

R = 128, r = 90, d = 128

R = 179, r = 86, d = 98:

R = 179, r = 86, d = 98


2

Chế biến, 270

import java.util.Scanner;
void setup(){size(500, 500);}
Scanner s=new Scanner(System.in);
int R=s.nextInt(),r=s.nextInt(),d=s.nextInt();
void draw(){
  int t=width/2,q=(R-r);
  for(float i=0;i<R*PI;i+=PI/2e4)
    point(q*sin(i)-d*sin(i*q/r)+t,q*cos(i)+d*cos(i*q/r)+t);
}

Đầu vào được nhập thông qua bàn điều khiển, một số trên mỗi dòng.

Ảnh chụp màn hình cho R = 65, r = 15, d = 24: nhập mô tả hình ảnh ở đây


2

GeoGebra, 87

Đó là, nếu bạn coi GeoGebra là ngôn ngữ hợp lệ.

R=2
r=1
d=1
D=R-r
Curve[D*cos(t)+d*cos(D*t/r),D*sin(t)-d*sin(D*t/r),t,0,2π*r/GCD[D,r]]

Chấp nhận đầu vào từ thanh đầu vào GeoGebra, theo định dạng <variable>=<value>, ví dụ R=1000.

Lưu ý rằng bạn có thể cần thay đổi kích thước thu phóng theo cách thủ công để xem toàn bộ hình ảnh.

ảnh chụp màn hình

(Thứ ở dưới cùng của cửa sổ là thanh đầu vào mà tôi đang nói đến)

Hãy thử trực tuyến tại đây .


1
Tôi cho rằng điều này có giới hạn giống như trình của Kyle Kanos, rằng bạn không thể chỉ định kích thước bằng pixel?
Martin Ender

@ m.buettner Có bạn đúng ... đã bỏ lỡ điều đó
user12205

2

HTML + Javascript 256 286 303

Chỉnh sửa Đã xóa cuộc gọi đầu tiên để di chuyển, nó vẫn hoạt động. Có thể tiết kiệm nhiều hơn cắt startPath, nhưng sau đó nó chỉ hoạt động lần đầu tiên

Edit2 30 byte lưu thx @ ӍѲꝆΛҐӍΛПҒЦꝆ

<canvas id=c></canvas>R,r,d:<input oninput="n=400;c.width=c.height=t=n+n;v=c.getContext('2d');s=this.value.split(',');r=s[1],d=s[2],R=s[0]-r;v.beginPath();for(C=Math.cos,S=Math.sin;t>0;v.lineTo(n+R*C(t)+d*C(R/r*t),n+R*S(t)-d*S(R/r*t)),t-=.02);v.stroke()">

Kiểm tra

Đặt đầu vào trong hộp văn bản (được phân tách bằng dấu phẩy), sau đó nhấn tab

R,r,d:<input onchange="n=400;c.width=c.height=t=n+n;v=c.getContext('2d');s=this.value.split(',');r=s[1],d=s[2],R=s[0]-r;v.beginPath();for(C=Math.cos,S=Math.sin;t>0;v.lineTo(n+R*C(t)+d*C(R/r*t),n+R*S(t)-d*S(R/r*t)),t-=.02);v.stroke()"><canvas id=c></canvas>


1
Bạn không thể chỉ cần thêm một id vào khung vẽ và sử dụng id đó trên toàn cầu thay vì phải sử dụng querySelector!
Mama Fun Roll

@ ӍѲꝆΛҐӍΛӍѲꝆΛҐӍΛҒЦꝆ yeeeeee tôi có thể. Đó là điều mà tôi không biết trong
edc65

Wow đó là cách tiết kiệm nhiều byte hơn tôi nghĩ.
Mama Fun Roll

2

R, 80 byte

f=function(R,r,d){a=0:1e5/1e2;D=R-r;z=D*exp(1i*a)+d*exp(-1i*D/r*a);plot(z,,'l')}

Tuy nhiên, nếu ai đó muốn số liệu 'sạch' (không có trục, không nhãn, v.v.), thì mã sẽ phải dài hơn một chút (88 ký tự):

f=function(R,r,d)plot((D=R-r)*exp(1i*(a=0:1e5/1e2))+d*exp(-1i*D/r*a),,'l',,,,,,'','',,F)

Một ví dụ mã sử dụng phiên bản dài hơn của f:

f(R<-179,r<-86,d<-98);title(paste("R=",R,", r=",r," d=",d,sep=""))

Một số ví dụ đầu ra:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


Điều này không có kích thước đầu vào bằng pixel, phải không? Ví dụ đầu tiên phải lớn gấp gần ba lần so với ví dụ thứ hai.
Martin Ender

Tại sao tất cả ,??
plannapus

Dấu phẩy được sử dụng để phân tách các đối số, nhiều trong số đó là NULL (không có gì). Ở đây, đối số vị trí phù hợp đã được sử dụng để giảm độ dài của mã. Tất nhiên đây là thực hành mã hóa xấu. Cách được đề xuất là sử dụng danh sách đối số có tên, chẳng hạn như type = "l", xlabel = "", v.v (và loại bỏ các dấu phẩy thừa!).
Phong

1

C # 813, là 999

Cần một số công việc để giảm số byte. Tôi quản lý để giảm nó một chút. Nó chấp nhận ba số nguyên phân tách không gian từ Bảng điều khiển.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
class P:Form
{
int R,r,d;
P(int x,int y,int z) {R=x;r=y;d=z;}
protected override void OnPaint(PaintEventArgs e)
{
if(r==0)return;
Graphics g=e.Graphics;
g.Clear(Color.Black);
int w=(int)this.Width/2;
int h=(int)this.Height/2;
List<PointF> z= new List<PointF>();
PointF pt;
double t,x,y;
double pi=Math.PI;
for (t=0;t<2*pi;t+=0.001F)
{
x=w+(R-r)*Math.Cos(t)+d*Math.Cos(((R-r)/r)*t);
y=h+(R-r)*Math.Sin(t)-d*Math.Sin(((R-r)/r)*t);
pt=new PointF((float)x,(float)y);
z.Add(pt);
}
g.DrawPolygon(Pens.Yellow,z.ToArray());
}
static void Main()
{
char[] d={' '};
string[] e = Console.ReadLine().Split(d);
Application.Run(new P(Int32.Parse(e[0]),Int32.Parse(e[1]),Int32.Parse(e[2])));
}
}

Mẫu đầu ra:

Xoắn ốc


1

tập lệnh shell + gnuplot (153)

Hầu hết các nỗ lực là để loại bỏ các trục và tics, thiết lập kích thước và phạm vi, và tăng độ chính xác. Rất may, gnuplot là tự nhiên để chơi golf, vì vậy hầu hết các lệnh có thể được viết tắt. Để lưu các ký tự, đầu ra phải được chuyển hướng đến một tệp hình ảnh theo cách thủ công.

gnuplot<<E
se t pngc si 800,800
se pa
se sa 1e4
uns bor
uns tic
a=$1-$2
b=400
p[0:2*pi][-b:b][-b:b]a*cos($2*t)+$3*cos(a*t),a*sin($2*t)-$3*sin(a*t) not
E

Gọi kịch bản với spiro.sh 175 35 25>i.pngcho nhập mô tả hình ảnh ở đây


1

R, 169 ký tự

f=function(R,r,d){png(w=2*R,h=2*R);par(mar=rep(0,4));t=seq(0,R*pi,.01);a=R-r;x=a*cos(t)+d*cos(t*a/r);y=a*sin(t)-d*sin(t*a/r);plot(x,y,t="l",xaxs="i",yaxs="i");dev.off()}

Thụt lề:

f=function(R,r,d){
    png(w=2*R,h=2*R) #Creates a png device of 2*R pixels by 2*R pixels
    par(mar=rep(0,4)) #Get rid of default blank margin
    t=seq(0,R*pi,.01) #theta
    a=R-r
    x=a*cos(t)+d*cos(t*a/r)
    y=a*sin(t)-d*sin(t*a/r)
    plot(x,y,t="l",xaxs="i",yaxs="i") #Plot spirograph is a plot that fits tightly to it (i. e. 2*R by 2*R)
    dev.off() #Close the png device.
}

Ví dụ:

> f(65,15,24)

nhập mô tả hình ảnh ở đây

> f(120,20,40)

nhập mô tả hình ảnh ở đây

> f(175,35,25)

nhập mô tả hình ảnh ở đây


1

SmileBASIC, 96 byte

INPUT R,Q,D
M=R+MAX(Q,D)
S=R-Q@L
GPSET M+S*COS(I)+D*COS(S/Q*I),M+S*SIN(I)-D*SIN(S/Q*I)I=I+1GOTO@L

Đầu vào: 50,30,50:

nhập mô tả hình ảnh ở đây


1

Befunge-98, 113 byte

&&:00p-10p&20p"PXIF"4(10g'd:*:I10v>H40gF1+:"}`"3**`>jvI@
1(4"TURT"p04/d'*g02I/g00*p03/d'*g<^-\0/g00*g01:Fg03H:<0P

Mã này dựa trên dấu vân tay Toán học điểm cố định (FIXP) cho một số phép tính lượng giác và dấu vân tay Đồ họa rùa (TURT) để vẽ đường đi của hình xoắn ốc .

Đồ họa Rùa trong Befunge rất giống với đồ họa trong ngôn ngữ lập trình Logo . Bạn vẽ bằng một "con rùa" (đóng vai trò là cây bút của bạn), mà bạn điều khiển xung quanh bề mặt đầu ra. Điều này đòi hỏi phải định hướng con rùa theo một hướng cụ thể, và sau đó hướng dẫn nó di chuyển về phía trước một khoảng cách nhất định.

Để làm việc với hệ thống này, tôi cần điều chỉnh các phương trình spirograph ban đầu thành một cái gì đó thân thiện với rùa hơn một chút. Tôi không chắc đây có phải là cách tiếp cận tốt nhất hay không, nhưng thuật toán tôi nghĩ ra có tác dụng như thế này:

ratio = (R-r)/r
distance1 = sin(1°) * (R-r)
distance2 = sin(1° * ratio) * d
foreach angle in 0° .. 36000°:
  heading(angle)
  forward(distance1)
  heading(-ratio*angle)
  forward(distance2)

Lưu ý rằng điều này thực sự vẽ đường dẫn với một kiểu hình zig-zag, nhưng bạn không thực sự chú ý trừ khi bạn phóng to hình ảnh.

Đây là một ví dụ sử dụng các tham số R = 73, r = 51, d = 45.

nhập mô tả hình ảnh ở đây

Tôi đã kiểm tra mã với CCBI cfunge , cả hai đều tạo đầu ra dưới dạng hình ảnh SVG. Vì đây là định dạng vectơ có thể mở rộng, hình ảnh thu được không có kích thước pixel như vậy - nó chỉ có tỷ lệ để phù hợp với kích thước màn hình (ít nhất là khi được xem trong trình duyệt). Ví dụ trên là một ảnh chụp màn hình đã được cắt và thu nhỏ thủ công.

Về lý thuyết, mã cũng có thể hoạt động trên Rc / Funge , nhưng trong trường hợp đó, bạn cần phải chạy trên một hệ thống với XWindows, vì nó sẽ cố gắng hiển thị đầu ra trong một cửa sổ.


0

wxMaxima : 110

f(R,r,d):=plot2d([parametric,(p:R-r)*cos(t)+d*cos(t*(p)/r),(p)*sin(t)-d*sin(t*(p)/r),[t,0,2*%pi*r/gcd(p,r)]]);

Điều này được gọi trong phiên tương tác thông qua f(#,#,#). Như một mẫu, xem xét f(3,2,1):

nhập mô tả hình ảnh ở đây


Mặc dù tôi thích đầu ra đẹp, tôi không chắc cách này theo "số nguyên trong khoảng từ 1 đến 200" hoặc "được cung cấp dưới dạng pixel".
Geobits

Đầu vào có thể là số nguyên hoặc số float, wxMaxima sẽ chuyển đổi thành float để thực hiện công việc của nó bằng mọi cách, tôi sẽ cập nhật hình ảnh bằng cách sử dụng số nguyên. Tôi cũng sẽ phải suy nghĩ nhiều hơn về đầu vào dưới dạng pixel.
Kyle Kanos

Vâng, tôi hình dung nó sẽ chuyển đổi chúng trong nội bộ, và đó không phải là vấn đề. Các ràng buộc số nguyên trên đầu vào chủ yếu là để có được các vòng khép kín dễ dàng hơn (chúng chỉ trông imo tốt hơn).
Geobits

0

Vợt

#lang racket/gui
(require 2htdp/image)

(define frame (new frame%
                   [label "Spirograph"]
                   [width 300]
                   [height 300]))

(define-values (R r d) (values 50 30 10)) ; these values can be adjusted;

(new canvas% [parent frame]
     [paint-callback
      (lambda (canvas dc)
        (send dc set-scale 3 3)
        (for ((t (in-range 0 (* 10(* R pi)) 1)))
          (define tr (degrees->radians t))
          (define a (- R r))
          (define x (+ (* a (cos tr))
                       (* d (cos (* tr (/ a r))))))
          (define y (- (* a (sin tr))
                       (* d (sin (* tr (/ a r))))))
          (send dc draw-ellipse (+ x 50) (+ y 50) 1 1)))])

(send frame show #t)

Đầu ra:

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.