1 準備
- GoogleColab.
にログインしておいてください。
- 「0713_辞書型.ipynb」という名前でノートブックを作成しておいてください。
- 今回はノートブックの提出はありません。
2 プログラミング学習について (再確認)
第01回講義でも伝えたように「ジュニアレベルのプログラマ(=ソフトウェアエンジニアのタマゴとして就職ができるレベル)に到達するために必要な学習時間は 1,000~2,000 時間」と言われています。またプログラミングの「超初心者」が「初心者」になるまでには 約250時間 の学習(経験)が必要とも言われています。
- 参考:プログラミングを始める前に知りたかったことトップ3@YouTube
( https://www.youtube.com/watch?v=8XwG81rHRhU )
つまり、毎週の2コマ (90分) の授業時間の取組み (=90分×30回=45時間) では圧倒的に学習時間が足りません。授業だけでは4年続けても200時間程度で やっと「脱・超初心者」になるか否か という程度です。当然ながら、そのような状況で進学や就職をしても、充実した時間は望めません。同期や後輩とのスキル差に起因して 不安感、焦燥感、劣等感、孤独感、自己否定感 に襲われる日々となるでしょう (現段階で既にそのような状況になっていませんか?!)。
ただ、このようなことは、特段に「プログラミング」という分野に限ったことではありません。毎週の2コマの体育 (音楽) の授業を受けているだけではスポーツ選手 (ミュージシャン) になれないこと、毎週6コマの英語の授業を受けているだけでは通訳や翻訳者になれないこと、と同じです。
では、どうすればいいのか。
授業という枠を超えてプログラミングを学ぶこと (親しむこと) が答えです (進路変更 という手段もありますが…) 。例えば、日々のスマホゲームや娯楽動画に費やす時間をプログラミング学習に変えてみてください。例えは、平日の1時間、休日の3時間をプログラミングに使えば、週あたり10時間が確保できます。1年間は約52週なので、1年では520時間の学習時間となります。
例えば、中学生や高校生が 部活動に費やしている時間 を考えれば、平日の1時間、休日の3時間という時間は、それほど無理なものではありません。また、将来的に1日8時間・40年間は関わらなければならない仕事に強く関わることを考えれば、十分に投資価値のある行動・時間だと言えます。
とはいえ、授業や塾、部活動のように強制力がない環境で「学び」を継続することは決して簡単なことではありません (それができるなら、ここではなくもう2ランク上位の学校に通っていたことでしょう) 。「学び」に充てる時間を確保する方法は「プログラミング関係のコンテストやセミナーに参加すること」あるいは「チームとして開発活動すること (=例えば総合課題実習や高専祭展示に向けた開発活動!!)」です。上手に機会や環境を利用して、自然にプログラミングを学ぶこと (親しむこと) ができるようにして欲しいと思います。
「どんな活動をすればよいか分からない」「何から学んだらよいのか分からない」「どうやって学んだらよいのか分からない」という場合は、皆さんから足を運んでくれれば、いつもでアドバイスします。
3 課題05 (自由課題)
現在までの プログラミング学習 (4カ月弱) の集大成 として「7月26日 (水) 23:55」を期限とする 課題05 に取り組んでくだい。
課題に対する直接的な評価は10点満点ですが、科目として成績評価するときには課題01~04よりも ウエイト (重み) は大きくします。この科目 (プログラミング1) は、知能情報コースとしては最重要科目ですので、十分な熱量を注いで計画的に取り組んでください。
- 過去課題を期限までに提出しない学生は、取り組み後はLINEで個別に完了報告をしてください。特に 課題01 と 課題04。
3.1 課題05の提出ファイルの作成手順
- ノートブックの雛形 (テンプレート) も用意したので、そちらもあわせて活用してください。
- GoogleColab.にアクセスして「課題05_40-WT.ipynb」のような名前のノートブックを作成してください。ここで「40-WT」の部分は「出席番号」「氏名の大文字イニシャル
(姓・名の順番)」としてください。
- 出席番号が1桁の学生は、ゼロ埋めしてください。
- ノートブックの共有設定を変更して「リンクを知っている全員」が「閲覧者」となるように設定してください。
3.2 注意事項
- 作品 (課題)
は、GoogleColab.上で実行可能なものとしてください。Colab.環境で
pipを使ってライブラリを追加することはOKです。 - 提出された課題は 本校の学生と教員、2I保護者に公開 します。公開可能な内容としてください。公序良俗や著作権などに反しなければ、テーマについて制限はありません。
- この課題には 最低でも10時間以上 を費やして取り組んでください (本科目は前期末試験がありませんので、試験勉強に相当する時間と熱量を投資してください)。
- テキストセルに プログラムの解説など
を記述してもらいます。
- 詳しくは雛形を参照してください。
input()によるユーザ入力は必要最低限として、置き換え可能なものは Colab.の Forms機能 を利用してください。- この授業で現在までに学習したことを最大限に取り込んだ内容を期待しています
(この授業で習っていない技術やライブラリを組み込むことも歓迎・推奨です)
。
- この授業で扱っているはずなのに、それが利活用されていないものは、評価が下がります。つまり「for構文 / 関数 / リスト / 辞書 / ライブラリ etc. を使って効率よく記述できるの処理なのに、それが使われていない」ものは評価は低いです。
- ICT分野の インターンシップ (4年生) や 就職活動などでは
ポートフォリオ (作品集)
が必要になってきます。そのための準備としても頑張って取り組んでください。
- 例: https://internship.team-lab.com/
- 例: https://www.jig.jp/news/topics/20230605_01
- 就活: ウェブエントリの項目例 「現在までに自分で作成してきたアプリやウェブサービスなどの成果物について記述してください。公開しているURLあれば記載してください。」
- ポートフォリオとしての質を考えた場合、「コメントの有無」や「内容」「可読性」「保守性」「再利用性」なども重要となります。
4 辞書 (dict)
Pythonにおける 辞書 (dict, Dictionary) は、他のプログラミング言語では「連想配列」や「ハッシュ」「ハッシュテーブル」と呼ばれているものです。
辞書は「キー (Key)」と「値 (Value)」の組み合わせを格納する組込み型のデータ構造で「キー (多くの場合は文字列) 」を使って「値(Value)」を高速に参照 (=取得) できる点に特徴があります。
例えば、辞書は次のように初期化して
(初期値を設定して)、その後、キーを使ってそれに対応する値を参照することができます。なお、辞書に使用する括弧は
[ ] ではなく { }
なので注意してください。
下記のプログラムを実行し、その結果を確認してください。
%reset -f
# 辞書の【初期化】 keyとvalueを : で区切って与える
player = {
'name': '勇者ヨシヒコ', # 各ペアはカンマで区切る
'level': 3,
'hp': 120,
'attack': 16,
'称号': '正義漢', # key には日本語も利用可能
'items': ['いざないの剣','たびびとのふく','やくそう'] # リストも格納可能
}
# 辞書の値【参照】[] に key を与えて value を参照
print( player['name'] ) # => 勇者ヨシヒコ'
# print( player[name] ) # => 実行時エラー。name という変数は存在しない最終行 (第15行目)
をアンコメントすると実行時エラーになることを確認してください。player[name]
では、name
という文字列をキーとするのではなく、name
という変数を探し、その変数に格納されている値をキーとして事象の値を参照する処理になってしまいます。プログラムのなかには
name という変数は存在しないので、当然ながら NameError
が発生します。print(player[name])
により意図する値を出力したいのなら、その文の前に
name='name' を記述しておく必要があります。
f文字列 の内部で「キー (文字列) を使って辞書の値の参照する場合」は、以下のように「シングルクォーテーション」と「ダブルクォーテーション」を使い分けしてください。
もしくは、次のようにすることも可能です。
- HPを表示するためのコードを
dict01.pyに追加して、その結果を確認せよ。 - ダブルクォーテーションだけで記述した
print(f"HP = {player["hp"]}")のような文を実行するとどうなるか。結果について推測したうえで、実際にコードを実行して検証せよ。 print(player['mp'])のように存在しないキーを与えるとどうなるか。結果について推測したうえで、実際にコードを実行して検証せよ。print(player)を追記し、その実行結果を確認せよ。
4.1 演習①
次のような 期待する出力 が得られるように
dict01.py の第13行目以降を書き換えよ。
期待する出力
勇者ヨシヒコ (正義漢)
- Lv : 3
- HP : 120
- 持ち物 : いざないの剣, たびびとのふく, やくそう
ヒント
- 「持ち物」の一覧を出力するためには「for文」か「アンパック」を使用します。アンパックは
第10回講義
で学習済みです。
- for文を利用する場合のヒント :
for item in player['items'] : - アンパックを利用する場合のヒント :
print( *player['items'], sep=', ' )
- for文を利用する場合のヒント :
4.2 辞書の値 (value) の更新、キーと値のペアの追加
次のプログラムを実行して、その結果を確認してください。また、その実行結果とプログラムを照らし合わせて、辞書型の特性について理解してください (必要に応じてコードの書き換えを行ない、その実行結果がどう変化するかを実証的に確認してください) 。
%reset -f
# キーとして 'x' と 'y' を持った辞書の値を整形表示する関数を定義
def print_point(p):
assert type(p) == dict # 辞書型(dict)であることを確認
print(f"({p['x']:.1f}, {p['y']:.1f})")
p1 = {} # 空の辞書。「p1=dict()」でも同じ処理になる
p1['x'] = 10 # key:'x' value:10 の追加
p1['y'] = 20
p2 = {'y':100, 'x':50} # キーは順不同で可
p2['y'] = 40 # 書き換え(上書き)
print_point(p1)
print_point(p2)上記のプログラムの解読を通して、以下のことが分かると思います。
- 関数の引数として「辞書型」を与えることもできる。
type(xxx) == dictによって、引数として受け取ったxxxが辞書型かどうかを確認できる。- 変数
yyyを「空のリスト」として初期化するにはyyy=[]あるいはyyy=list()という文を記述したのに対して、「空の辞書」として初期化するにはxxx={}あるいはxxx=dict()と記述する。 - 関数を利用することでプログラムをすっきりと記述できる。
4.3 辞書が特定のキーを持つかチェックする方法
次のようにして、辞書が「特定のキーを持っているか」を判定することができます。プログラムを実行して、その結果を確認してください。
%reset -f
items = {
'やくそう':8,
'どくけしそう':2,
'ぬののふく':1
}
for x in ['やくそう', 'きえさりそう'] : # ループ変数 x は「やくそう」→「きえさりそう」
print(f'勇者ヨシヒコは「{x}」を',end='')
if x in items.keys() : # 辞書型にキー「x」が含まれるか?
print(f'{items[x]}個もっている。')
else :
print('もっていない。')4.4 演習② 辞書が持つ「キー」と「値」の全列挙したい。
「辞書が持っているキーと値を全列挙する方法」について、ウェブ検索やChatGPTなどを利用して調べて理解し、実際に検証せよ (処理の目的が明確なとき、それを自己解決するための演習) 。
具体的には、次のように初期化された辞書から 期待する結果 を得るようなコードを記述せよ。
%reset -f
# この関数を書き換える
def print_dict(d):
assert type(d) == dict
print('...')
character_status = {
'name': 'Hiro',
'level': 10,
'hp': 100,
'mp': 30,
'attack': 15,
'defense': 10,
'experience': 0,
}
print_dict(character_status)期待する結果
name : Hiro
level : 10
hp : 100
mp : 30
attack : 15
defense : 10
experience : 0
ヒント f文字列の書式指定 (左寄せの空白埋め、右寄せの空白埋め) を上手に活用してください。
5 リストの扱いに関する補足① : for構文との組み合わせ
以前に簡単に触れていますが、for構文を使ってリストの全要素を参照するような処理
(loop-01a.py) は、loop-01b.py
のようにスマートに記述することができます。
%reset -f
items = ['やくそう', 'どくけしそう', 'ひのきのぼう', 'たびびとのふく']
# print(len(items)) # => 4
for i in range(len(items)):
print(items[i])上記では、ループ変数 c には数値ではなく、リスト
arr の要素 (つまり「やくそう」「どくけしそう」…)
が順番に格納されながら繰返し処理されます。
Python では基本的に loop01b.py
のような記述が推奨されます (
loop01a.pyの記述は非推奨です )。
5.1 enumlate
リストと繰返しを組み合わせる場合、以下のように「その要素は何番目か」もあわせて出力したい場合があります。
1.やくそう
2.どくけしそう
3.ひのきのぼう
4.たびびとのふく
このような場合は enumerate 関数
(イニューマレイト関数) を利用して次のように記述できます。enumerate
は「列挙する」という意味になります。実際に実行して、その結果について確認してください。
%reset -f
items = ['やくそう', 'どくけしそう', 'ひのきのぼう', 'たびびとのふく']
for i,c in enumerate(items): # ここに注目!
print(f'{i+1}. {c}')さらに、enumerate
関数は、第2引数に初期値を設定可能で、以下のように記述することもできます。
%reset -f
items = ['やくそう', 'どくけしそう', 'ひのきのぼう', 'たびびとのふく']
for i,c in enumerate(items,1): # i の初期値を 1 に設定
print(f'{i}. {c}')enumerate
関数は、利用頻度が高いので覚えておくようにしてください
(
自分は使う予定がなくても、他人のプログラムを読む場面で出現するので、enumerateの挙動は十分に理解しておいてください
)。
5.2 演習③
下記の「期待する出力」が得られるように、次のプログラムを変更・追記し、その実行結果を確認せよ。
- ここでは
range関数とlen関数の組み合わせではなく、enumerate関数の利用を意図しています。 - ここでは
enumerateの第2引数に、適切な初期値を設定することを期待しています。 - 数値のゼロ埋め方法を忘れてしまった場合は「Python f文字列 書式指定 ゼロ埋め」などで検索してください。
%reset -f
codename = ['Coffee Lake Refresh','Comet Lake',
'Rocket Lake','Alder Lake','Raptor Lake','Meteor Lake']期待する出力
■ intel デスクトップPC用Coreプロセッサのコードネーム
第09世代 Coffee Lake Refresh
第10世代 Comet Lake
第11世代 Rocket Lake
第12世代 Alder Lake
第13世代 Raptor Lake
第14世代 Meteor Lake
6 リストの扱いに関する補足② : アンパック
こちらも以前に簡単に触れていますが unpack-01a.py
は unpack-01b.py
のようにスマートに記述することができます。
どちらのプログラムも同じ出力が得られることを確認してください。
Pythonにおける アンパック または
アンパッキング
とは、リスト内の要素を個々の変数に分割して関数の引数に与える手法を指します。アンパックするためには、変数名の先頭に
* を与えます。
unpack-01b.pyの第03行目をprint(ip_addr,sep='.')のようにした場合 (アスタリスク*を付けていない場合) 、どのような出力を得るか。結果について推測したうえで、実際にコードを実行して確認せよ。
7 リストの扱いに関する補足③ : スライス
Pythonのリストでは スライス
という操作により、指定の部分範囲を取得することができます。スライスは
[] の内部で、コロン :
を使って、[開始値:終了値]
のように範囲を表現します。
例えば arr[2:6] とした場合、次の図のようにリスト
arr の「2番目から5番目
(=6-1番目)までの範囲」の部分取得ができます。また、開始値を省略すると「リストの先頭から」となり、終了値を省略すると「リストの末尾まで」の意味になります。
スライスしたものは、関数の引数などに利用可能です。例えば、次のプログラムは、合計を求める組み込み関数
sum()
の引数に「スライスしたリスト」を与えています。実際に実行して、その結果について確認してください。
%reset -f
arr = [10,20,30,40,50,60,70,80]
s1 = sum(arr)
print(f's1 = {s1}') # sum
s2 = sum(arr[:3]) # 0番目から2番目(3番目を含まない)までの合計
s3 = sum(arr[3:]) # 3番目から最後までの合計
s4 = sum(arr[2:6]) # 2番目から5番目までの合計
print(f's2={s2}, s3={s3}, s4={s4}') print(arr[:3])、print(arr[3:])、print(arr[2:6])を追記すると、その出力はどのようになるか。結果について推測したうえで、実際にコードを実行して確認せよ。arr[:]とすると、どのようになるか (何らかのスライス処理がされるのか、それとも文法エラーや実行エラーとなるのか、以下同様) 。結果について推測したうえで、実際にコードを実行して確認せよ。arr[]とすると、どのようになるか。arr[:100]とすると、どのようになるか。arr[3:3]とすると、どのようになるか。arr[5:3]とすると、どのようになるか。arr[-1:]やarr[-2:]とすると、どのようになるか。arr[:-1]やarr[:-2]とすると、どのようになるか。arr[2:6:2]とすると、どのようになるか。
8 文字列に対する1文字参照やスライス処理
「文字列」は「リスト」ではありませんが、「リスト」と同じように
[] を使って要素 (=1文字)
を参照したり、スライスで部分文字列を取得することができます。半角文字、全角文字、絵文字を含めてPythonでは適切に「1文字」を切り分けることができます。
例えば、変数 item
に「やくそう」という文字列が格納されている場合、name[0]
で「や」、name[0:2] で「やく」、name[-1]
で「う」を参照することができます。
ただし、あくまで「リストと同じように操作できる」だけで、文字列はリストではないので
name[0]='ど' のような操作はできません
(薬草を毒草に変えることはできません)。書き換えようとすると、どのようなエラーになるのか実際にコードを書いて確認してください。
以下は、トランプのカードを「スート (♠♦♥♣) 」と「ランク
(A234…JQK) 」の 2文字からなる文字列
として表現し、さらに []
を使ってスートとランクを個別参照している例です。実際に実行して結果を確認し、プログラムを解読・理解してください。
%reset -f
import random as r
cards = ['♠A', '♠2', '♥3', '♥4','♣Q', '♣K']
print(f'山札は {cards}')
print()
card = r.choice(cards)
print(f'山札から1枚ひいたカードは「{card}」')
print(f' スートは「{card[0]}」、ランクは「{card[1]}」でした。')
print()
cards.remove(card)
print(f'よって、現在の山札は {cards}')また、文字列は、次のようにfor文にも使うことができます。
%reset -f
string = '微分積分1で爆死'
print(' _人人_')
for c in string : # for in (文字列)
print(f'_) {c} (_')
print(' ^Y^Y^^')9 GoogleColab.の出力セルのクリア
Jupyter環境 (Google Colab.) における出力セルは
IPython.display.clear_output()
によって内容をクリア (消去)
することができます。
次のプログラムを実行して、その結果について確認してください。
%reset -f
import time
import IPython.display # 要インポート
for i in range(5,0,-1):
print(f'{i}...')
time.sleep(1) # Arduino の wait に相当。単位は「秒」
IPython.display.clear_output() # 出力セルの消去
print('🚀')
for i in range(3):
time.sleep(0.5)
print('⚡')9.1 応用例
自由課題のヒントにしてください。
%reset -f
import time
import random as r
import IPython.display
n=9 # 9回(イニング)までのゲーム委
G = [-1]*n # スコアの初期化
H = [-1]*n
wait_time = 2 # [Sec]
# チームのスコア #########################
def print_team_score(name,score):
print(f'{name}|',end='')
for i in range(n):
if score[i] != -1:
print(f'{score[i]:>2}|',end='')
else :
print(' |',end='')
print(f'{sum(score[:t]):>2}|')
# スコアボード全体の出力 #################
def print_score_board():
IPython.display.clear_output() # 出力をクリア
print('-+'+'--+'*(n+1))
print(' |',end='')
for i in range(1,n+1):
print(f'{i:>2}|',end='')
print('計|')
print('-+'+'--+'*(n+1))
print_team_score('G',G)
print_team_score('H',H)
print('-+'+'--+'*(n+1))
# メイン処理 #############################
for t in range(n):
# 先攻「G」の攻撃回
G[t] = r.choices([0,1,2,3],[5,3,1,1])[0]
print_score_board()
time.sleep(wait_time)
# 後攻「H」の攻撃回
H[t] = r.choices([0,1,2,3],[4,3,2,1])[0]
print_score_board()
time.sleep(wait_time)
if sum(H) > sum(G):
print('😄😄😄😄😄')
else :
print('😱😱😱😱😱')10 条件式の工夫
ユーザーから入力された文字列が 犬 または
いぬ または イヌ のとき、「ワン
! 」という文字列を出力する処理を考えます。
この処理 (条件分岐)
を素直に記述すると次のようになります。or で
OR条件 を表現しています。
%reset -f
animal = input('動物名を入力してください : ')
if animal == '犬' or animal == 'いぬ' or animal == 'イヌ' :
print('ワン!')
else :
print('・・・')これに対して、(初心者において) よくある間違いとして、次の第03行目のように不適切な条件式を記述してしまうことがあります。
%reset -f
animal = input('動物名を入力してください : ')
if animal == '犬' or 'いぬ' or 'イヌ' : # 不適切な条件式
print('ワン!')
else :
print('・・・')上記の条件式 animal == '犬' or 'いぬ' or 'イヌ'
では「ネコ」を入力した場合でも「ワン !
」が出力されてしまいます。実際に実行して結果を確認してみてください。この理由は、if文の
条件式を書く位置
には、単なる「数値」や「文字列」も記述可能で、その場合、特定の値以外では条件が「真」として判定されるためです。
実際に確認してみます。以下のプログラムを実行して、その結果を確認してみてください。以下に示す例では、すべての条件が「真」として判定され、処理
(print()) が実行されています。
%reset -f
if 'いぬ' :
print('1')
if 109 :
print('2')
if -20 :
print('3')
if 3.14 :
print('4')
if ['A','B','C'] :
print('5')
if [0] :
print('6')
# 次の XXX の部分を自分で思いつく値に変更して実行してみてください。
# if XXXX :
# print('7')一方で、条件が「偽」として判定されるのは、次のように限られた値だけになります。実際に、その実行結果を確認してみてください。
%reset -f
if 0 :
print('1')
if 0.0 :
print('2')
if [] :
print('3')
if None:
print('4')
if False :
print('5')
if '' :
print('6')以上踏まえ、条件式に
animal == '犬' or 'いぬ' or 'イヌ'
を使用すると、animal
の内容に関係なく、いぬ
が「真」となってしまいます。
よって、animal
が「犬」「いぬ」「イヌ」のいずれかのときだけ「真」とするためには、最初に示したように
animal == '犬' or animal == 'いぬ' or animal == 'イヌ'
と記述するか、第08回
で教えたように次のようにする必要があります。
%reset -f
animal = input('動物名を入力してください : ')
if animal in ['犬','いぬ','イヌ'] : # リスト ['犬','いぬ','イヌ'] に anmial は含まれるか?
print('ワン!')
else :
print('・・・')11 プログラマの心得「前向きな怠惰の思想」
ICTエンジニア (特にプログラマやSE) には「面倒な作業はラクして簡単に瞬殺で済ませようとする「前向きな怠惰」の姿勢や信念」が必要です。これは、言い換えれば「めんどくさいことをしないためならいかなる努力も惜しまない姿勢や信念」が必要とも言えます。
「関数化できる処理を、関数定義しない」、「変数を使わずに、数値リテラルを使用する」、「同じような処理をfor文を利用せずに記述する」といった姿勢では、プログラミングスキルは一向に伸びませんし、コーディングはいつまでも面倒なままで、楽にも楽しくもなりません。
11.1 具体的な事例
一般に、自由課題では「トランプ」を使ったゲームをテーマにプログラミングに取り組む学生が多いです。
例えば、52枚のカードの初期化について、最も愚直な方法は次のようなものです。
%reset -f
# プログラマ的な発想・姿勢に基づかない初期化
cards = ['♠A', '♠2', '♠3', '♠4', '♠5', '♠6', '♠7', '♠8', '♠9', '♠J', '♠Q', '♠K',
'♦A', '♦2', '♦3', '♦4', '♦5', '♦6', '♦7', '♦8', '♦9', '♦J', '♦Q', '♦K',
'♥A', '♥2', '♥3', '♥4', '♥5', '♥6', '♥7', '♥8', '♥9', '♥J', '♥Q', '♥K',
'♣A', '♣2', '♣3', '♣4', '♣5', '♣6', '♣7', '♣8', '♣9', '♣J', '♣Q', '♣K']
print(cards)上記のコードを記述に要する時間は、せいぜい3分程度ですが、この3分の面倒を避けるためにプログラムを、考えたり、調べたり、試行錯誤したりすることに1時間、2時間を費やすことができるか が、プログラミング思考になれているか、否かの指標になります。
このような「めんどくさいことをしないためならいかなる努力も惜しまない」ということができれば、上記
card_init_01.py
は、次のように書けることに気付き、その内容の理解に至ると思います。これにより、このカードの初期化に相当するタスクからは
永遠に解放される
という恩恵を得ることができます。
%reset -f
# プログラマ的な発想・姿勢に基づく初期化
suit = ['♠','♥','♦','♣']
rank = ['A','2','3','4','5','6','7','8','9','J','Q','K']
cards = [None]*(len(suit)*len(rank))
t = 0
for s in suit:
for n in rank :
cards[t]=f'{s}{n}'
t+=1
print(f'cards={cards}')さらに、時間を費やせば、次のようなプログラムにできるというところに到達すると思います。
%reset -f
suit = list('♠♥♦♣')
rank = list('A23456789JQK')
cards = [None]*(len(suit)*len(rank))
t = 0
for s in suit:
for n in rank :
cards[t]=f'{s}{n}'
t+=1
print(f'cards={cards}')さらに、時間を費やせば、次のようなプログラムにできるというところに到達すると思います (ラムダ式やmapなどを含んだ下記のコードを理解するためには、数時間~十数時間を必要とします、現時点では以下の詳細について必ずしも理解する必要はありません) 。
itertools.product() 関数は「情報2」の第12回講義
(p.198)
で学んだ集合演算の「直積」に相当する処理です。
%reset -f
import itertools
suit = list('♠♥♦♣')
rank = list('A23456789JQK')
cards = list(map( lambda x: x[0]+x[1],itertools.product(suit,rank)))
print(f'cards={cards}')11.2 演習④
次に示すプログラムの Step1
のトランプの初期化を「全52枚」に書き換え、さらに
judge()
関数を完成させよ。ここでカードは、ランクが大きいほうが強いものとする
(ただし、例外的にキングよりもエースが強いものとする)。
また、ランクが同じ場合は、スペード、ハート、ダイヤ、クローバの順で強いものとする (スートではスペードが最強) 。
%reset -f
import random as r
# 引数で受け取った札束の状態を確認する関数
def print_cards (x) :
assert type(x) is list
print(f'山札は |',end='')
print(*x,sep='|',end='') # アンパック
print(f'| の {len(x)}枚 です。')
# c1 が強い場合は「True」, c2が強い場合は「False」を返す関数
def judge(c1,c2):
assert type(c1) is str
assert type(c2) is str
assert c1 != c2
return True
## Step1 ####
print(f'トランプの初期化')
cards = ['♠A', '♠2', '♥3', '♥4','♣Q', '♣K']
print_cards(cards)
## Step2 ####
print()
r.shuffle(cards)
print(f'山札をシャッフルしました。')
print_cards(cards)
## Step3 ####
print()
p1 = cards.pop()
print(f'P1が山札から 1枚ひいたカードは |{p1}| でした。 ',end='')
print(f'このカードのスートは「{p1[0]}」、ランクは「{p1[1]}」です。')
print_cards(cards)
## Step4 ####
print()
p2 = cards.pop()
print(f'P2が山札から 1枚ひいたカードは |{p2}| でした。 ',end='')
print(f'このカードのスートは「{p2[0]}」、ランクは「{p2[1]}」です。')
print_cards(cards)
## Step5 ####
print()
print('この勝負、P1の「',end='')
if judge(p1,p2) : # 自作関数 judge の呼び出し
print('勝ち',end='')
else :
print('負け',end='')
print('」です。')(中級者向け) 上記プログラムの Step3 と Step4 は、ほぼ同じ処理といえる。この処理を関数を使ってまとめよ。
ヒント:draw_card
という関数で、「山札」と「名前(P1やP2)」を与え、引いたカードを返すような関数
12 ライブラリのインポートに関する補足
自由課題に取り組む際、様々なウェブを参照すると思います。ウェブに掲載されているサンプルプログラムでは
from math import sin のように from
を含んだ インポートの表記
を見かけると思います。
from
を使用する場合と、使用しない場合では、以下のように、ライブラリに含まれる
関数の呼び出し が、若干変わってきます。
%reset -f
# form を使用したimport文
from math import sin,cos
x = sin(0.25)**2 + cos(0.25)**2 # math.は不要
print(x)%reset -f
# form を使用しないimport文
import math
x = math.sin(0.25)**2 + math.cos(0.25)**2 # math.が必要
print(x)import01.pyでmath.sin(0.25)とすると、どのようになるか。結果について推測したうえで、実際にコードを実行して確認せよ。import01.pyで \(\sin^{2}(\theta)+\cos^{2}(\theta)+\tan^{2}(\theta)\) を計算したい。どのようにコードを書き換えればよいか。実際にコードを書き換え、その結果について確認せよ。