Spirograph Time!

14

Un spirographe est un jouet qui dessine des hypotrochoïdes et des épitrochoïdes. Pour ce défi, nous allons nous concentrer uniquement sur les hypotrochoïdes.

De Wikipédia :

Un hypotrochoïde est une roulette tracée par un point attaché à un cercle de rayon r roulant autour de l'intérieur d'un cercle fixe de rayon R , où le point est à une distance d du centre du cercle intérieur.

Les équations paramétriques pour elles peuvent être définies comme:

entrez la description de l'image ici

entrez la description de l'image ici

θ est l'angle formé par l'horizontale et le centre du cercle de roulement.


Votre tâche consiste à écrire un programme qui dessinera le chemin tracé par le point défini ci-dessus. En entrée, vous recevrez R , r et d , tous les entiers compris entre 1 et 200 inclus.

Vous pouvez recevoir cette entrée depuis stdin, des arguments ou une entrée utilisateur, mais elle ne peut pas être codée en dur dans le programme. Vous pouvez l'accepter sous la forme qui vous convient le mieux; sous forme de chaînes, entiers, etc.

Présumer:

  • Les unités d'entrée sont données en pixels.
  • R > = r

La sortie doit être une représentation graphique de l'hypotrochoïde définie par l'entrée. Aucune sortie ASCII ou autre texte n'est autorisée. Cette image peut être enregistrée dans un fichier ou affichée à l'écran. Inclure une capture d'écran ou une image de la sortie pour une entrée de votre choix.

Vous pouvez choisir toutes les couleurs que vous souhaitez pour le chemin / arrière-plan, sous réserve d'une restriction de contraste. Les deux couleurs doivent avoir un composant HSV «Value» à au moins la moitié de l'échelle. Par exemple, si vous mesurez le HSV à partir de [0...1], il devrait y avoir au moins une 0.5différence. Entre [0...255]il devrait y avoir une 128différence minimale .


Il s'agit d'un code golf, la taille minimale du code source en octets gagne.

Géobits
la source
Pouvons-nous supposer R > rou R ≥ r? (Idem pour ret d.)
Martin Ender
10
Félicitations pour avoir posté la 2000e question! ;-)
Poignée de porte
@ m.buettner R>=r, mais dn'est pas limité à r, et peut être n'importe où dans la plage 1-200.
Geobits
De quel type de résolution parlons-nous?
Kyle Kanos
@KyleKanos Étant donné que l'entrée est en pixels et que chacun a un plafond de 200, elle ne devrait jamais être supérieure à 798x798, étant donné R=200, r=1, d=200. Vous pouvez redimensionner l'image à l'entrée si vous le souhaitez, ou la conserver à une taille constante, tant qu'elle est entièrement visible.
Geobits

Réponses:

8

Mathematica, 120 octets

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]

Code non généré et exemple de sortie: enter image description here

Si je peux inclure les axes dans l'intrigue, je peux enregistrer 9 autres caractères.

Martin Ender
la source
5

JavaScript (ECMAScript 6) - 312 314 caractères

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

Exemple de sortie

r = 1, R = 200, d = 30

enter image description here

MT0
la source
J'aime ça, mais ikt est cassé d'une façon ou d'une autre. Essayez les exemples dans R.
edc65
La dernière ligne pourrait être pour (; t <R * P; v.lineTo (X (), Y ())) t + = P / R
edc65
@ edc65 Il n'est pas cassé, il ne faisait tout simplement pas assez d'itérations pour effectuer une rotation complète dans ces exemples. J'ai augmenté les itérations de 9 * PI à R * 2 * PI et cela devrait être mieux (cependant, j'ai laissé l'incrément à PI / 1000 car sinon il casserait pour les petites valeurs de R).
MT0
3

Python: 579

Sommaire

Ce n'est pas du tout compétitif compte tenu de la réponse de Mathematica, mais j'ai quand même décidé de la poster car les photos sont jolies et cela peut inspirer quelqu'un ou être utile à quelqu'un. Parce qu'il est tellement plus grand, je l'ai laissé fondamentalement non golfé. Le programme attend une entrée de ligne de commande de R, r, d.

Capture d'écran

Voici deux exemples, un pour (5,3,5) et un pour (10,1,7) example 5-3-5 example 10-1-7

Code

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
la source
2
Pouvez-vous ajuster le ratio? Il semble que l'image soit compressée verticalement.
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
la source
2

Traitement, 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'entrée est entrée via la console, un numéro par ligne.

Capture d'écran pour R = 65, r = 15, d = 24: entrez la description de l'image ici

segfaultd
la source
2

GeoGebra, 87

Autrement dit, si vous considérez GeoGebra comme une langue valide.

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

Accepte les entrées de la barre de saisie GeoGebra, au format <variable>=<value>, par exemple R=1000.

Notez que vous devrez peut-être modifier manuellement la taille du zoom pour afficher l'image entière.

capture d'écran

