Waktu Spirograph!

14

Spirograph adalah mainan yang menggambar hipotrokoid dan epitrokoid. Untuk tantangan ini, kami hanya akan fokus pada hypotrochoids.

Dari Wikipedia :

Hipotrokoid adalah roulette yang dilacak oleh titik yang melekat pada lingkaran jari-jari r yang berputar di dalam lingkaran tetap jari-jari R , di mana titik tersebut adalah jarak d dari pusat lingkaran dalam.

Persamaan parametrik untuk mereka dapat didefinisikan sebagai:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Di mana θ adalah sudut yang dibentuk oleh horizontal dan pusat lingkaran bergulir.


Tugas Anda adalah menulis program yang akan menggambar jalur yang dilacak oleh titik yang ditentukan di atas. Sebagai masukan, Anda akan diberikan R , r , dan d , semua bilangan bulat antara 1 dan 200 inklusif.

Anda dapat menerima input ini dari stdin, argumen, atau input pengguna, tetapi tidak dapat di-hardcode ke dalam program. Anda dapat menerimanya dalam bentuk apa pun yang paling nyaman bagi Anda; sebagai string, integer, dll.

Menganggap:

  • Unit input diberikan dalam piksel.
  • R > = r

Keluaran harus berupa representasi grafis dari hipotrokoid yang didefinisikan oleh input. ASCII- atau output berbasis teks lainnya tidak diizinkan. Gambar ini dapat disimpan ke file atau ditampilkan di layar. Sertakan tangkapan layar atau gambar output untuk input pilihan Anda.

Anda dapat memilih warna apa pun yang Anda suka untuk jalur / latar belakang, tunduk pada batasan kontras. Kedua warna harus memiliki komponen 'Nilai' HSV setidaknya setengah skala terpisah. Misalnya, jika Anda mengukur HSV dari [0...1], harus ada setidaknya 0.5perbedaan. Antara [0...255]harus ada 128perbedaan minimum .


Ini adalah kode golf, ukuran minimum kode sumber dalam byte yang menang.

Geobit
sumber
Bisakah kita berasumsi R > ratau R ≥ r? (Sama untuk rdan d.)
Martin Ender
10
Selamat telah memposting pertanyaan ke-2000! ;-)
Gagang pintu
@ m.buettner R>=r, tetapi dtidak dibatasi r, dan bisa di mana saja dalam kisaran 1-200.
Geobits
Resolusi apa yang sedang kita bicarakan?
Kyle Kanos
@KyleKanos Karena input dalam piksel dan masing-masing memiliki batas 200, seharusnya tidak boleh lebih besar dari 798x798, diberikan R=200, r=1, d=200. Anda dapat mengubah ukuran gambar ke input jika Anda mau, atau menyimpannya pada ukuran yang konstan, selama semuanya terlihat.
Geobits

Jawaban:

8

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

Output kode dan contoh yang tidak digabungkan: masukkan deskripsi gambar di sini

Jika saya dapat memasukkan sumbu dalam plot, saya dapat menyimpan 9 karakter lainnya.

Martin Ender
sumber
5

JavaScript (ECMAScript 6) - 312 314 Karakter

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

Contoh Output

r = 1, R = 200, d = 30

masukkan deskripsi gambar di sini

MT0
sumber
Saya suka, tapi entah bagaimana ikt rusak. Coba contoh di R.
edc65
Baris terakhir bisa untuk (; t <R * P; v.lineTo (X (), Y ())) t + = P / R
edc65
@ edc65 Itu tidak rusak itu hanya tidak melakukan iterasi yang cukup untuk melakukan rotasi penuh dalam contoh-contoh itu. Saya telah meningkatkan iterasi dari 9 * PI ke R * 2 * PI dan itu harus lebih baik (namun, saya telah meninggalkan kenaikan pada PI / 1000 karena jika tidak maka akan rusak karena nilai-nilai kecil R).
MT0
3

Python: 579

Ringkasan

Ini sama sekali tidak kompetitif mengingat jawaban Mathematica, tetapi saya memutuskan untuk tetap mempostingnya karena gambar-gambarnya cantik dan dapat menginspirasi seseorang atau berguna bagi seseorang. Karena jauh lebih besar, pada dasarnya saya membiarkannya tidak diserang. Program mengharapkan input baris perintah dari R, r, d.

Tangkapan layar

Berikut adalah dua contoh, satu untuk (5,3,5) dan satu untuk (10,1,7) contoh 5-3-5 contoh 10-1-7

Kode

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()
RT
sumber
2
Bisakah Anda menyesuaikan rasionya? Tampaknya gambar dikompresi secara vertikal.
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

core1024
sumber
2

Memproses, 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);
}

Input dimasukkan melalui konsol, satu nomor per baris.

Cuplikan layar untuk R = 65, r = 15, d = 24: masukkan deskripsi gambar di sini

segfaultd
sumber
2

GeoGebra, 87

Yaitu, jika Anda menganggap GeoGebra sebagai bahasa yang valid.

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

Menerima input dari bilah input GeoGebra, dalam format <variable>=<value>, misR=1000 .

Perhatikan bahwa Anda mungkin perlu mengubah ukuran zoom secara manual untuk melihat seluruh gambar.

tangkapan layar

(Masalah di bagian bawah jendela adalah bilah masukan yang saya bicarakan)

Cobalah online di sini .

pengguna12205
sumber
1
Saya kira ini memiliki batasan yang sama dengan pengiriman Kyle Kanos, bahwa Anda tidak dapat menentukan ukuran dalam piksel?
Martin Ender
@ m.buettner Ya Anda benar ... melewatkannya
user12205
2

HTML + Javascript 256 286 303

