เวลาสปิโรกราฟ!


14

สปิโรกราฟราเป็นของเล่นที่วาดไฮโปคลอรอยด์และเอพิโตรรอยด์ สำหรับความท้าทายนี้เราจะเน้นที่ไฮโปคลอรอยด์

จากวิกิพีเดีย :

ไฮเปอร์โบรอยด์คือรูเล็ตที่ติดตามโดยจุดที่ติดอยู่กับวงกลมรัศมีr ที่หมุนไปรอบ ๆ ด้านในของรัศมีคงที่Rซึ่งจุดคือระยะทางdจากจุดศูนย์กลางของวงกลมภายใน

สมการพารามิเตอร์สำหรับพวกเขาสามารถกำหนดเป็น:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

โดยที่θคือมุมที่เกิดขึ้นจากแนวนอนและศูนย์กลางของวงกลมกลิ้ง


งานของคุณคือการเขียนโปรแกรมที่จะวาดเส้นทางที่ติดตามโดยจุดที่กำหนดไว้ด้านบน ในฐานะที่เป็นอินพุทคุณจะได้รับR , rและdจำนวนเต็มทั้งหมดตั้งแต่ 1 ถึง 200

คุณสามารถรับอินพุตนี้จาก stdin, อาร์กิวเมนต์หรืออินพุตของผู้ใช้ แต่ไม่สามารถ hardcoded ลงในโปรแกรม คุณสามารถยอมรับได้ในรูปแบบใดก็ตามที่สะดวกที่สุดสำหรับคุณ เป็นสตริงจำนวนเต็ม ฯลฯ

สมมติ:

  • หน่วยอินพุตมีหน่วยเป็นพิกเซล
  • R > = r

เอาท์พุทควรเป็นตัวแทนกราฟิกของ hypotrochoid ที่กำหนดโดยอินพุต ไม่อนุญาตให้ใช้ ASCII หรือเอาต์พุตแบบข้อความอื่น ๆ ภาพนี้สามารถบันทึกเป็นไฟล์หรือแสดงบนหน้าจอ รวมภาพหน้าจอหรือภาพของเอาท์พุทสำหรับอินพุตที่คุณเลือก

คุณสามารถเลือกสีใดก็ได้ที่คุณต้องการสำหรับเส้นทาง / พื้นหลังโดยมีข้อ จำกัด เรื่องความคมชัด สองสีต้องมีองค์ประกอบ 'ค่า' HSV อย่างน้อยครึ่งหนึ่งของขนาดแยกจากกัน ตัวอย่างเช่นหากคุณวัด HSV จาก[0...1]ควรมี0.5ความแตกต่างอย่างน้อยที่สุด ระหว่าง[0...255]ควรมีความ128แตกต่างขั้นต่ำ


นี่คือรหัสกอล์ฟขนาดต่ำสุดของซอร์สโค้ดเป็นไบต์ชนะ


เราสามารถสรุปได้R > rหรือR ≥ r? (เหมือนกันrและd.)
Martin Ender

10
ขอแสดงความยินดีกับการโพสต์คำถามที่ 2000! ;-)
Doorknob

@ m.buettner R>=rแต่dไม่ได้ถูก จำกัดrและสามารถอยู่ที่ใดก็ได้ในช่วง 1-200
Geobits

เรากำลังพูดถึงความละเอียดอะไรกันบ้าง?
Kyle Kanos

@KyleKanos ตั้งแต่การป้อนข้อมูลที่อยู่ในพิกเซลและแต่ละคนมีหมวก 200 มันไม่ควรที่เคยมีขนาดใหญ่กว่า 798x798 R=200, r=1, d=200ให้ คุณสามารถปรับขนาดภาพเป็นอินพุทถ้าคุณต้องการหรือเก็บไว้ที่ขนาดคงที่ตราบใดที่มันสามารถมองเห็นได้ทั้งหมด
Geobits

คำตอบ:


8

