AtCoder Grand Contest 046:A - Takahashikun, The Striderのアニメーション描画


でてないんですが,AGC046のA問題のグラフ描画をしてみました.
ちなみに私のレーティングは今現在624です,,,センスないけど楽しいからゆっくり一歩一歩進めてますmypage

問題はここからどうぞ!
以下のようなコードでシミュレーションできるかなあと思ってます,

import math
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

def simulate(X):
    #高橋くんが到達していく点集合を格納するリスト
    x=[]
    y=[] 
    #スタートポジション
    x.append(0)
    y.append(0)
    #何回でスタートに戻るかはこの式から求められる,問題AはこれでAC取れる
    K = 360 / math.gcd(X,360) 
    #開始時の真北を0度の軸とする
    deg = 0 

    for i in range(int(K)): #K点求める
        next_x = x[-1] - np.sin(deg*(np.pi/180)) #前の点と,今現在の角度から次点のx座標を計算
        next_y = y[-1] + np.cos(deg*(np.pi/180)) #前の点と,今現在の角度から次点のy座標を計算
        x.append(next_x) #x点を保存
        y.append(next_y) #y点を保存
        deg+=X #向きをX度変える
    return x,y

#90度変える場合
X=90
x,y = simulate(X)

plt.plot(x, y,'b-o')
#以下,個人的に今回のプロットで見えやすいと思う体裁にするための設定
plt.axes().set_aspect('equal','datalim')
ax = plt.gca()  
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

上のコードの実行結果は以下のような感じになります.

引数を90から136に変えると,結構綺麗な感じになります.

また,アニメーションを以下のようなコードで生成すると,

fig = plt.figure()
imgs = []
plt.axes().set_aspect('equal','datalim')
ax = plt.gca()  
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

for i in range(len(x)):
    img = plt.plot(x[:i+1], y[:i+1], 'b-o')
    imgs.append(img)

ani = animation.ArtistAnimation(fig, imgs, interval=1000)
ani.save('../qiita.gif', writer='pillow') 
plt.show()

以下のような感じになります(X=136の場合).

こういう綺麗な図形なんていうんでしたっけ??

短いちょっとした記事ですが,読んでくれてありがとうございます

*追記
高橋くんの到着点はある円に乗るので,円も描きました.以下のようなコードです.

import matplotlib.patches as patches
center_x = (min(x)+max(x))/2
center_y = 0.5
radius = np.sqrt(1/(2*(1-np.cos(X*(np.pi/180)))))
circle = patches.Circle(xy=(center_x, center_y), radius=radius, fc='w', ec='r')
center = patches.Circle(xy=(center_x, center_y), radius=0.01, fc='r', ec='r')
ax.add_patch(circle)
ax.add_patch(center)

中心のx座標の求め方が厳密ではない気もしますが,,,,
以下が実行例です(X=260の時)

参考

matplotlibでimagemagickを使わずにアニメGIFを保存する
matplotlib で線分をアニメーションさせる
Matplotlibで円や長方形などの図形を描画