2023-2I プログラミング1 第04回 講義資料

2023年05月11日(木)5・6時限

1 準備

2 前回までの復習

プログラミングスキルを効果的に習得するためには 調べる試す考える をバランスよく実践していくことが求められます。

以下は、前回までの学習内容に基づく演習です。どれだけ定着しているでしょうか? もし、定着していなければ 自分に適した「学びのスタイル」を試行錯誤で探ってください

2.1 演習①

3 標準入力

標準入力Standard Input)とは、コンピュータ上でプログラムが実行される際、ユーザーからの入力を受け取るための窓口で、そこには主にキーボードやファイルを通して文字列データを与えます (流し込みます) 。

例えば、GUI (Graphical User Interface) を持たない コンソールプログラム においてユーザーに名前や年齢を入力 してもらうような処理は標準入力を使って実現します。

Pythonでは、input という関数を使って標準入力を受け取り、それを 文字列として変数に格納 します。例えば、標準入力から 2023 のような数値を入力しても、変数に格納されるデータは 数値でなく文字列 となるので注意してください。

次のプログラムを実行して、標準入力 の動作を確認してください。

%reset -f
print('名前を入力してください >> ',end='')
name = input()
print('年齢を入力してください >> ',end='')
age = input()
print(f'{name}さんは{age}歳なんですねwww')

変数 age に格納された値が 文字列であることを確認 するために、次のプログラムを実行して動作を確認してください。

%reset -f
print('名前を入力してください >> ',end='')
name = input()
print('年齢を入力してください >> ',end='')
age = input()
print(f'{name}さんの年齢を2倍すると{age*2}歳っすねwww') # ここを変更

4 文字列を整数値に変換 int関数

文字列を整数値に変換するためには int() 関数を使用します。次のプログラム実行して「文字列が整数値に変換できていること」を確認せよ。

%reset -f
print('あなたの年齢を入力してください >> ',end='')
age = input()
age = int(age) # ここで文字列から整数値に変換
print(f'年齢を2倍すると{age*2}歳っすねwww')

5 文字列を実数値に変換 float関数

文字列を実数値 (小数を含む数値、厳密には浮動小数点数) に変換するためには float() 関数を使用します。

%reset -f
print('''時刻0において速度 v (m/s) の物体が、
一定の加速度 a (m/s^2) を保ちながら
t秒間の間に進む 距離x(m) を求めます。
''')
v = input('速度 v (m/s) を入力してください >> ')
v = float(v)
a = input('加速度 a (m/s^2) を入力してください >> ')
a = float(a)
t = input('走行時間 t (s) を入力してください >> ')
t = float(t)
x = v*t + 0.5*a*t**2
print(f'走行した距離は {x} (m) です。')

5.1 演習②

標準入力から半径 r と高さ h を与えて「円柱」の体積 V と表面積 S を計算するプログラムを作成せよ。

なお、\(\pi\) (定数) は、mathライブラリから、次のように値を得ることができる。

%reset -f
import math
p = math.pi
print(f'pi={p}')

6 コメント

プログラムにおける コメント とは、コードのなかに説明や注意事項、開発者の意図などを表すために記すテキストです。コメントはプログラムの実行に影響を与えず、他の開発者や未来の自分がコードを理解する助けとして使用されます。

Python では # がコメントを表す記号になります。

Google Colab. や VSCode などの開発環境では Ctrl+/ のショートカットキーより、アクティブ行の「コメントアウト (コメント化) 」「アンコメント (コメント解除) 」を切り替え可能です。

上記では、標準入力を取り上げましたが、ノートブック開発環境においては 基本的に標準入力は使用しません。特にデバッグ (プログラムが意図した動作をするようにエラーを取り除いたり、検証したりする行為) の際には、実行毎に標準入力から値を与えることは煩雑なので、以下のようにコメントを利用して「標準入力」と「リテラルによる入力(ハードコーディング)」を切り替えます。

6.1 計算式をテストするとき

標準入力部をコメントアウトした例

%reset -f
print('''時刻0において速度 v (m/s) の物体が、
一定の加速度 a (m/s^2) を保ちながら
t秒間の間に進む 距離x(m) を求めます。
''')
# v = float(input('速度 v (m/s) を入力してください >> '))
# a = float(input('加速度 a (m/s^2) を入力してください >> '))
# t = float(input('走行時間 t (s) を入力してください >> '))
v = 1.5
a = 2
t = 4
x = v*t + 0.5*a*t**2
print(f'走行した距離は {x} (m) です。')

6.2 リリースするとき、標準入力をテストするとき