Mathematica ขนาด 120 ไบต์

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]

โค้ด Ungolfed และเอาต์พุตตัวอย่าง: ป้อนคำอธิบายรูปภาพที่นี่

หากฉันอาจรวมแกนไว้ในพล็อตฉันสามารถบันทึกอักขระได้อีก 9 ตัว


5

JavaScript (ECMAScript 6) - 312 314 ตัวอักษร

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()

JSFIDDLE

ตัวอย่างผลลัพธ์

r = 1, R = 200, D = 30

ป้อนคำอธิบายรูปภาพที่นี่


ฉันชอบมัน แต่ ikt ก็หักอย่างใด ลองตัวอย่างใน R.
edc65

บรรทัดสุดท้ายอาจเป็น (; t <R * P; v.lineTo (X (), Y ())) t + = P / R
edc65

@ edc65 มันไม่พังแค่ทำซ้ำไม่พอในการหมุนตัวอย่าง ฉันได้เพิ่มการทำซ้ำจาก 9 * PI เป็น R * 2 * PI และควรจะดีกว่า (อย่างไรก็ตามฉันได้เพิ่มส่วนที่เหลือที่ PI / 1000 มิฉะนั้นมันจะแตกสำหรับค่า R ขนาดเล็ก)
MT0

3

Python: 579

สรุป

นี่ไม่ใช่การแข่งขันที่ได้รับคำตอบจาก Mathematica แต่ฉันตัดสินใจที่จะโพสต์ต่อไปเพราะภาพสวยและอาจเป็นแรงบันดาลใจให้ใครบางคนหรือเป็นประโยชน์กับใครบางคน เพราะมันใหญ่กว่ามากฉันจึงทิ้งมันไว้โดยไม่อัปยศ โปรแกรมคาดว่าอินพุตบรรทัดคำสั่งของ R, r, d

ภาพหน้าจอ

นี่คือสองตัวอย่างหนึ่งสำหรับ (5,3,5) และอีกหนึ่งสำหรับ (10,1,7) ตัวอย่างที่ 5-3-5 ตัวอย่างที่ 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
คุณสามารถปรับอัตราส่วนได้หรือไม่? ดูเหมือนว่าภาพจะถูกบีบอัดในแนวตั้ง
อัล

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

กำลังดำเนินการ, 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);
}

อินพุตถูกป้อนผ่านคอนโซลหนึ่งหมายเลขต่อบรรทัด

สกรีนช็อตสำหรับ R = 65, r = 15, d = 24: ป้อนคำอธิบายรูปภาพที่นี่


2

GeoGebra, 87

นั่นคือถ้าคุณพิจารณา GeoGebra เป็นภาษาที่ถูกต้อง

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

รับข้อมูลจากแถบอินพุต GeoGebra ในรูปแบบเช่น<variable>=<value>R=1000

โปรดทราบว่าคุณอาจต้องเปลี่ยนขนาดการซูมด้วยตนเองเพื่อดูทั้งภาพ

ภาพหน้าจอ

(สิ่งที่อยู่ด้านล่างของหน้าต่างคือแถบป้อนข้อมูลที่ฉันพูดถึง)

ลองออนไลน์ได้ที่นี่


1
ฉันคิดว่าสิ่งนี้มีข้อ จำกัด เหมือนกับการส่งของ Kyle Kanos คุณไม่สามารถระบุขนาดเป็นพิกเซลได้หรือไม่
Martin Ender

@ m.buettner ใช่คุณถูก ... พลาดไปแล้ว
user12205

2

HTML + Javascript 256 286 303

แก้ไข ลบสายที่ 1 เพื่อย้ายไปยังทำงานได้อยู่แล้ว สามารถประหยัดการเริ่มต้นการตัดเพิ่มเติมได้ แต่จากนั้นจะทำงานเฉพาะในครั้งแรกเท่านั้น