(La chose en bas de la fenêtre est la barre d'entrée dont je parlais)

Essayez-le en ligne ici .

user12205
la source
1
Je suppose que cela a la même limitation que la soumission de Kyle Kanos, que vous ne pouvez pas spécifier la taille en pixels?
Martin Ender
@ m.buettner Oui, vous avez raison ... manqué ça
user12205
2

HTML + Javascript 256 286 303

Modifier le premier appel supprimé de moveTo, cela fonctionne quand même. Pourrait économiser plus de coupe beginPath, mais cela ne fonctionne que la première fois

Edit2 30 octets enregistrés 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()">

Tester

Mettez la saisie dans la zone de texte (séparée par des virgules) puis appuyez sur 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
la source
1
Ne pourriez-vous pas simplement ajouter un identifiant au canevas et l'utiliser globalement au lieu d'avoir à utiliser querySelector!
Mama Fun Roll
@ ӍѲꝆΛҐӍΛПҒЦꝆ yeeeeees je pourrais. C'est quelque chose que je n'étais pas au courant en mai 2014
edc65
Wow, c'était bien plus d'octets enregistrés que je ne le pensais.
Mama Fun Roll
2

R, 80 octets

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

Cependant, si l'on veut des chiffres «propres» (pas d'axes, pas d'étiquettes, etc.), alors le code devra être légèrement plus long (88 caractères):

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

Un exemple de code utilisant la version longue de f:

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

Quelques exemples de sorties:

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

Feng
la source
Cela ne prend pas les tailles d'entrée en pixels, n'est-ce pas? Le premier exemple devrait être presque trois fois plus grand que le second.
Martin Ender
Pourquoi tous les ,??
plannapus
Les virgules ont été utilisées pour séparer les arguments, dont beaucoup étaient NULL (rien). Ici, la correspondance d'arguments positionnels a été utilisée pour réduire la longueur du code. Bien sûr, c'est une mauvaise pratique de codage. La méthode recommandée serait d'utiliser une liste d'arguments nommés, tels que type = "l", xlabel = "", etc. (et de se débarrasser des virgules redondantes!).
Feng
1

C # 813, était 999

Nécessite un peu de travail pour réduire le nombre d'octets. J'ai réussi à le réduire un peu. Il accepte trois entiers séparés par des espaces de la 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])));
}
}

Échantillon de sortie:

Spirographe

bacchusbeale
la source
1

script shell + gnuplot (153)

La majeure partie de l'effort consiste à supprimer les axes et les tics, à définir la taille et la plage et à augmenter la précision. Heureusement, gnuplot est naturel pour le golf, donc la plupart des commandes peuvent être abrégées. Pour enregistrer des caractères, la sortie doit être redirigée manuellement vers un fichier image.

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

Appeler le script avec spiro.sh 175 35 25>i.pngdonne entrez la description de l'image ici

orion
la source
1

R, 169 caractères

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

Dentelé:

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

Exemples:

> f(65,15,24)

entrez la description de l'image ici

> f(120,20,40)

entrez la description de l'image ici

> f(175,35,25)

entrez la description de l'image ici

plannapus
la source
1

SmileBASIC, 96 octets

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

Entrée: 50,30,50:

entrez la description de l'image ici

12Me21
la source
1

Befunge-98, 113 octets

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

Ce code s'appuie sur l' empreinte digitale FIXP (Fixed Point Maths) pour certains calculs trigonométriques et sur Turtle Graphics (TURT) empreinte digitale pour tracer le chemin du spirographe.

Les graphiques Turtle dans Befunge sont très similaires dans leur comportement aux graphiques du langage de programmation Logo . Vous dessinez avec une «tortue» (servant de plume), que vous dirigez autour de la surface de sortie. Cela implique d'orienter la tortue dans une direction particulière, puis de lui demander d'avancer d'une certaine distance.

Afin de travailler avec ce système, j'avais besoin d'ajuster les équations du spirographe d'origine en quelque chose d'un peu plus convivial pour les tortues. Je ne sais pas si c'est la meilleure approche, mais l'algorithme que j'ai trouvé fonctionne quelque chose comme ceci:

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)

Notez que cela dessine en fait le chemin avec une sorte de motif en zig-zag, mais vous ne le remarquez vraiment que si vous zoomez de près sur l'image.

Voici un exemple utilisant les paramètres R = 73, r = 51, d = 45.

entrez la description de l'image ici

J'ai testé le code avec CCBI et cfunge , qui produisent tous deux une sortie sous la forme d'une image SVG. Comme il s'agit d'un format vectoriel évolutif, l'image résultante n'a pas de taille de pixel en tant que telle - elle est simplement mise à l'échelle pour s'adapter à la taille de l'écran (au moins lorsqu'elle est affichée dans un navigateur). L'exemple ci-dessus est une capture d'écran qui a été recadrée et mise à l'échelle manuellement.

En théorie, le code pourrait également fonctionner sur Rc / Funge , mais dans ce cas, vous devrez exécuter sur un système avec XWindows, car il essaiera de rendre la sortie dans une fenêtre.

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

Ceci est appelé dans la session interactive via f(#,#,#). À titre d'exemple, considérez f(3,2,1):

entrez la description de l'image ici

Kyle Kanos
la source
Bien que j'aime la jolie sortie, je ne sais pas comment cela suit "des entiers entre 1 et 200" ou "donnés en pixels".
Geobits
L'entrée peut être des entiers ou des flottants, wxMaxima se convertira en flottant pour faire son travail de toute façon, je mettrai à jour une image en utilisant des entiers. Je devrai penser davantage à l'entrée en tant que pixels.
Kyle Kanos
Ouais, je pensais que ça les convertirait en interne, et ce n'est pas un problème. La contrainte entière sur l'entrée était principalement de faciliter les boucles fermées (elles ont juste l'air mieux imo).
Geobits
0

Raquette

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

Production:

entrez la description de l'image ici

rnso
la source