数値リテラルの入力をコメントアウトした例

%reset -f
print('''時刻0において速度 v (m/s) の物体が、
一定の加速度 a (m/s^2) を保ちながら
t秒間の間に進む 距離x(m) を求めます。
''')
v = float(input('速度 v (m/s) を入力してください >> '))
a = float(input('加速度 a (m/s^2) を入力してください >> '))
t = float(input('走行時間 t (s) を入力してください >> '))
# v = 1.5
# a = 2
# t = 4
x = v*t + 0.5*a*t**2
print(f'走行した距離は {x} (m) です。')

Google Colab.では複数行を選択した状態で Ctrl+/ を実行すると、複数行をまとめてコメントアウト/アンコメントできます。実際に確認してみてください。

7 Colab.のフォーム機能

Google Colab. の環境では フォーム という機能を使って入力を与えることもできます。

次のコードを実行して、その動作を確認してみてください。

%reset -f
name = '山田'     #@param {type:"string"}
height = 172.5    #@param {type:"number"}
age = 10          #@param {type:"slider", min:10, max:80, step:1}
print(f'{name}さんの身長は{height}で、年齢は{age}歳で、1年後は{age+1}歳になっています')

この フォーム の機能は、Google Colab. (Jupyter) 環境でのみ使用ができます (Python固有の機能ではありません)。詳細については 公式ページ を参考にしてください。

7.1 フォームの利用例

次のコードを実行して、動作を確認してみてください

%reset -f
#@markdown # 物理学習支援ツール
#@markdown 時刻 $0$ において速度 $v$ ($\mathrm{m/s}$) の物体が、
#@markdown 一定の加速度 $a$ ($\mathrm{m/s^{2}}$) を保ちながら
#@markdown $t$秒間の間に進む 距離$x$($\mathrm{m}$) を求めます。

#@markdown 速度 $v$ ($\mathrm{m/s}$) を入力してください 
v = 1.5    #@param {type:"number"}
#@markdown 加速度 $a$ ($\mathrm{m/s^{2}}$) を入力してください 
a = 2    #@param {type:"number"}
#@markdown 走行時間 $t$ ($\mathrm{s}$) を入力してください 
t = 4    #@param {type:"number"}

x = v*t + 0.5*a*t**2
print(f't=0 から t={t} に走行した距離は {x:.2f} (m) です。')

8 繰返し構文

Python では次のような構文で n 回の繰り返し処理ができます。

%reset -f
n = 5
for i in range(n):
  print('Hello ', end='')
  print('World.')

上記を実行すれば、Hello World. という文字が5回出力されます。

Pythonでは、繰返し範囲を インデント (字下げ) により指示します。例えば、次にように05行目のインデントを解除して、どのように動作が変化するか、また、なぜそのようになるか、を確認してみてください。

%reset -f
n = 5
for i in range(n):
  print('Hello ', end='')
print('World.')

ここでは、変数 n を使用していますが、次のように range の引数に直接数値を入れることもできます。

%reset -f
for i in range(7):
  print('Hello World.')

8.1 演習③

繰り返し構文を利用して、次のような出力を得るプログラムを記述してください。

AAA
AAA
AAA
BBBB
BBBB
BBBB
BBBB
BBBB

AAA が3行、BBBBが5行、出力されています。。

9 休憩

ChatGPTに質問してみましょう。

私は高専の2年生です。知能情報コースという情報系の学科に所属してソフトウェアエンジニアとして就職して新規開発プロジェクトに従事すること目指しています(既存案件の保守業務に携わることや、SESなどの派遣系の企業に就職することは希望していません)。担任の先生からは「そのようなキャリアを目指すのであれば、学校での授業という「受動的で最低限のプログラミング学習」では、新卒採用時に要求されるスキルレベル(期待されているスキルレベル)に到達しない。授業の枠を超えて自学したり、課外活動としてクラスメイトとソフトウェア開発の経験を積むことが絶対的に必要だ。」と言われました。このアドバイスは「まとも」なものですか。

10 タートルグラフィックス

繰り返し構文に到達したので、その応用としてタートルグラフィックスで遊んでみます。

タートルグラフィックス (Turtle Graphics) は、プログラミング言語で簡単な図形やアニメーションを描画するためのグラフィカルな方法です。Turtle は、そのまま「亀」の意味になります。

タートルグラフィックス

タートルグラフィックスの核となる概念は「タートル」と呼ばれるカーソルです。タートルは、プログラムによって指示されたとおりに画面上を移動し、その軌跡に沿って線や図形を描画します。タートルには「 前進」「後退」「左回転」「右回転」などの基本的な操作が用意されており、これらの操作を組み合わせてさまざまな図形を描くことができます。