แก้ไข 2 30 ไบต์บันทึกแล้วขอบคุณ @ ӍѲꝆΛҐӍΛПҒЦꝆ

<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()">

ทดสอบ

ใส่อินพุตในกล่องข้อความ (คั่นด้วยเครื่องหมายจุลภาค) จากนั้นกดแท็บ

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
คุณไม่สามารถเพิ่ม id ลงใน canvas และใช้ id นั้นทั่วโลกแทนที่จะต้องใช้ querySelector!
Mama Fun Roll

@ ӍѲꝆΛҐӍΛПҒЦꝆ yeeeeee ฉันทำได้ มันเป็นสิ่งที่ฉันไม่ทราบในพฤษภาคม 2014
edc65

ว้าวนั่นเป็นวิธีที่ประหยัดได้มากกว่าที่ฉันคิดไว้
Mama Fun Roll

2

R, 80 ไบต์

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')}

อย่างไรก็ตามหากต้องการตัวเลขที่ "สะอาด" (ไม่มีแกนไม่มีป้ายกำกับ ฯลฯ ) รหัสจะต้องยาวขึ้นอีกเล็กน้อย (88 ตัวอักษร):

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

ตัวอย่างรหัสหนึ่งที่ใช้รุ่นที่ยาวกว่าของ f:

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

ตัวอย่างผลลัพธ์:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่


นี่ไม่ได้ใช้ขนาดอินพุตเป็นพิกเซลใช่ไหม ตัวอย่างแรกควรมีขนาดใหญ่เป็นสองเท่าเกือบสองเท่า
Martin Ender

ทำไมทุก,??
plannapus

เครื่องหมายจุลภาคถูกใช้เพื่อแยกการขัดแย้งซึ่งส่วนใหญ่เป็น NULL (ไม่มีอะไร) นี่คือการจับคู่อาร์กิวเมนต์ตำแหน่งเพื่อลดความยาวของรหัส หลักสูตรนี้เป็นการฝึกเขียนโค้ดที่ไม่ดี วิธีที่แนะนำคือการใช้รายการอาร์กิวเมนต์ที่มีชื่อเช่น type = "l", xlabel = "" ฯลฯ (และกำจัดเครื่องหมายจุลภาคซ้ำซ้อน!)
Feng

1

C # 813 คือ 999

ต้องการงานบางอย่างเพื่อลดจำนวนไบต์ ฉันจัดการเพื่อลดมันเล็กน้อย ยอมรับจำนวนเต็มสามช่องว่างคั่นจากคอนโซล

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])));
}
}

ตัวอย่างผลลัพธ์:

spirograph


1

เชลล์สคริปต์ + gnuplot (153)

ความพยายามส่วนใหญ่คือการลบแกนและสำบัดสำนวนตั้งขนาดและช่วงและเพิ่มความแม่นยำ โชคดีที่ gnuplot นั้นเป็นธรรมชาติสำหรับการเล่นกอล์ฟดังนั้นคำสั่งส่วนใหญ่จึงสามารถย่อได้ หากต้องการบันทึกอักขระเอาต์พุตจะต้องถูกเปลี่ยนเส้นทางไปยังไฟล์รูปภาพด้วยตนเอง

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

โทรสคริปต์ด้วยการspiro.sh 175 35 25>i.pngให้ ป้อนคำอธิบายรูปภาพที่นี่


1

R, 169 ตัวละคร

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()}

เยื้อง:

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.
}

ตัวอย่าง:

> f(65,15,24)

ป้อนคำอธิบายรูปภาพที่นี่

> f(120,20,40)

ป้อนคำอธิบายรูปภาพที่นี่

> f(175,35,25)

ป้อนคำอธิบายรูปภาพที่นี่


1

SmileBASIC ขนาด 96 ไบต์

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

อินพุต: 50,30,50:

ป้อนคำอธิบายรูปภาพที่นี่


1

Befunge-98, 113 bytes

&&: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

