スピログラフ時間!


14

スピログラフは、下垂体と外epi体を描くおもちゃです。この課題のために、私たちはただ単にトロポコイドに焦点を合わせます。

ウィキペディアから:

ヒポトロコイドは、半径Rの固定円の内側を転がる半径rの円に取り付けられた点によってトレースされるルーレットであり、その点は内部円の中心からの距離dです。

それらのパラメトリック方程式は次のように定義できます。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここで、θは水平とローリングサークルの中心によって形成される角度です。


あなたの仕事は、上記で定義されたポイントによってトレースされたパスを描くプログラムを書くことです。入力として、Rr、およびdが与えられます。これらはすべて1〜200の整数です。

この入力は、stdin、引数、またはユーザー入力から受け取ることができますが、プログラムにハードコーディングすることはできません。あなたにとって最も都合の良い形式でそれを受け入れることができます。文字列、整数などとして

仮定:

  • 入力単位はピクセルで指定されます。
  • R > = r

出力は、入力によって定義された次トロコイドのグラフィック表現である必要があります。ASCIIまたはその他のテキストベースの出力は許可されていません。この画像はファイルに保存するか、画面に表示できます。選択した入力の出力のスクリーンショットまたは画像を含めます。

コントラストの制限に従って、パス/背景に好きな色を選択できます。2つの色には、少なくともスケールの半分離れたHSV「値」コンポーネントが必要です。たとえば、からHSVを測定している場合、[0...1]少なくとも0.5違いがあるはずです。間[0...255]に最小の128差があるはずです。


これはコードゴルフで、ソースコードの最小サイズがバイト単位で勝ちます。


R > rまたは仮定することができますかR ≥ r?(同じもののためrd。)
マーティン・エンダー

10
2000番目の質問の投稿おめでとうございます!;-)
ドアノブ

@ m.buettner R>=r、ただしにd制限されていませんr範囲内であればどこでもかまい。
ジオビット

どのような解決策について話しているのですか?
カイルカノス

@KyleKanos入力はピクセル単位で、それぞれの上限は200であるため、が与えられた場合、798x798より大きくなることはありませんR=200, r=1, d=200。必要に応じて、入力に合わせて画像のサイズを変更したり、すべてが見える限り一定のサイズに維持したりできます。
ジオビット

回答:


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]

ゴルフされていないコードと出力例: ここに画像の説明を入力してください

軸をプロットに含めることができれば、さらに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の例を試してください。
edc6514年

最終行はfor(; t <R * P; v.lineTo(X()、Y()))t + = P / R
edc65

@ edc65これらの例では、完全なローテーションを行うのに十分な反復を行っていなかっただけで、壊れていません。反復回数を9 * PIからR * 2 * PIに増やしましたが、より良いはずです(ただし、Rの値が小さいと破損するため、増分をPI / 1000のままにしました)。
MT0

3

Python:579

概要

Mathematicaの答えを考えるとこれはまったく競争力がありませんが、写真はきれいで、誰かに刺激を与えたり、誰かに役立つかもしれないので、とにかく投稿することにしました。とても大きいので、基本的に手放しません。プログラムは、R、r、dのコマンドライン入力を想定しています。

スクリーンショット

次に、2つの例を示します。1つは(5,3,5)に、もう1つは(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
比率を調整できますか?画像は縦に圧縮されているようです。
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

処理中、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);
}

入力はコンソールから入力され、1行に1つの数字が入ります。

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の提出と同じ制限があり、ピクセル単位でサイズを指定できないと思いますか?
マーティンエンダー

@ m.buettnerはい、あなたは右...逃していること
user12205

2

HTML + Javascript 256 286 303

編集 MoveToの最初の呼び出しを削除しましたが、とにかく動作します。カットするbeginPathをさらに節約できますが、最初にしか機能しません

Edit2 30バイトが保存されました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()">

テスト

入力をテキストボックスに入力し(カンマ区切り)、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
キャンバスにIDを追加し、querySelectorを使用する代わりにそのIDをグローバルに使用することはできませんでした!
ママファンロール

@ӍѲꝆΛҐӍΛПҒЦꝆそうだね。2014
5

うわー、思ったよりもずっと多くのバイトが節約された。
ママファンロール

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の長いバージョンを使用した1つのコード例:

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

いくつかの出力例:

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください


これはピクセル単位の入力サイズを取りませんか?最初の例は、2番目の例のほぼ3倍の大きさでなければなりません。
マーティンエンダー

なぜすべて,
プランナパス14年

コンマは引数の分離に使用され、その多くはNULL(なし)でした。ここでは、コードの長さを減らすために位置引数のマッチングが使用されました。もちろんこれは悪いコーディングの習慣です。推奨される方法は、type = "l"、xlabel = ""などの名前付き引数リストを使用することです(そして、余分なコンマを取り除きます!)。
風水14年

1

C#813、999でした

バイト数を減らすには、いくらかの作業が必要です。私はそれを少し減らすことができました。コンソールから3つのスペースで区切られた整数を受け入れます。

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

出力サンプル:

スパイログラフ


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.pnggivesを使用し てスクリプトを呼び出すここに画像の説明を入力してください


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バイト

&&: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のTurtle Graphicsは、Logoプログラミング言語のグラフィックと動作が非常に似ています。あなたは「亀」(ペンの役目)を使って描き、それを出力面の周りで操縦します。これには、カメを特定の方向に向けてから、一定の距離だけ前進するように指示する必要があります。

このシステムを使用するには、元の呼吸運動記録方程式をもう少しカメに優しいものに調整する必要がありました。これが最善のアプローチであるかどうかはわかりませんが、私が思いついたアルゴリズムは次のように動作します:

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を使用した例です。

ここに画像の説明を入力してください

CCBIcfungeでコードをテストしました。どちらも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の間の整数」または「ピクセルとして与えられる」にどのように従うのかわかりません。
ジオビット

入力は整数でもフロートでもかまいませんが、wxMaximaはフロートに変換して作業を実行します。整数を使用して画像を更新します。入力についてもピクセルとして考える必要があります。
カイルカノス

ええ、私はそれを内部的に変換するだろうと考えました、それは問題ではありません。入力に対する整数の制約は、主に閉じたループを簡単にすることでした(それらは見た目が良くなります)。
ジオビット

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.