Python学習日記 – 座標移動
はじめに
新学期が始まって1か月、学業に追われて深く考える時間はあまりなかった。本を読むことはよくあるが、Pythonの本よりは文学書を読むことが多かった。休み前日の試験が終わった後、Pythonの本をめくって、自分にとって新しい発見があったので、学期前に作ったプログラムを改良・アップグレードして、座標移動プログラムを書いた。
出力プレビュー
「#」の部分は私の説明で、実際の実行時には表示されない
Tell me your X position:
10 # 私が入力した値
Tell me your Y position:
0 # 私が入力した値
Original X position is 10.0
Original Y position is 0.0.
Original position is (10.0,0.0).
New X position is 12.0
New Y position is -1.0
New position is ((12.0, -1.0))
Introduction rules
There are four cases in total
Spead: slow
Add 1 X position and reduce 2 Y position
Spead: medium
Add 2 X position and reduce 1 Y position
Spead: fast
Add 3 X position and add 3 Y position
Spead: veryfast
Add 4 X position and add 6 Y position
全コード
############################
### Date 2021 October 1 ###
### Author Magneto ###
### Name 座標移動 <——>
### Random True ###
### Language Python ###
############################
# randomモジュールを導入
import random
# speadの内容を定義し、ランダムに処理
spead_0 = ['slow', 'medium', 'fast', 'veryfast']
spead_random = random.choice(spead_0)
# ユーザーがX座標を入力
print("\nTell me your X position:")
your_x_position = input()
# ユーザーがY座標を入力
print("Tell me your Y position:")
your_y_position = input()
# X座標を変換
x_position = float(your_x_position)
# Y座標を変換(+1は初期位置)
y_position = float(your_y_position)
# 初期座標値を出力
print(f"\nOriginal X position is {x_position}"
f"\nOriginal Y position is {y_position}."
f"\nOriginal position is ({x_position},{y_position}).")
# if-elif-else文
# slowを定義
if spead_random == 'slow':
# アルゴリズム
x_increment = x_position + 1
y_increment = y_position - 2
# mediumを定義
elif spead_random == 'medium':
# アルゴリズム
x_increment = x_position + 2
y_increment = y_position - 1
# fastを定義
elif spead_random == 'fast':
# アルゴリズム
x_increment = x_position + 3
y_increment = y_position + 3
# その他を定義。速度は最速とみなし、メーター表示上限に達する
else:
# アルゴリズム
x_increment = x_position + 4
y_increment = y_position + 6
# 移動後の座標を出力
print(f"New X position is {x_increment}"
f"\nNew Y position is {y_increment}"
f"\nNew position is ({x_increment,y_increment})")
# 内容紹介の定義
alien = {
'slow': 'Add 1 X position and reduce 2 Y position',
'medium': 'Add 2 X position and reduce 1 Y position',
'fast': 'Add 3 X position and add 3 Y position',
'veryfast': 'Add 4 X position and add 6 Y position'
}
print("\nIntroduction rules")
# 文字置換とタイプ総数の紹介
if len(alien) == 4:
# 文字置換
The_number = 'four'
# タイプ総数の紹介
print(f"There are {The_number} cases in total")
# その他の場合
else:
# 空値を出力
print("NULL")
# for文で出力
for spead_1, position in alien.items():
print(f"Spead: {spead_1}")
print(f"{position}")
コード分析
分析の説明
コード分析では、何行目のコードが何に使われるかを具体的に説明する。行数にはコメントの行数も含まれる。
randomモジュール
9行目の import random で、randomモジュールをこのプログラムに導入している。randomの役割は、辞書の内容をランダムに処理することだ。これは12行目で確認できる。11行目で辞書の内容を書き、randomでランダム処理をした。もしこれを出力すると:
# randomモジュールを導入
import random
# speadの内容を定義し、ランダムに処理
spead_0 = ['slow', 'medium', 'fast', 'veryfast']
spead_random = random.choice(spead_0)
# 値を出力
print(f"現在の速度は{spead_random}")
spead_0 から任意の値を取り出して出力する。最初の値を出力するわけではない。
出力内容
eg:
現在の速度はmedium
コードを改良する前は、randomを多用していた(詳しくは『Python学習日記 – 法外狂徒の物語』参照)。 改良後は、ランダムな値を人の入力に変更した。よりランダムだ(嘘)。
しかし速度は依然としてランダム処理のままだ。計算が楽だからだ。入力する必要はない。
人の入力
inputを使って数値を入力する:
# ユーザーがX座標を入力
print("\nTell me your X position:")
your_x_position = input()
# ユーザーがY座標を入力
print("Tell me your Y position:")
your_y_position = input()
ここで your_座標タイプ_position は、次の変換ロジックに対応する。なお、私は次のようなコードは使わなかった:
a = input("Tell me your X positison:")
出力内容
eg:
Tell me your X position:0 # 0は私が入力した値
このようなコードを使うと、実行結果が見苦しくなるからだ。優れたプログラムは、ロジックと美しさを兼ね備えている。
演算問題の解決
inputで入力した場合、元の方法で出力された値は正常に演算できない。エラーになる。
エラーコード例
a = input("Number is ")
b = a + 3
print(f"Now your number is {b}")
エラー内容
b = a + 3
TypeError: can only concatenate str (not "int") to str
どうするか? 私は直接CVした(嘘)。友人が書いた小さなプログラムを調べてみると、float() で入力値を処理すれば演算可能になることがわかった。こうなった。
a = input("Number is ")
b= float(a)
c = b + 3
print(f"Now your number is {c}")
出力内容
eg:
Number is 1
4.0
この処理を2組書いた。X座標とY座標の入力値にそれぞれ対応している:
# X座標を変換
x_position = float(your_x_position)
# Y座標を変換(+1は初期位置)
y_position = float(your_y_position)
これで、入力値は your_座標タイプ_position の浮動値から 座標タイプ_position の定値に変換され、後続の演算が可能になる。
初期座標の出力
元のコードではこう書いていた:
print(f"\nOriginal X position is {x_position}"
f"\nOriginal Y position is {y_position}."
f"\nOriginal position is ({x_position},{y_position}).")
ここで {座標タイプ_position} は私たちが入力した値だ。この段階では計算を使っていないので、{座標タイプ_position} を your_座標タイプ_position に置き換えても正常に表示される。しかし、バイト数を減らすために(暇だった)、{座標タイプ_position} の形式で値を参照することをお勧めする。
print() 内では、\n を書かなくても、直接改行することで改行できる。もちろん \n の書き方でも有効だ。
そうそう、print() で文字だけを出力する場合は、print() を使って出力できる:
print("これはテキストです")
出力内容
eg:
これはテキストです
もし値を参照したいなら、後ろに f(format、フォーマット設定)を付ける必要がある。書くとこうなる:
message = テキスト
print(f"これは{message}です")
出力内容
eg:
これはテキストです
もちろん、これは最も基本的な部分なので、これ以上説明する必要はない。ある本の第2章で説明されている問題だ。
if-elif-else文
まず元のコードを見てみよう:
# if-elif-else文
# slowを定義
if spead_random == 'slow':
# アルゴリズム
x_increment = x_position + 1
y_increment = y_position - 2
# mediumを定義
elif spead_random == 'medium':
# アルゴリズム
x_increment = x_position + 2
y_increment = y_position - 1
# fastを定義
elif spead_random == 'fast':
# アルゴリズム
x_increment = x_position + 3
y_increment = y_position + 3
# その他を定義。速度は最速とみなし、メーター表示上限に達する
else:
# アルゴリズム
x_increment = x_position + 4
y_increment = y_position + 6
ここでは計算が絡むので、前述の float() で変換してから計算する必要がある。
ここの数値は任意に書ける。最小値が負にならないようにしたが、実際にテストしてみると、負になっても問題ない。バグは発生しない……
ここで最も技術的なのは if-elif-else 文だ。技術というより、ロジックと言うべきだろう。
このコード全体の意味を翻訳してみよう。これ以上詳しく説明する必要はない。
# if-elif-else文 #
# slowを定義 #
if spead_random == 'slow': # spead_randomの値がslowなら、
# アルゴリズム #
x_increment = x_position + 1 # x_increment(新規変数)の値はx_positionの値+1
y_increment = y_position - 2 # y_increment(新規変数)の値はx_positionの値-2
# mediumを定義 #
elif spead_random == 'medium': # 上記以外でspead_randomの値がmediumなら、
# アルゴリズム #
x_increment = x_position + 2 # x_incrementの値はx_positionの値+2
y_increment = y_position - 1 # y_incrementの値はx_positionの値-1
# fastを定義 #
elif spead_random == 'fast': # 上記以外でspead_randomの値がfastなら、
# アルゴリズム #
x_increment = x_position + 3 # x_incrementの値はx_positionの値+3
y_increment = y_position + 3 # y_incrementの値はx_positionの値+3
# その他を定義。速度は最速とみなし、メーター表示上限に達する
else: # その他の場合
# アルゴリズム #
x_increment = x_position + 4 # x_incrementの値はx_positionの値+4
y_increment = y_position + 6 # y_incrementの値はx_positionの値+6
こういうことだ。ここで else は速度が veryfast の場合とみなしているが、論理的には slow、medium、fast 以外のすべての値がこのロジックを実行する。つまり、仮に現在の速度が veryslow でも、アルゴリズムは X+4、Y+6 になる。しかし、辞書の制約により、全部で4つのケースしか存在しないので、この問題は発生しない。
移動後の座標出力
print(f"New X position is {x_increment}"
f"\nNew Y position is {y_increment}"
f"\nNew position is ({x_increment,y_increment})")
ここで参照している座標値は、if-elif-else 処理で計算されたものだ。これ以上説明する必要はない。
内容紹介
まずコードを見てみよう:
# 内容紹介の定義
alien = {
'slow': 'Add 1 X position and reduce 2 Y position',
'medium': 'Add 2 X position and reduce 1 Y position',
'fast': 'Add 3 X position and add 3 Y position',
'veryfast': 'Add 4 X position and add 6 Y position'
}
print("\nIntroduction rules")
# 文字置換とタイプ総数の紹介
if len(alien) == 4:
# 文字置換
The_number = 'four'
# タイプ総数の紹介
print(f"There are {The_number} cases in total")
# その他の場合
else:
# 空値を出力
print("NULL")
# for文で出力
for spead_1, position in alien.items():
print(f"Spead: {spead_1}")
print(f"{position}"
ここには多くのものが含まれている。
まず alien = {……} の部分は辞書だ。最初の列は速度、2番目の列は紹介文だ。最初の列の値を key、2番目の列の値を value と呼ぶ。
各 key 値は1つの value 値に対応し、横方向に対応している。
その後の print() は最も単純な print文なので、説明は不要だ。
if から始まる部分もまたロジックだ:
# 文字置換とタイプ総数の紹介
if len(alien) == 4:
# 文字置換
The_number = 'four'
# タイプ総数の紹介
print(f"There are {The_number} cases in total")
# その他の場合
else:
# 空値を出力
print("NULL")
alien辞書のタイプ総数が4なら、新しい値 The_number = 'four' が生成され、There are four cases in total という文が出力される。
そうでなければ、単語 NULL を出力する。
これは分かりにくいかもしれないが、これがロジックだ。
最後に alien 辞書の値を出力する:
# for文で出力
for spead_1, position in alien.items():
print(f"Spead: {spead_1}")
print(f"{position}")
spead_1 は key に、position は value に対応する。key と value を読み取り、それぞれ spead_1、position に代入する。
最後に print で出力する。
for はループだ。値がすべて出力されていない場合、すべて出力されるまで繰り返し出力する。
終わり
さて、これで終わりだろうか? これはここ1年で私が書いた中で最も技術的な記事かもしれない……