Spirograph Time!


14

Uno spirografo è un giocattolo che disegna ipotrochoidi ed epitrochoidi. Per questa sfida, ci concentreremo solo sugli ipotrochoidi.

Da Wikipedia :

Un ipotrochoid è una roulette tracciata da un punto attaccato a un cerchio di raggio r che rotola all'interno di un cerchio fisso di raggio R , dove il punto è una distanza d dal centro del cerchio interno.

Le equazioni parametriche per esse possono essere definite come:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Dove θ è l'angolo formato dall'orizzontale e dal centro del cerchio di rotolamento.


Il tuo compito è scrivere un programma che disegnerà il percorso tracciato dal punto sopra definito. Come input, ti verranno dati R , r e d , tutti i numeri interi compresi tra 1 e 200 inclusi.

È possibile ricevere questo input da stdin, argomenti o input dell'utente, ma non può essere codificato nel programma. Puoi accettarlo in qualunque forma sia più conveniente per te; come stringhe, numeri interi, ecc.

Assumere:

  • Le unità di input sono indicate in pixel.
  • R > = r

L'output dovrebbe essere una rappresentazione grafica dell'ipotrochoid definito dall'input. Non è consentito alcun output basato su testo ASCII o altro. Questa immagine può essere salvata in un file o visualizzata sullo schermo. Includi uno screenshot o un'immagine dell'output per un input di tua scelta.

Puoi scegliere tutti i colori che ti piacciono per il percorso / sfondo, soggetto a una limitazione del contrasto. I due colori devono avere il componente "Valore" di HSV almeno a metà della scala. Ad esempio, se stai misurando HSV da [0...1], ci dovrebbe essere almeno una 0.5differenza. Tra [0...255]ci dovrebbe essere una 128differenza minima .


Questo è un codice golf, vince la dimensione minima del codice sorgente in byte.


Possiamo assumere R > ro R ≥ r? (Lo stesso per re d.)
Martin Ender,

10
Congratulazioni per aver pubblicato la 2000esima domanda! ;-)
Maniglia della porta

@ m.buettner R>=r, ma dnon è vincolato a r, e può trovarsi ovunque nell'intervallo 1-200.
Geobits

Di che tipo di risoluzione stiamo parlando?
Kyle Kanos,

@KyleKanos Dato che l'input è in pixel e ognuno ha un limite di 200, non dovrebbe mai essere più grande di 798x798, dato R=200, r=1, d=200. Se lo desideri, puoi ridimensionare l'immagine sull'input o mantenerla a dimensioni costanti, purché sia ​​tutta visibile.
Geobits

Risposte:


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]

Codice non golfato e output di esempio: inserisci qui la descrizione dell'immagine

Se posso includere gli assi nella trama, posso salvare altri 9 caratteri.


5

JavaScript (ECMAScript 6) - 312 314 caratteri

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

Esempio di output

r = 1, R = 200, D = 30

inserisci qui la descrizione dell'immagine


Mi piace, ma ikt è rotto in qualche modo. Prova gli esempi in R.
edc65

L'ultima riga potrebbe essere per (; t <R * P; v.lineTo (X (), Y ())) t + = P / R
edc65,