Edit Panggilan 1 yang dihapus untuk memindahkanTo, tetap berfungsi. Bisa menghemat lebih banyak pemotongan beginPath, tetapi hanya berfungsi pertama kali

Edit2 30 byte disimpan 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()">

Uji

Masukkan input ke dalam kotak teks (pisahkan koma) lalu tekan 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>

edc65
sumber
1
Tidak bisakah Anda menambahkan id ke kanvas dan menggunakan id itu secara global alih-alih harus menggunakan kueriSelektor!
Mama Fun Roll
@ ӍѲꝆΛҐӍΛПҒЦꝆ yeeeeees aku bisa. Itu adalah sesuatu yang tidak saya sadari pada Mei 2014
edc65
Wow itu jauh lebih banyak byte yang disimpan daripada yang saya pikir.
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')}

Namun, jika seseorang menginginkan angka 'bersih' (tanpa sumbu, tanpa label, dll), maka kodenya harus sedikit lebih panjang (88 karakter):

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

Salah satu contoh kode menggunakan versi f:

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

Beberapa contoh keluaran:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Feng
sumber
Ini tidak mengambil ukuran input dalam piksel, bukan? Contoh pertama harus hampir tiga kali lebih besar dari yang kedua.
Martin Ender
Kenapa semua ,??
plannapus
Koma digunakan untuk memisahkan argumen, banyak di antaranya NULL (tidak ada). Di sini pencocokan argumen posisi digunakan untuk mengurangi panjang kode. Ini tentu saja merupakan praktik pengkodean yang buruk. Cara yang disarankan adalah menggunakan daftar argumen bernama, seperti type = "l", xlabel = "", dll (dan singkirkan koma yang berlebihan!).
Feng
1

C # 813, adalah 999

Perlu beberapa pekerjaan untuk mengurangi jumlah byte. Saya berhasil menguranginya sedikit. Ia menerima tiga bilangan bulat yang dipisahkan ruang dari Konsol.

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

Sampel keluaran:

Spirograph

bacchusbeale
sumber
1

skrip shell + gnuplot (153)

Sebagian besar upaya adalah untuk menghapus sumbu dan tics, mengatur ukuran dan jangkauan, dan meningkatkan presisi. Untungnya, gnuplot alami untuk bermain golf, sehingga sebagian besar perintah dapat disingkat. Untuk menyimpan karakter, output harus diarahkan ke file gambar secara manual.

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

Memanggil skrip dengan spiro.sh 175 35 25>i.pngmemberi masukkan deskripsi gambar di sini

orion
sumber
1

R, 169 karakter

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

Bertakuk:

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

Contoh:

> f(65,15,24)

masukkan deskripsi gambar di sini

> f(120,20,40)

masukkan deskripsi gambar di sini

> f(175,35,25)

masukkan deskripsi gambar di sini

plannapus
sumber
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

Input: 50,30,50:

masukkan deskripsi gambar di sini

12Me21
sumber
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

Kode ini bergantung pada sidik jari Fixed Point Maths (FIXP) untuk beberapa perhitungan trigonometri, dan Turtle Graphics (TURT) sidik jari untuk menggambar jalur spirograph.

Grafik Turtle di Befunge sangat mirip dalam perilaku dengan grafis dalam bahasa pemrograman Logo . Anda menggambar dengan 'kura-kura' (berfungsi sebagai pena Anda), yang Anda arahkan di sekitar permukaan output. Ini berarti mengarahkan kura-kura ke arah tertentu, dan kemudian memerintahkannya untuk bergerak maju dengan jarak tertentu.

Untuk bekerja dengan sistem ini, saya perlu menyesuaikan persamaan spirograph asli menjadi sesuatu yang sedikit lebih ramah kura-kura. Saya tidak yakin apakah ini pendekatan terbaik, tetapi algoritme yang saya gunakan bekerja dengan cara seperti ini:

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)

Perhatikan bahwa ini sebenarnya menggambarkan jalur dengan semacam pola zig-zag, tetapi Anda tidak benar-benar memperhatikan kecuali Anda memperbesar dekat pada gambar.

Berikut ini contoh menggunakan parameter R = 73, r = 51, d = 45.

masukkan deskripsi gambar di sini

Saya telah menguji kodenya dengan CCBI dan cfunge , yang keduanya menghasilkan output dalam bentuk gambar SVG. Karena ini adalah format vektor yang dapat diskalakan, gambar yang dihasilkan tidak memiliki ukuran piksel - hanya skala yang sesuai dengan ukuran layar (setidaknya bila dilihat di browser). Contoh di atas adalah tangkapan layar yang telah dipangkas dan diskalakan secara manual.

Secara teori kode ini juga dapat bekerja pada Rc / Funge , tetapi dalam hal ini Anda harus menjalankan pada sistem dengan XWindows, karena itu akan mencoba untuk membuat output di jendela.

James Holderness
sumber
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)]]);

Ini disebut dalam sesi interaktif via f(#,#,#). Sebagai sampel, pertimbangkan f(3,2,1):

masukkan deskripsi gambar di sini

Kyle Kanos
sumber
Meskipun saya suka output cantik, saya tidak yakin bagaimana ini mengikuti "bilangan bulat antara 1 dan 200" atau "diberikan sebagai piksel".
Geobits
Input dapat berupa bilangan bulat atau mengapung, wxMaxima akan dikonversi menjadi float untuk melakukan tugasnya, saya akan memperbarui gambar menggunakan bilangan bulat. Saya juga harus memikirkan input sebagai piksel.
Kyle Kanos
Ya, saya pikir itu akan mengubah mereka secara internal, dan itu tidak masalah. Batasan integer pada input terutama untuk mendapatkan loop tertutup lebih mudah (mereka hanya terlihat lebih baik).
Geobits
0

Raket

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

Keluaran:

masukkan deskripsi gambar di sini

juga
sumber