0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

基礎プロI 100本ノック グラフィックス編

Last updated at Posted at 2023-08-27

以下の C による初歩の C プログラミング 100 本ノックを Julia で解いてみました。

基礎プロI 100本ノック グラフィックス編
http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksGraphics.html

各プログラムにおいて、特に指定が無い限りは入力値が指定された形式であるかどうかをチェックする必要はない(例えば整数型の値を入力させるところでアルファベットを入力された場合など)。

グラフィックシステムは Julia の Plots を使用する。

基本的な描画関数として,以下を事前に定義しておく。

以下のような手順で使用する。

  1. start() で ウィンドウの大きさを指定して,描画を開始する。
  2. 描画関数で描画する。
  3. stop() で終了する。必要でない場合もあるが,描画されないときは stop() を書く。
using Plots

function start(w=600, h=400)
    pyplot(size=(w, h), grid=false, aspectratio=1, label="", xlims=(0, w), ylims=(0, h), showaxis=false)
    delta = 1
    plot([delta, w-delta, w-delta, delta, delta], [delta, delta, h-delta, h-delta, delta], color=:black, lw=0.1)
end

stop() = plot!();

function circle(ox, oy, r, color=:black; lw=0.5, fill=false)
    # 中心座標 ox, oy,半径 r, 描画色,塗りつぶしするかどうか
    θ = 0:5:360
    x = r.*cosd.(θ)
    y = r.*sind.(θ)
    if fill
        plot!(ox .+ x, oy .+ y, linecolor=color, lw=lw, seriestype=:shape, fillcolor=color)
    end
    plot!(ox .+ x, oy .+ y, color=:black, lw=lw)
end;

function rect(x1, y1, x2, y2, color=:black; lw=0.5, fill=false)
    # 長方形の左下の座標 x1, y1,右上の座標 x2, y2,描画色
    if fill
        plot!([x1, x2, x2, x1, x1], [y1, y1, y2,  y2, y1], color=color, lw=lw, seriestype=:shape, fillcolor=color)
    end
    plot!([x1, x2, x2, x1, x1], [y1, y1, y2,  y2, y1], color=:black, lw=lw)
end;

No. 60 円

中心座標を入力させ、横600縦400のウィンドウを開き、入力した座標に半径50の円を描くプログラムを作成せよ。

print("円の中心座標を入力:")
(x, y) = parse.(Int, split(readline()))

start(600, 400)
circle(x, y, 50)
stop()
円の中心座標を入力:
stdin>  200 150

output_4_2.png

No. 61 正方形と内接円

横600縦400のウィンドウを開き、左下の座標が(200, 100)で大きさが200の正方形と、それに内接する円を描くプログラムを作成せよ。必要な座標はプログラム中でコンピュータに計算させること。

start(600, 400)
rect(200, 100, 200 + 200, 100 + 200)
circle(300, 200, 100)
stop()

output_6_0.png

No. 62 円と外接正方形

円の中心座標を入力させ、横600縦400のウィンドウを開き、入力した中心座標に半径80の円と、それに外接する正方形を描くプログラムを作成せよ。

print("中心座標を入力:")
(x, y) = parse.(Int, split(readline()))

start(600, 400)
circle(x, y, 80)
rect(x - 80, y - 80, x + 80, y + 80)
stop()
中心座標を入力:
stdin>  240 180

output_8_2.png

No. 63 象限

中心座標を入力させ、横600縦400のウィンドウを開き、入力した中心座標がウィンドウの左下なら赤、左上なら緑、右下なら青、右上なら黄の塗りつぶし色で、入力した座標に半径50の円を描くプログラムを作成せよ。境界上の場合はどちらの色でも構わない。

print("中心座標を入力:")
(x, y) = parse.(Int, split(readline()))

start(600, 400)
(ox, oy) = (300, 200)
if x < ox && y < oy
    color = :red
elseif x < ox && y > oy
    color = :green
elseif x >= ox && y < oy
    color = :blue
else
    color = :yellow
end
circle(x, y, 50, color, fill=true)
hline!([oy], color=:black)
vline!([ox], color=:black)
stop()
中心座標を入力:
stdin>  430 270

output_10_2.png

No. 64 象限+中央

