ねらい: 新しいデータ型を作る前に,データ型に実装する機能を整理し,実装する.ねらいは課題A10_1と同じ.
※この課題では,新しいデータ型の作成は行わない.
以下の手順に従って,タートルグラフィクスのタートルを等速直線運動させよ.
ねらい: 新しいデータ型を作成する方法を習得する.データ型を使用しない場合との相違を確認する.ねらいは課題A10_2と同じ.
課題B10_1に対応させて,2次元平面上を運動する質点を表す新しいデータ型 PointMass を作成せよ.
データ型 PointMass の仕様は以下の通りである.
作成したデータ型を用いて,課題B10_1と同様の動作を実現せよ. 作成後のプログラムの一部を示す.データ型 PointMass を定義した後,以下のようにしてデータ型 PointMass を利用するものとする.
import turtle
class PointMass:
def __init__(self):
self.x = 0
(中略)
point = PointMass()
point.setup()
while True:
dt = 0.1
point.move(dt)
ねらい: 初期化メソッドを使用して,インスタンスの生成時に必要な設定を行う方法を習得する.ねらいは課題A10_4と同じ.
課題B10_2で作成したデータ型 PointMass の初期化メソッドを,以下の仕様に変更せよ.
なお,本変更を加えた場合に,課題B10_2におけるインスタンスの生成部分が point = PointMass()
のままだとタートルが中央で静止したままになる(理由は考えてみよ).動作を確認するために,PointMass 型のインスタンスを生成する際に,適当な初期値を与えるようにせよ.
ねらい: データ型を作成することで,複数のインスタンスを簡単に扱えることを実感する.
課題B10_3で作成したデータ型 PointMass を用いて,複数のタートルを同時に動かすことを考える.
まず,PointMass 型のインスタンスを10個生成し,生成されたインスタンスをリスト list_points で保持せよ(※). 初期値は以下のようにランダムに指定せよ.
次に,無限ループ内で,リスト list_points の要素として保持されている PointMass 型のインスタンス全てについて,移動処理を行え(※※).
余力のある人は,メソッド move() を改良し,タートルの向きを進行方向に対して一致させよ.ヒント: 逆三角関数を使う.
(※)のヒント: 空リストを作りインスタンスを後ろに追加(append)していけばよい.
(※※)のヒント: for文を使うとリストの要素を1つずつに対して処理を行える.リストの要素が PointMass 型でも同じである.
本課題のように10個(匹?)のタートルの描画を同時に行うと,デフォルトの速度設定ではかなり遅く感じられる.
高速化する方法1: turtle.Turtle 型のメソッド speed() を用いて速度を設定する.引数に0を与えると,途中のアニメーションを省略するため最高速になる.
self.kame.speed(0)
高速化する方法2: turtle モジュールの関数 delay() を用いて描画の遅延を設定する.引数に0を与えると最高速になる.
turtle.delay(0)
見違えるほど高速になり気持ちがよいので,一度試してみてほしい.
本課題では,PointMass 型を複数生成する際に,for 文と関数 range() を使っていることと思う(もし10回同じ行をコピー&ペーストしていたら,for 文の使い方を復習せよ).
繰り返し変数を繰り返し処理内で使用しない場合も,文法上,何らかの変数名を指定する必要がある.このような場合は,変数名を _ とすることがPythonでは慣例的である.
for _ in range(10):
:
(ブロック内では変数 _ を使わない.暗黙の了解)
変数名を _ とする他の例として,関数やメソッドから複数の値がタプルで返ってくるが,一部の値を利用しない場合に,戻り値を代入する先として用いられるなどの使い方がなされる.
課題B10_4までで作成したデータ型 PointMass に,重力加速度による影響を加えよ.
更なる発展として,以下のうち任意の要素を実装せよ.複数実装してもよい.
跳ね返る: メソッド move() に処理を追加して,画面端で跳ね返るようにする(ただし上端は除く).
色の設定: 描画色を保持するデータ属性を作り,設定するメソッドを加える.何らかの基準に沿って色を変える.
大きさの設定: サイズを保持するデータ属性を作り,設定するメソッドを加える.描画は turtle.Turtle 型のメソッド dot() で行う.
実時間での動作: 変数 dt の値として,前回メソッド move() が呼ばれてからの経過時間を設定する.
ねらい: 作成したプログラムが適切に動作しているかを確認する.
本課題は課題A10_5の続きである.
データ型 Dice が適切に動作していることを確認するために,最大値と最小値をチェックすることを考えてみる.
まず,上記の手順を,面数が 1, 2, ..., 100 であるサイコロを順に生成して行うスクリプトを作成して実行し,結果を確認せよ.この段階では,OKしか出ないはずである.
次に,メソッド shoot() に対して,以下の変更を加えよ.
【誤り生成機能】 生成されたランダムな値に対して,(1) 10000分の1の確率で1を加える (2) 10000分の1の確率で1を引く,の各処理を行った後,戻り値として返す.
再度スクリプトを実行し,結果を確認せよ.
提出するスクリーンショットは,Anaconda Prompt の画面をスクロールさせて探し,NG!の項目が表示されており,かつ最大値がおかしいものと最小値がおかしいものが両方入っている箇所とせよ.スクリーンショットに適した箇所がない場合は,何度か実行せよ.
ねらい: 更に複雑なデータ属性やメソッドを作成する方法を習得する.
※課題B10_7を実施した場合には,メソッド shoot() に【誤り生成機能】を追加していると思われるが,本課題の実施にあたっては削除しておくこと.
これまでに作成したサイコロに,「いかさまモード」を追加する.このモードの仕様は以下の通りである.
また,いかさまモードが正しく動作しているかを確認するために,以下のメソッドを追加する.
面数が同じ Dice 型のインスタンスを2つ生成し,片方をいかさまモードにした後,それぞれを10000回実行し,各サイコロの出目の回数を表示して,いかさまモードが正しく動作していることを確認せよ.
コメント: メソッド aggregate() の実装について,aggregate()が呼ばれるたびに全履歴から回数を集計する方法と,あらかじめ各出目の回数をカウントする辞書を用意しておき,サイコロを振る(shoot())たびにカウントする方法が考えられる(他にもあるかもしれない)が,一長一短である.前者はデータの管理が楽だが頻繁に呼び出されると速度が遅い.後者は高速だが履歴と各出目の回数の2つのデータを常に整合させておかなければならない.