はじめに
「名門の森」は、物理体系的理解と演習を重視した問題集です。本記事では、この「名門の森」をPythonと生成AI(ChatGPTなど)を活用しながら、より実践的・再現可能な方法で学習・再構築していくことを目的としています。
◆ 学習の進め方
学習の基本方針は次の通りです:
- Google Colab 上で Python コードを使いながら、数式やグラフ、計算結果をインタラクティブに確認する。ブラウザとGoogleアカウントがあれば利用でき、ノートブック形式で記録と再現が可能です。
- わからないところや式展開の途中などは、生成AI(例:ChatGPT)に式や質問を入力して補完する。途中式の導出、変数定義、定義の再確認などに活用します。
- 理解した内容や確認できた数式・コード・考察は、自分の言葉でプレーンテキストまたはMarkdown+コードセル付きのノート形式で整理する。これにより、検索・再利用・共有が容易になります。
問題1:放物運動
# ============================================================
# プログラム名:monkey_hunting_simulation.py
# Program Title: Monkey Hunting Simulation – Does the projectile hit?
# ============================================================
import numpy as np
import matplotlib.pyplot as plt
# ---------------------------------------------------------------
# ■ 問題(日本語)
# 地上の射手が、木の上にいるサルを狙って物体を角度θで発射する。
# 同時にサルは枝から落下(自由落下)を始める。
# 射手がサルの初期位置を正確に狙えば、サルに命中するかを確認せよ。
#
# ■ Problem (English)
# A projectile is launched at a monkey hanging from a tree.
# The monkey lets go and begins to fall at the same moment the projectile is fired.
# If the initial velocity vector is aimed exactly at the monkey’s initial position,
# will the projectile hit the monkey?
# ---------------------------------------------------------------
# -------------------------------
# PARAMETERS / パラメータ設定
# -------------------------------
g = 9.8 # gravitational acceleration [m/s^2] / 重力加速度
v0 = 20.0 # initial speed [m/s] / 発射初速度
a = 10.0 # horizontal distance to monkey [m] / 水平方向距離
b = 5.0 # vertical height of monkey [m] / 鉛直方向高さ
# Compute angle theta so that the initial velocity vector points to (a, b)
# θ = arctan(b / a)
theta = np.arctan2(b, a)
# Velocity components
v0x = v0 * np.cos(theta)
v0y = v0 * np.sin(theta)
# Time to impact (based on straight-line motion)
t_hit = np.sqrt(a**2 + b**2) / v0
# Time samples from 0 to t_hit
t = np.linspace(0, t_hit, 100)
# -------------------------------
# TRAJECTORIES / 軌道計算
# -------------------------------
# P's trajectory: projectile motion
x_p = v0x * t
y_p = v0y * t - 0.5 * g * t**2
# Q's trajectory: free fall from (a, b)
x_q = np.full_like(t, a)
y_q = b - 0.5 * g * t**2
# -------------------------------
# PLOTTING / プロット描画
# -------------------------------
plt.figure(figsize=(8, 6))
plt.plot(x_p, y_p, label='Projectile P', color='blue')
plt.plot(x_q, y_q, label='Falling monkey Q', color='red', linestyle='--')
plt.plot(a, 0, 'ko', label='Impact Point') # 衝突点
plt.plot(0, 0, 'bo', label='Launch Point')
plt.plot(a, b, 'ro', label='Monkey Start Position')
plt.xlabel('Horizontal distance x [m]')
plt.ylabel('Vertical height y [m]')
plt.title('Monkey Hunting Simulation')
plt.grid(True)
plt.axis('equal')
plt.legend()
plt.tight_layout()
plt.show()
# -------------------------------
# RESULT / 結果表示
# -------------------------------
# Compute vertical difference at x = a
# t_hit is the time both reach same horizontal point
y_p_at_hit = v0y * t_hit - 0.5 * g * t_hit**2
y_q_at_hit = b - 0.5 * g * t_hit**2
diff = abs(y_p_at_hit - y_q_at_hit)
print("---- Simulation Result ----")
print(f"Time to impact: {t_hit:.3f} s")
print(f"Projectile y at impact: {y_p_at_hit:.3f} m")
print(f"Monkey y at impact: {y_q_at_hit:.3f} m")
print(f"Vertical difference: {diff:.5f} m")
if diff < 0.01:
print("✅ HIT: The projectile hits the falling monkey.")
else:
print("❌ MISS: The projectile misses the monkey.")
問題2:放物運動
import numpy as np
import pandas as pd
# Program Name: Projectile Motion Calculation Based on Meimon no Mori p.12
print("Program Name: Projectile Motion Calculation Based on Meimon no Mori p.12\n")
# 定数設定
g = 9.8 # 重力加速度 [m/s^2]
e = 0.8 # 反発係数
theta_deg = 45 # 発射角度 [度]
theta = np.radians(theta_deg) # ラジアンに変換
v0 = 10.0 # 初速度 [m/s]
l = 5.0 # 壁までの距離 [m]
# 計算
# 最高点の高さ h1
h1 = (v0**2) * (np.sin(theta)**2) / (2 * g)
# 反射後の最高点の高さ h2
h2 = (e * v0 * np.sin(theta))**2 / (2 * g)
# AB間の時間 t2
t1 = l / (v0 * np.cos(theta))
t2 = 2 * v0 * np.sin(theta) / g
# BC = e * v0 * cosθ * (t2 - t1)
vx = v0 * np.cos(theta)
BC = e * vx * (t2 - t1)
# OB = e^2 * v0^2 * sin(2θ) / g
OB = (e**2) * v0**2 * np.sin(2 * theta) / g
# 合計距離 l = OB + BC
l_total = OB + BC
# 結果のデータフレーム作成
results = pd.DataFrame({
"項目": [
"初速度 v0 [m/s]",
"発射角度 θ [deg]",
"最高点の高さ h1 [m]",
"反射後の高さ h2 [m]",
"AB間の時間差 t2 - t1 [s]",
"水平方向距離 BC [m]",
"着地点 OB [m]",
"合計距離 l = OB + BC [m]"
],
"値": [
v0,
theta_deg,
round(h1, 3),
round(h2, 3),
round(t2 - t1, 3),
round(BC, 3),
round(OB, 3),
round(l_total, 3)
]
})
# Google Colabで表示
results
問題3:放物運動
# ============================================================
# Program: reflection_projectile_theoretical_vs_simulation.py
# Purpose: 名門の森に基づく「斜方投射+多段反射」運動の可視化と理論比較
# ============================================================
import numpy as np
import matplotlib.pyplot as plt
# -----------------------------
# PARAMETERS / パラメータ設定
# -----------------------------
g = 9.8 # gravity [m/s^2]
h = 2.0 # initial height [m]
e = 0.8 # coefficient of restitution
theta_deg = 45 # launch angle in degrees
theta = np.radians(theta_deg)
# -----------------------------
# Step 1: 初速度 v0 = sqrt(2gh)
# -----------------------------
v0 = np.sqrt(2 * g * h)
# -----------------------------
# Step 2: 速度成分
# -----------------------------
v0x = v0 * np.cos(theta)
v0y = v0 * np.sin(theta)
# -----------------------------
# Step 3: 時間と高さを各バウンドについて計算
# -----------------------------
n_bounce = 3 # バウンド回数
colors = ['blue', 'green', 'orange', 'purple']
x_all = []
y_all = []
x_last = 0
for i in range(n_bounce):
# 各バウンドの速度
vx_i = (e ** i) * v0x
vy_i = (e ** i) * v0y
t_flight = 2 * vy_i / g # 滞空時間
# 時間分割
t = np.linspace(0, t_flight, 100)
x = x_last + vx_i * t
y = vy_i * t - 0.5 * g * t**2
x_all.append(x)
y_all.append(y)
x_last = x[-1] # 次の初期位置に
# -----------------------------
# Step 4: 理論値の計算
# -----------------------------
# T_inf = 2 * e * v0 * sinθ / (g * (1 - e))
T_inf = (2 * e * v0 * np.sin(theta)) / (g * (1 - e))
# OB_theory = (4 * e * h * sinθ) / (1 - e^2)
OB_theory = (4 * e * h * np.sin(theta)) / (1 - e**2)
# -----------------------------
# Step 5: プロット描画
# -----------------------------
plt.figure(figsize=(10, 5))
for i in range(n_bounce):
plt.plot(x_all[i], y_all[i], label=f'Trajectory {i+1}', color=colors[i])
plt.axhline(0, color='gray', linestyle='--')
plt.title("Multiple Reflection Projectile ")
plt.xlabel("Horizontal distance x [m]")
plt.ylabel("Vertical height y [m]")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
# -----------------------------
# Step 6: 結果出力
# -----------------------------
print("===== Simulation Summary =====")
print(f"Initial speed v₀ = {v0:.3f} m/s")
print(f"Total flight time (T_inf) = {T_inf:.3f} s")
print(f"Theoretical OB distance = {OB_theory:.3f} m")
print(f"Simulated x_final = {x_last:.3f} m")
print("===============================")
問題4:剛体の釣り合い
# ============================================================
# Program: moment_and_force_balance.py
# Purpose: Calculation and Visualization of Moment and Force Balance for a Rigid Body on an Inclined Plane Based on Meimon no Mori
# ============================================================
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# -----------------------------
# Parameters / パラメータ設定
# -----------------------------
g = 9.8 # gravity acceleration [m/s^2]
M = 1.0 # mass of the rod [kg], assumed for calculation
l = 1.0 # length unit [m], assumed for scaling
theta_deg = 53.13 # angle θ in degrees (approx. for sinθ=4/5, cosθ=3/5)
theta = np.radians(theta_deg)
# Trigonometric values from triangle ABC (3:4:5)
cos_theta = 3/5
sin_theta = 4/5
# -----------------------------
# Step 1: Moment about point B
# -----------------------------
# Mg * 5l * cosθ = R * 10l * sinθ
R = (M * g * 5 * l * cos_theta) / (10 * l * sin_theta)
R = (3/8) * M * g # Simplified as per derivation
# -----------------------------
# Step 2: Vertical force balance
# -----------------------------
N = M * g
# -----------------------------
# Step 3: Horizontal force balance
# -----------------------------
F = R
# -----------------------------
# Step 4: Net reaction force at point B
# -----------------------------
net_force = np.sqrt(N**2 + F**2)
net_force_simplified = (np.sqrt(73) / 8) * M * g
# -----------------------------
# Step 5: Alternative moment about point A (verification)
# -----------------------------
# N * 10l * cosθ = Mg * 5l * cosθ + F * 10l * sinθ
moment_A_left = N * 10 * l * cos_theta
moment_A_right = M * g * 5 * l * cos_theta + F * 10 * l * sin_theta
moment_A_check = np.isclose(moment_A_left, moment_A_right)
# -----------------------------
# Step 6: DataFrame for results
# -----------------------------
results = pd.DataFrame({
"項目 / Item": [
"支持反力 R [N] / Support force R",
"垂直抗力 N [N] / Normal force N",
"静止摩擦力 F [N] / Friction force F",
"合力の大きさ [N] / Net reaction force",
"A点まわりのモーメント平衡 / Moment balance at A"
],
"値 / Value": [
round(R, 3),
round(N, 3),
round(F, 3),
round(net_force, 3),
"Satisfied" if moment_A_check else "Not satisfied"
]
})
# -----------------------------
# Step 7: Vector visualization with adjusted scale
# -----------------------------
plt.figure(figsize=(10, 6))
# Origin at point B (0,0)
origin = np.array([0, 0])
# Vectors for forces at point B
N_vector = np.array([0, N]) # Normal force (vertical)
F_vector = np.array([F, 0]) # Friction force (horizontal)
R_vector = np.array([-R * sin_theta, R * cos_theta]) # Support force at angle
net_force_vector = N_vector + F_vector # Net reaction force at B
# Plot vectors with adjusted scale
scale = 20.0 # Adjusted scale (larger value = shorter arrows)
plt.quiver(*origin, *N_vector, color='blue', scale=scale, label='Normal force N', width=0.005, alpha=0.8)
plt.quiver(*origin, *F_vector, color='red', scale=scale, label='Friction force F', width=0.005, alpha=0.8)
plt.quiver(*origin, *R_vector, color='green', scale=scale, label='Support force R', width=0.005, alpha=0.8)
plt.quiver(*origin, *net_force_vector, color='purple', scale=scale, label='Net reaction force', width=0.005, alpha=0.8)
# Set axis limits based on maximum force magnitude
max_force = max(N, F, net_force, np.linalg.norm(R_vector)) * 1.2 # 20% margin
plt.xlim(-max_force, max_force)
plt.ylim(-max_force, max_force)
# Plot settings
plt.title("Force Vectors at Point B")
plt.xlabel("Horizontal Force [N]")
plt.ylabel("Vertical Force [N]")
plt.grid(True)
plt.legend()
plt.axis('equal') # Equal scaling for x and y axes
plt.tight_layout()
# Show plot
plt.show()
# -----------------------------
# Step 8: Display results
# -----------------------------
print("===== Calculation Summary =====")
print(results.to_string(index=False))
print("===============================")
問題5:剛体の釣り合い
# ============================================================
# Program: sliding_vs_tipping_analysis.py
# Purpose: Sliding vs. Tipping condition analysis for rigid body on incline
# 名門の森の式に基づき、滑り条件・転倒条件を数式で比較
# ============================================================
import numpy as np
import pandas as pd
# -----------------------------
# Parameters / パラメータ設定
# -----------------------------
g = 9.8 # gravity [m/s^2]
M = 1.0 # mass [kg]
a = 0.5 # center of mass to base (horizontal) [m]
b = 1.0 # center of mass to base (vertical) [m]
mu = 0.6 # friction coefficient
theta_deg = 30 # incline angle [deg]
theta = np.radians(theta_deg) # convert to radians
# -----------------------------
# Step 1: Sliding condition (摩擦による滑り)
# F1 = Mg (μ cosθ - sinθ)
F1 = M * g * (mu * np.cos(theta) - np.sin(theta))
# -----------------------------
# Step 2: Tipping condition (モーメントによる転倒)
# F2 = (Mg / 2b) * (a cosθ - b sinθ)
F2 = (M * g / (2 * b)) * (a * np.cos(theta) - b * np.sin(theta))
# -----------------------------
# Step 3: Comparison
# → F1 > F2 → tipping occurs first
# → F2 > F1 → sliding occurs first
if F1 > F2:
mode = "Tipping occurs first (転倒が先)"
elif F2 > F1:
mode = "Sliding occurs first (滑りが先)"
else:
mode = "Simultaneous (同時に発生)"
# -----------------------------
# Output as table
# -----------------------------
result_data = {
"Incline θ (deg)": theta_deg,
"F1 (Sliding condition)": round(F1, 3),
"F2 (Tipping condition)": round(F2, 3),
"Result": mode
}
df = pd.DataFrame([result_data])
print("=== Sliding vs. Tipping Analysis ===")
print(df.to_string(index=False))