中心座標を入力させ、横600縦400のウィンドウを開き、入力した中心座標がウィンドウの中心から左右上下に100以内ならオレンジ、それ以外で、左下なら赤、左上なら緑、右下なら青、右上なら黄の塗りつぶし色で、入力した座標に半径50の円を描くプログラムを作成せよ。境界上の場合はどちらの色でも構わない。

print("円の中心座標を入力:")
(x, y) = parse.(Int, split(readline()))

start(600, 400)
(ox, oy) = (300, 200)
hline!([oy], color=:black)
vline!([ox], color=:black)
rect(ox - 100, oy - 100, ox + 100, oy + 100, :white, fill=true)
if ox - 100 < x < ox + 100 && oy - 100 < y < oy + 100
    color = :orange
elseif x < ox && y < oy
    color = :red
elseif x < ox && y >= ox
    color = :green
elseif x >= ox && y < ox
    color = :blue
else
    color = :yellow
end
circle(x, y, 50, color, fill=true)
stop()
円の中心座標を入力:
stdin>  480 80

output_12_2.png

No. 65 十字型

中心座標を入力させ、横600縦400のウィンドウを開き、半径10の円を中心座標とその上下左右に5つずつ、中心の間隔を30として描くプログラムを繰り返しを使って作成せよ(具体的な位置関係は下の実行結果例を見よ)。

print("円の中心座標を入力:")
(x, y) = parse.(Int, split(readline()))

start(600, 400)
for i in -2:2, j in -2:2
    (i == 0 || j == 0) && circle(x + 30i, y + 30j, 10)
end
stop()
円の中心座標を入力:
stdin>  340 180

output_14_2.png

No. 66 ×型

中心座標を入力させ、横600縦400のウィンドウを開き、半径10の円を中心座標とその斜め方向に5つずつ、中心の間隔を縦方向および横方向それぞれ30(中心の距離が30ではない)として描くプログラムを繰り返しを使って作成せよ(具体的な位置関係は下の実行結果例を見よ)。

print("円の中心座標を入力:")
(x, y) = parse.(Int, split(readline()))

start(600, 400)
for i in -2:2, j in -2:2
    (i == j || i == -j) && circle(x + 30i, y + 30j, 10)
end
stop()
円の中心座標を入力:
stdin>  340 180

output_16_2.png

No. 67 5×5

中心座標を入力させ、横600縦400のウィンドウを開き、半径10の円を中心座標とその上下左右に5行五列の25個、中心の間隔を縦方向および横方向それぞれ30として描くプログラムを繰り返しを使って作成せよ(具体的な位置関係は下の実行結果例を見よ)。

print("円の中心座標を入力:")
(x, y) = parse.(Int, split(readline()))

start(600, 400)
for i in -2:2, j in -2:2
    circle(x + 30i, y + 30j, 10)
end
stop()
円の中心座標を入力:
stdin>  340 180

output_18_2.png

No. 68 マス目

マス目の数(1以上の整数値)を入力させ、横600縦600のウィンドウを開き、ウィンドウの縦横がマス目の数に区切られるよう等間隔に線を描くプログラムを作成せよ。整数値の計算の場合、入力値によっては多少の誤差が生じるが、できるだけ誤差が小さくなるよう工夫せよ。

print("マス目の数:")
n = parse(Int, readline())

start(600, 600)
x = collect(1:n-1) .* (600/n)
hline!(x, color=:black)
vline!(x, color=:black)
hline!([0], color=:red)
マス目の数:
stdin>  9

output_20_2.png

No. 69 市松模様

マス目の数(1以上の整数値)を入力させ、横600縦600のウィンドウを開き、ウィンドウの縦横がマス目の数に区切られ、マス目を白と黒で交互に塗りつぶして描くプログラムを作成せよ(白と黒が交互になっていればよい)。整数値の計算の場合、入力値によっては多少の誤差が生じるが、できるだけ誤差が小さくなるよう工夫せよ。

print("マス目の数:")
n = parse(Int, readline())

start(600, 600)
w = 600/n
for i in 0:n-1, j in 0:n-1
    isodd(i + j) && rect(i*w, j*w,(i + 1)w, (j + 1)w, :black, fill=true)
end
stop()
マス目の数:
stdin>  9

output_22_2.png

No. 70 bound

横600縦400のウィンドウ内を、半径30の円が、中心の初期位置(0,0)、初速(5,3)で移動し、ウィンドウの端に円の中心が達したら反対方向に跳ね返る動きをするプログラムを作成せよ。1画面ごとの休止時間は0.05秒でよい。