รหัสนี้อาศัยลายนิ้วมือFixed Point Maths (FIXP)สำหรับการคำนวณตรีโกณมิติและลายนิ้วมือTurtle Graphics (TURT)สำหรับการวาดเส้นทางของสไปโรกราฟ

เต่ากราฟิกใน Befunge จะคล้ายกันมากในการทำงานกราฟิกในการเขียนโปรแกรมภาษาโลโก้ คุณวาดด้วย 'เต่า' (ทำหน้าที่เป็นปากกาของคุณ) ซึ่งคุณคัดท้ายรอบพื้นผิวเอาท์พุท สิ่งนี้เกี่ยวข้องกับการปรับทิศทางเต่าไปในทิศทางที่เฉพาะเจาะจงแล้วสั่งให้มันเคลื่อนที่ไปข้างหน้าในระยะที่กำหนด

เพื่อที่จะทำงานกับระบบนี้ฉันจำเป็นต้องปรับสมการสปิรากราฟแบบดั้งเดิมให้เป็นสิ่งที่เป็นมิตรกับเต่ามากขึ้น ฉันไม่แน่ใจว่านี่เป็นวิธีที่ดีที่สุดหรือไม่

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)

โปรดทราบว่าการดำเนินการนี้จะดึงเส้นทางด้วยรูปแบบซิกแซก แต่คุณไม่สังเกตเห็นนอกเสียจากว่าคุณจะขยายภาพอย่างใกล้ชิด

นี่คือตัวอย่างการใช้พารามิเตอร์ R = 73, r = 51, d = 45

ป้อนคำอธิบายรูปภาพที่นี่

ฉันทดสอบโค้ดด้วยCCBIและcfungeซึ่งทั้งคู่สร้างผลลัพธ์ในรูปแบบของภาพ SVG เนื่องจากนี่เป็นรูปแบบเวกเตอร์ที่ปรับขนาดได้ภาพที่ได้จึงไม่ได้มีขนาดพิกเซลเช่นนี้ - เพียงปรับขนาดให้พอดีกับขนาดหน้าจอ (อย่างน้อยเมื่อดูในเบราว์เซอร์) ตัวอย่างข้างต้นคือการดักจับหน้าจอที่ถูกครอบตัดและปรับขนาดด้วยตนเอง

ในทางทฤษฎีแล้วรหัสนั้นสามารถทำงานกับRc / Funge ได้ด้วย แต่ในกรณีนี้คุณจะต้องใช้งานระบบที่มี XWindows เนื่องจากจะพยายามแสดงผลลัพธ์ในหน้าต่าง


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)]]);

สิ่งนี้เรียกว่าในเซสชันโต้ตอบผ่าน f(#,#,#)นี้เรียกว่าในเซสชั่นแบบโต้ตอบผ่านเป็นตัวอย่างพิจารณาf(3,2,1):

ป้อนคำอธิบายรูปภาพที่นี่


ในขณะที่ฉันชอบผลลัพธ์ที่ออกมาฉันไม่แน่ใจว่าจะทำตาม "จำนวนเต็มระหว่าง 1 ถึง 200" หรือ "กำหนดเป็นพิกเซล" ได้อย่างไร
Geobits

อินพุตอาจเป็นจำนวนเต็มหรือลอยตัว wxMaxima จะแปลงเป็นโฟลว์เพื่อทำงานของมันอย่างไรก็ตามฉันจะอัปเดตรูปภาพโดยใช้จำนวนเต็ม ฉันจะต้องคิดมากเกี่ยวกับอินพุตเป็นพิกเซลด้วย
Kyle Kanos

ใช่ฉันคิดว่ามันจะแปลงพวกเขาภายในและนั่นไม่ใช่ปัญหา ข้อ จำกัด จำนวนเต็มของอินพุตส่วนใหญ่คือการปิดลูปง่ายขึ้น (พวกเขาดูดีกว่า imo)
Geobits

0

แร็กเกต

#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)

เอาท์พุท:

ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.