タートルグラフィックスは、特に子どもたちや初心者向けのプログラミング教育において、視覚的で直感的な理解を促すためによく使用されます。また、繰り返しや条件分岐などのプログラミングの基本的な概念を学ぶのにも役立ちます

10.1 準備

独立したコードセルを作成して、以下を実行してください 。以降、ノートブックを再開するたびに (GoogleColab. に再接続するたびに) 実行してください。

!pip install ColabTurtle

上記はPythonのプログラムではなく、Colab.を実行している 仮想マシン (Linux) に対する直接的な命令 (コマンド) になります。このコマンドは、Pythonの パッケージ管理システムであるpip を使って、ColabTurtleというライブラリを仮想マシンにインストールするために実行しています。

この「ColabTurtle」は、Google Colab 上でも動作するように Turtle Graphics を実装したライブラリで、簡単な図形やアニメーションを描画するために使われます。

10.2 基本形

%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))

02行目では ColabTurtle.Turtle という モジュール(ライブラリ) を インポート して、t という略称で扱うことを指示しています。もともとインポートとは「輸入」の意味ですが、ここでは「自分のプログラムのなかにXXXというライブラリを取り込む」のようなイメージでとらえてください。

03行目では、t (=ColabTurtle.Turtleを略名) の 初期化(初期設定) をしています。Initialize という語 (初期化という意味) はプログラミングでは頻出するので覚えておいてください。

10.2.1 補足

上記のプログラムは 02行目で as t を使わずに以下のように書くこともできます。可読性が下がり、タイプミスしやすくなるというデメリットがあります。

%reset -f
import ColabTurtle.Turtle
ColabTurtle.Turtle.initializeTurtle(initial_speed=5,initial_window_size=(400,400))

例えば、02行目で import ColabTurtle.Turtle as tur としたら、03行目はどのように記述するべきでしょうか。考えて実際に手を動かして実行してみてください。

10.3 絶対位置座標を与えてカメを移動させる

次のプログラムを実行して結果を確認してください。

%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))
t.goto(50,30)

さらに、次のプログラムを実行して結果を確認してください。

%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))
t.goto(50,30)
t.goto(50,100) # 追加

「コード」と「実行結果」を突き合わせながら、次のようなことを推測して、さらに確証を得てください。プログラミングでは、このように「サンプルコード」と「その実行結果」から 機能や仕組み、内部動作を推測する・検証する 能力が強く要求されます。この過程では goto メソッド (関数) のパラメータを変更したり文を追加したりして、実際に試すこともしてください。また、リファレンス も参照してください。

上記のことが、指示されなくても反射的に、自然にできるようになってください。さらに「引数に描画領域の範囲外の値を与えるとどうなるのか」「goto メソッドの引数に実数値を与えるとどうなるのか」のような好奇心を持てるようになってください。

10.4 ペンの上下/形状/色を操作する、背景色を設定する

次のプログラムを実行して結果を確認してください。また、shape メソッド、bgcolo メソッド、color メソッド、up メソッド、dowb メソッドなどの各メソッドがどのような機能を持つのか、引数としてどのような値を持つのかについて、考える試す を通して推測し、また、調べる試す を通して確証を得てください。

%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))

# ペンの形状をカメ('turtle')から円('circle')に変更 
t.shape(shape='circle')

# 背景色をセット(RGB指定 0~255)
t.bgcolor(240,240,240)

# ペンの色をセット(RGB指定 0~255)
t.color(0,0,255)
  
t.up() # ペンを持ち上げる
t.goto(50,30)

t.down() # ペンを下す
t.goto(50+300,30)

t.hideturtle() # ペン先を非表示

10.5 絶対座標で移動・相対位置指示で移動

次の p1.py は絶対座標でカーソルを移動させて正方形を描いています。また p2.py は相対位置指示で移動で正方形を描いています。実際に動作させて確認してから、コードを解読してください。

%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))
t.shape(shape='circle')
t.bgcolor(0,0,0)
t.color(0,255,0)
  
t.up(); t.goto(50,50);t.down() # 50,50に移動

t.goto(350,50)
t.goto(350,350)
t.goto(50,350)
t.goto(50,50)
%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))

t.shape(shape='circle')
t.bgcolor(0,0,0)
t.color(0,255,0)

t.up(); t.goto(50,50); t.down() # 50,50に移動

t.right(90)
t.forward(300)
t.right(90); t.forward(300)
t.right(90); t.forward(300)
t.right(90); t.forward(300)