start(600, 400)
(r, x, y) = (30, 0, 0)
(speedx, speedy) = (5, 3)
anim = Animation()
for i = 1:2000
    plt = plot()
    plt = rect(1, 1, 599, 399)
    plt = circle(x, y, r, fill=true)
    x += speedx
    if x > 600 || x < 0
        speedx = -speedx
    end
    y += speedy
    if y > 400 || y < 0
        speedy = -speedy
    end
    frame(anim, plt)
end
gif(anim, "gif70.gif")

gif70.gif

No. 71 bound

横600縦400のウィンドウ内を、半径30の円が、中心の初期位置(30,30)、初速(5,3)で移動し、ウィンドウの端に円の端が接したら反対方向に跳ね返る動きをするプログラムを作成せよ。1画面ごとの休止時間は0.05秒でよい。

start(600, 400)
(r, x, y) = (30, 30, 30)
(speedx, speedy) = (5, 3)
anim = Animation()
for i = 1:2000
    plt = plot()
    plt = rect(1, 1, 599, 399)
    plt = circle(x, y, r, fill=true)
    x += speedx
    if x > 600 - r || x < r
        speedx = -speedx
    end
    y += speedy
    if y > 400 - r || y < r
        speedy = -speedy
    end
    frame(anim, plt)
end
gif(anim, "gif71.gif")

gif71.gif

No. 72 ワープ

横600縦400のウィンドウ内を、半径30の円が、中心の初期位置(30,30)、初速(5,3)で移動し、ウィンドウの端に円の中心が接したら反対側の端から出現する(左右、上下の端が繋がっているようになっている)プログラムを作成せよ。1画面ごとの休止時間は0.05秒でよい。

start(600, 400)
(r, x, y) = (30, 30, 30)
(speedx, speedy) = (5, 3)
anim = Animation()
for i = 1:2000
    plt = plot()
    plt = rect(1, 1, 599, 399)
    plt = circle(x, y, r, fill=true)
    x += speedx
    if x > 600
        x = 0
    end
    y += speedy
    if y > 400
        y = 0
    end
    frame(anim, plt)
end
gif(anim, "gif72.gif")

gif72.gif

No. 73 bound×2

横600縦400のウィンドウ内を、半径30の円が2つ、中心の初期位置(30,30)、それぞれの初速が(5,3)と(3,5)で移動し、ウィンドウの端に円の端が接したら反対方向に跳ね返る動きをするプログラムを作成せよ。1画面ごとの休止時間は0.05秒でよい。

start(600, 400)
(r, x, y) = (30, 30, 30)
(r2, x2, y2) = (30, 30, 30)
(speedx, speedy) = (5, 3)
(speedx2, speedy2) = (3, 5)
anim = Animation()
for i = 1:2000
    plt = plot()
    plt = rect(1, 1, 599, 399)
    plt = circle(x, y, r, fill=true)
    plt = circle(x2, y2, r2, fill=true)
    # ball1
    x += speedx
    if x > 600 - r || x < r
        speedx = -speedx
    end
    y += speedy
    if y > 400 - r || y < r
        speedy = -speedy
    end
    # ball2
    x2 += speedx2
    if x2 > 600 - r2 || x2 < r2
        speedx2 = -speedx2
    end
    y2 += speedy2
    if y2 > 400 - r2|| y2 < r
        speedy2 = -speedy2
    end
    frame(anim, plt)
end
gif(anim, "gif73.gif")

gif73.gif

No. 74 衝突判定

横600縦400のウィンドウ内を、半径30の円が2つ、そらぞれの中心の初期位置(30,30)と(570,370)、それぞれの初速が(5,3)と(-3,-5)で移動し、ウィンドウの端に円の端が接したら反対方向に跳ね返る動きをし、円が接するか重なる場合は赤、そうでない場合は青で塗りつぶして表示するプログラムを作成せよ。1画面ごとの休止時間は0.05秒でよい。