@ edc65 Non è rotto, ma non stava facendo abbastanza iterazioni per fare una rotazione completa in quegli esempi. Ho aumentato le iterazioni da 9 * PI a R * 2 * PI e dovrebbe essere migliore (tuttavia, ho lasciato l'incremento su PI / 1000 poiché altrimenti si spezzerebbe per piccoli valori di R).
MT0,

3

Python: 579

Sommario

Questo non è affatto competitivo data la risposta di Mathematica, ma ho deciso di pubblicarlo comunque perché le immagini sono carine e può ispirare qualcuno o essere utile a qualcuno. Perché è molto più grande, l'ho lasciato praticamente non golfato. Il programma prevede un input da riga di comando di R, r, d.

Immagine dello schermo

Ecco due esempi, uno per (5,3,5) e uno per (10,1,7) esempio 5-3-5 esempio 10-1-7

Codice

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
Puoi regolare il rapporto? Sembra che l'immagine sia compressa verticalmente.
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

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

L'ingresso è inserito tramite console, un numero per riga.

Schermata per R = 65, r = 15, d = 24: inserisci qui la descrizione dell'immagine


2

GeoGebra, 87

Cioè, se consideri GeoGebra una lingua valida.

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

Accetta input dalla barra di input di GeoGebra, nel formato <variable>=<value>, ad es R=1000.

Si noti che potrebbe essere necessario modificare manualmente le dimensioni dello zoom per visualizzare l'intera immagine.

immagine dello schermo

(La cosa nella parte inferiore della finestra è la barra di input di cui stavo parlando)

Provalo online qui .


1
Suppongo che questo abbia lo stesso limite dell'invio di Kyle Kanos, che non puoi specificare la dimensione in pixel?
Martin Ender,

@ m.buettner Sì, hai ragione ... perso quello
user12205

2

HTML + Javascript 256286 303

Modifica Rimossa la 1a chiamata per spostarsi, funziona comunque. Potrebbe risparmiare più il taglio di beginPath, ma poi funziona solo la prima volta

Modifica2 30 byte salvati grazie a @ ӍѲꝆΛҐӍΛПҒЦꝆ

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

Test

Inserisci input nella casella di testo (virgola separata) quindi premi 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
Non potresti semplicemente aggiungere un ID all'area di disegno e utilizzarlo a livello globale invece di dover utilizzare querySelector!
Mama Fun Roll

@ ӍѲꝆΛҐӍΛПҒЦꝆ yeeeeees I could. È qualcosa di cui non ero a conoscenza nel maggio 2014
edc65,

Wow, questo è stato un modo in cui sono stati salvati molti più byte di quanto pensassi.
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')}

Tuttavia, se si vogliono figure "pulite" (senza assi, senza etichette, ecc.), Il codice dovrà essere leggermente più lungo (88 caratteri):

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

Un esempio di codice che utilizza la versione più lunga di f:

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

Alcuni esempi di output:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


Questo non accetta le dimensioni di input in pixel, vero? Il primo esempio dovrebbe essere quasi tre volte più grande del secondo.
Martin Ender,

Perché tutti ,??
plannapus,

Le virgole sono state utilizzate per separare gli argomenti, molti dei quali erano NULL (niente). Qui la corrispondenza dell'argomento posizionale è stata usata per ridurre la lunghezza del codice. Questa ovviamente è una cattiva pratica di programmazione. Il modo consigliato sarebbe quello di usare un elenco di argomenti con nome, come type = "l", xlabel = "", ecc (e sbarazzarsi delle virgole ridondanti!).
Feng,

1

C # 813, era 999

Ha bisogno di un po 'di lavoro per ridurre il conteggio dei byte. Sono riuscito a ridurlo un po '. Accetta tre numeri interi separati da spazio dalla Console.

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

Campione di uscita:

Spirograph


1

shell script + gnuplot (153)

La maggior parte dello sforzo consiste nel rimuovere gli assi e i tic, impostare le dimensioni e l'intervallo e aumentare la precisione. Per fortuna, gnuplot è naturale per il golf, quindi la maggior parte dei comandi può essere abbreviata. Per salvare i caratteri, l'output deve essere reindirizzato manualmente a un file di immagine.

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

Chiamare lo script con spiro.sh 175 35 25>i.pnginserisci qui la descrizione dell'immagine


1

R, 169 caratteri

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

rientrato:

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

Esempi:

> f(65,15,24)

inserisci qui la descrizione dell'immagine

> f(120,20,40)

inserisci qui la descrizione dell'immagine

> f(175,35,25)

inserisci qui la descrizione dell'immagine


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

Ingresso: 50,30,50:

inserisci qui la descrizione dell'immagine


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

Questo codice si basa sull'impronta digitale Fixed Point Maths (FIXP) per alcuni calcoli trigonometrici e sull'impronta digitale Turtle Graphics (TURT) per tracciare il percorso dello spirografo.

La grafica Turtle in Befunge ha un comportamento molto simile alla grafica nel linguaggio di programmazione Logo . Disegni con una "tartaruga" (che funge da penna), che gira intorno alla superficie di uscita. Ciò comporta l'orientamento della tartaruga in una direzione particolare, e quindi l'incarico di avanzare di una certa distanza.

Per lavorare con questo sistema, avevo bisogno di regolare le equazioni spirografiche originali in qualcosa di un po 'più adatto alle tartarughe. Non sono sicuro che questo sia l'approccio migliore, ma l'algoritmo che ho ideato funziona in questo modo:

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)

Nota che questo in realtà disegna il percorso con una specie di motivo a zig-zag, ma non ti accorgi davvero a meno che non ingrandisci da vicino l'immagine.

Ecco un esempio usando i parametri R = 73, r = 51, d = 45.

inserisci qui la descrizione dell'immagine

Ho testato il codice con CCBI e cfunge , entrambi i quali producono output sotto forma di un'immagine SVG. Poiché si tratta di un formato vettoriale scalabile, l'immagine risultante non ha una dimensione in pixel in quanto tale, ma si adatta alle dimensioni dello schermo (almeno quando viene visualizzata in un browser). L'esempio sopra è una schermata che è stata ritagliata e ridimensionata manualmente.

In teoria il codice potrebbe funzionare anche su Rc / Funge , ma in quel caso avresti bisogno di essere in esecuzione su un sistema con XWindows, dal momento che proverà a rendere l'output in una finestra.


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

Questo viene chiamato nella sessione interattiva tramite f(#,#,#). Come esempio, considera f(3,2,1):

inserisci qui la descrizione dell'immagine


Mentre mi piace l'output piuttosto, non sono sicuro di come segue "numeri interi compresi tra 1 e 200" o "dato come pixel".
Geobits

L'input può essere numeri interi o float, wxMaxima si convertirà in float per fare comunque il suo lavoro, aggiornerò un'immagine usando numeri interi. Dovrò pensare di più anche all'input come pixel.
Kyle Kanos,

Sì, ho pensato che li avrebbe convertiti internamente, e questo non è un problema. Il vincolo intero sull'input era principalmente quello di rendere più semplici i loop chiusi (hanno solo un aspetto migliore).
Geobits

0

Racchetta

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

Produzione:

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.