新しく登場した right メソッドについても、好奇心を持って「実数値は与えられるのか」「負の値は与えられるのか」「360を超える値は与えられるのか」「もしかして left メソッドも存在するのか」といったことが自然に思い浮かぶように思考回路を変容させて、さらに実際に確認してみる習慣を身に付けてください (指示されなくても…)。

1行に複数の文を記述する方法

Pythonでは原則として1行に1文を記述しますが、セミコロン ; を使って1行のなかに複数の文を記述することができます。

例えば、次の2つのプログラムは同じ意味を持ちます。

t.up();t.goto(50,50);t.down()
t.up()
t.goto(50,50)
t.down()

10.5.1 発展1 (五芒星)

%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))

t.shape(shape='circle');t.bgcolor(0,0,0);t.color(0,255,0)
t.up(); t.goto(400/2,400/2);t.down()

d = 300
t.up()
t.forward(d/2);t.right(36/2)
t.down()
t.right(180-36);t.forward(d)
t.right(180-36);t.forward(d)
t.right(180-36);t.forward(d)
t.right(180-36);t.forward(d)
t.right(180-36);t.forward(d)

10.5.2 発展2 (三角形)

%reset -f
import ColabTurtle.Turtle as t
t.initializeTurtle(initial_speed=5,initial_window_size=(400,400))

t.shape(shape='circle');t.bgcolor(0,0,0);t.color(0,255,0)
t.up();t.goto(400/2,400/2);t.down()

a = 60
d = 300
t.up()
t.forward(d/2);t.right(a/2)
t.down()
t.right(180-a);t.forward(d)
t.right(180-a);t.forward(d)
t.right(180-a);t.forward(d)

10.5.3 演習④

11 課題 (宿題)

次の「演習⑤」について、今回の後期で作成したノートブックのなかで取組み、そのリンクを Google Classroom 経由で提出してください。

11.1 演習⑤-1

高専入学後、現在までに学習した「物理」や「数学」、その他の「専門科目」に関する何らかの演習問題を取り上げ、それをテキストセルに記述してください。また、それを解くための Python プログラムを作成し、その実行結果が正しいことをテスト (確認・検証) してください。どのような方法でテストしたのか、その方法と結果もテキストセルに記載してください。

ここでは、次のような関数、構文、機能を複数組み合わせたプログラムを期待しています。授業で扱っていないPythonのライブラリや構文を使っても問題ありません (ただし、機能や意味を十分に理解したうえで使ってください)。

なお、問題を解くためのプログラムではなく、その学習を支援ような観点のプログラムでも問題ありません。

11.2 演習⑤-2

タートルグラフィックスを使って、以下の条件でラインアートを作成してください。

11.3 演習⑤-3

テキストセルに「この課題の取組み時間:XXX分」を記述してください。

12 おまけ

今後、関数(再帰処理)、条件分岐の構文、randomライブラリ、mathライブラリなどを学習していけば、次のようなプログラムを内容を理解して書けるようになっていきます。

%reset -f
import ColabTurtle.Turtle as t
import math
import random
import matplotlib.pyplot as plt

cm = plt.get_cmap('Wistia',17)

t.initializeTurtle(initial_speed=13,initial_window_size=(400,300))
t.shape(shape='circle')
t.bgcolor('black')
t.color(*map(lambda p:int(p*255),cm(1)[:3]))

t.up(); t.goto(t.window_width()//2,t.window_height()-30);t.down()

color_offset = 0
init_length = 40
init_width  = 15
min_length = 12
max_level = 12

def draw_branch(p, w, v):
  p2 = max(1,int(p + (p * random.randint(-15,15)*0.01)))
  t.down();t.width(w);t.color(*map(lambda p:int(p*255),cm(color_offset+v)[:3]))
  t.forward(p2);
  generate_branch(math.ceil(p2*0.82),math.ceil(w*0.75),v+1)
  t.up();t.back(p2)

def generate_branch(p, w, v):
  if p < min_length or v > max_level:
    return
  else:
    a1,a2 = 20+random.randint(-2,2), 20+random.randint(-2,2)
    t.left(a1)
    draw_branch(p,w,v)
    t.right(a1+a2)    
    draw_branch(p,w,v)
    t.left(a2)

t.face(-90)
t.color(*map(lambda p:int(p*255),cm(color_offset)[:3]))
t.width(init_width+1)
t.forward(init_length)
generate_branch(init_length,init_width,0)
t.color(*map(lambda p:int(p*255),cm(color_offset)[:3]))
t.back(init_length)