start(600, 400)
(r, x, y) = (30, 30, 30)
(r2, x2, y2) = (30, 30, 30)
(speedx, speedy) = (5, 3)
(speedx2, speedy2) = (3, 5)
anim = Animation()
for i = 1:2000
    plt = plot()
    plt = rect(1, 1, 599, 399)
    color = (x - x2)^2 + (y - y2)^2 < (r + r2)^2 ? :red : :blue
    plt = circle(x, y, r, color, fill=true)
    plt = circle(x2, y2, r2, color, fill=true)
    # ball1
    x += speedx
    if x > 600 - r || x < r
        speedx = -speedx
    end
    y += speedy
    if y > 400 - r || y < r
        speedy = -speedy
    end
    # ball2
    x2 += speedx2
    if x2 > 600 - r2 || x2 < r2
        speedx2 = -speedx2
    end
    y2 += speedy2
    if y2 > 400 - r2|| y2 < r
        speedy2 = -speedy2
    end
    frame(anim, plt)
end
gif(anim, "gif74.gif")

gif74.gif

75. bound×5

横600縦400のウィンドウ内を、半径30の円が5つ、中心の初期位置(30,30)、それぞれの初速が(1,5)、(2,4)、(3,3)、(4,2)、(5,1)で移動し、ウィンドウの端に円の端が接したら反対方向に跳ね返る動きをするプログラムを作成せよ。1画面ごとの休止時間は0.05秒でよい。

function ball(x, y, speedx, speedy)
    plt = circle(x, y, r, fill=true)
    x += speedx
    if x > 600 - r || x < r
        speedx = -speedx
    end
    y += speedy
    if y > 400 - r || y < r
        speedy = -speedy
    end
    return (x, y, speedx, speedy)
end

start(600, 400)
(r1, x1, y1) = (30, 30, 30)
(r2, x2, y2) = (30, 30, 30)
(r3, x3, y3) = (30, 30, 30)
(r4, x4, y4) = (30, 30, 30)
(r5, x5, y5) = (30, 30, 30)
(speedx1, speedy1) = (1, 5)
(speedx2, speedy2) = (2, 4)
(speedx3, speedy3) = (3, 3)
(speedx4, speedy4) = (4, 2)
(speedx5, speedy5) = (5, 1)
anim = Animation()
for i = 1:2000
    plt = plot()
    plt = rect(1, 1, 599, 399)
    (x1, y1, speedx1, speedy1) = ball(x1, y1, speedx1, speedy1)
    (x2, y2, speedx2, speedy2) = ball(x2, y2, speedx2, speedy2)
    (x3, y3, speedx3, speedy3) = ball(x3, y3, speedx3, speedy3)
    (x4, y4, speedx4, speedy4) = ball(x4, y4, speedx4, speedy4)
    (x5, y5, speedx5, speedy5) = ball(x5, y5, speedx5, speedy5)
    frame(anim, plt)
end
gif(anim, "gif75.gif")

gif75.gif

No. 76 色が変わるbound×5

横600縦400のウィンドウ内を、半径30の円が5つ、中心の初期位置(30,30)、それぞれの初速が(1,5)、(2,4)、(3,3)、(4,2)、(5,1)で移動し、ウィンドウの端に円の端が接したら反対方向に跳ね返る動きをするプログラムを作成せよ。ただし、それぞれの円の色は、壁に当たるごとに赤→青→緑→黄と変化し、黄の次は赤に戻る。1画面ごとの休止時間は0.05秒でよい。

function ball(x, y, speedx, speedy, color)
    colors = [:red, :blue, :green, :yellow]
    plt = circle(x, y, r, colors[color], fill=true)
    x += speedx
    if x > 600 - r || x < r
        speedx = -speedx
        color += 1
        color > 4 && (color = 1)
    end
    y += speedy
    if y > 400 - r || y < r
        speedy = -speedy
        color += 1
        color > 4 && (color = 1)
    end
    return (x, y, speedx, speedy, color)
end

start(600, 400)
(r1, x1, y1, color1) = (30, 30, 30, 1)
(r2, x2, y2, color2) = (30, 30, 30, 1)
(r3, x3, y3, color3) = (30, 30, 30, 1)
(r4, x4, y4, color4) = (30, 30, 30, 1)
(r5, x5, y5, color5) = (30, 30, 30, 1)
(speedx1, speedy1) = (1, 5)
(speedx2, speedy2) = (2, 4)
(speedx3, speedy3) = (3, 3)
(speedx4, speedy4) = (4, 2)
(speedx5, speedy5) = (5, 1)
anim = Animation()
for i = 1:2000
    plt = plot()
    plt = rect(1, 1, 599, 399)
    (x1, y1, speedx1, speedy1, color1) = ball(x1, y1, speedx1, speedy1, color1)
    (x2, y2, speedx2, speedy2, color2) = ball(x2, y2, speedx2, speedy2, color2)
    (x3, y3, speedx3, speedy3, color3) = ball(x3, y3, speedx3, speedy3, color3)
    (x4, y4, speedx4, speedy4, color4) = ball(x4, y4, speedx4, speedy4, color4)
    (x5, y5, speedx5, speedy5, color5) = ball(x5, y5, speedx5, speedy5, color5)
    frame(anim, plt)
end
gif(anim, "gif76.gif")

gif76.gif

No. 77 boundする円とマス目

横400縦400のウィンドウ内を、半径30の赤色の円が、中心の初期位置(30,30)、初速(5,3)で移動し、ウィンドウの端に円の端が接したら反対方向に跳ね返る。ウィンドウは10x10のマス目で区切られており、円の中心が通過したマス目は黒色に塗りつぶされていくプログラムを作成せよ。1画面ごとの休止時間は0.05秒でよい。

function setgrid!(grid, x, y)
    grid[ceil(Int, x/40), ceil(Int, y/40)] = 1
end

function paintgrid(grid)
    for i in 1:10
        for j in 1:10
            if grid[i, j] == 1
                rect(40(i - 1), 40(j - 1), 40i, 40j, :black, fill=true)
            end
        end
    end
end;

start(400, 400)
(r, x, y) = (30, 30, 30)
(speedx, speedy) = (5, 3)
grid = zeros(Int, 10, 10)
anim = Animation()
for i = 1:1000
    plt = plot()
    plt = rect(1, 1, 399, 399)
    setgrid!(grid, x, y)
    paintgrid(grid)
    plt = circle(x, y, r, :red, fill=true)
    x += speedx
    if x > 400 - r || x < r
        speedx = -speedx
    end
    y += speedy
    if y > 400 - r || y < r
        speedy = -speedy
    end
    frame(anim, plt)
end
gif(anim, "gif77.gif")

gif77.gif

No. 78 放物線運動

横600縦400のウィンドウを開き、半径30の円が、初期位置(30,30)、x方向の初速10、y方向の初速25で、下向きに重力が働くものとして放物線運動する様子をアニメーション表示するプログラムを作成せよ(重力加速度の値は下記参照)。1画面ごとの休止時間は0.05秒でよい。
t回目の繰り返しの時に、円の中心座標(x,y)は次の式で計算できる。
x = x0 + u * t;
y = y0 + v * t + a * t * t / 2;
uとvはx,y軸方向の初速、aは重力加速度で-1として計算せよ。

start(600, 400)
(x0, y0) = (30, 30)
(u, v) = (10, 25)
a = -1
anim = Animation()
plt = plot()
for t in 1:50
    x = x0 + t*u
    y = y0 + t*v +a*t^2/2
    circle(x, y, 30, :red, fill=true)
    frame(anim, plt)
end
gif(anim, "gif78.gif")

gif78.gif

No. 79 モンテカルロ法

まず横400縦400のウィンドウを開く。
次に、0から399までの乱数を2つ生成してx,y座標とし、原点(0,0)からの距離が400以下であれば赤、400よりも大きければ青の小さな円をその位置に描く。この手順を繰り返し、正方形中のランダムな位置に円を10000個描きながら赤の点の個数を数えておき、点の個数から円周率の近似値を求めよ。
円周率の近似値は次の式で計算できる。
π=(赤い点の個数 * 4.0)/全部の点の個数

function circle2(ox, oy, n)
    red = 0
    r = 2
    θ = 0:60:360
    x = r.*cosd.(θ)
    y = r.*sind.(θ)
    anim = Animation()
    plt = plot()
    for i in 1:n
        if ox[i]^2 + oy[i]^2 <= 400^2
            plot!(ox[i] .+ x, oy[i] .+ y, linecolor=:red, seriestype=:shape, fillcolor=:red)
            red += 1
        else
           plot!(ox[i] .+ x, oy[i] .+ y, linecolor=:blue, seriestype=:shape, fillcolor=:blue)
        end    
        frame(anim, plt)
    end
    gif(anim, "gif79.gif")
    return red
end;

start(400, 400)
n = 1000
x = rand(0:399, n)
y = rand(0:399, n)
rect(1, 1, 399, 399)
red = circle2(x, y, n)
stop()
円周率 = 4red/n
3.128

gif79.gif

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?