#author("2021-10-24T11:43:34+09:00","default:takataka","takataka")
[[AProg/2021/ex05]]
#author("2021-11-04T08:51:42+09:00","default:takataka","takataka")
* 応用プログラミング及び実習 2021年度 ex06 [#xa9b83a6]

* 応用プログラミング及び実習 2021年度 ex05 [#xa9b83a6]

//&color(red){''工事中''};

#contentsx

**注意 [#ib719427]


notebook のセルを実行していると,たまにセルの番号のところが [*] となったままで反応が返ってこなくなるときがあります.
ありがちな状況と対処法を書いときます
+ 単に処理に時間がかかってるだけ → 待てばいい
+ input( ) が入力待ってる → 入力欄になんか入力して Enter
+ いつまで待ってもだめ → ウィンドウ上部の「■」ボタンを押して,そのセルの実行を強制的に停止させる



** ex05A [#kadaiA]
** ex06A [#kadaiA]

[[ex05kadaiA.ipynb>https://github.com/takatakamanbou/AProg/blob/main/ex05kadaiA.ipynb]]
*** Step1 [#j82f0773]

+ 上記のリンク先から notebook ファイルをダウンロードして開く
-- notebook の扱い方を忘れたひとは [[こちら>../Setup#part2]] 
+ そこに記された指示にしたがって notebook を編集・実行して保存
+ その notebook ファイルを以下の提出場所へ提出
授業で作成したファイル ex06constants.txt を読み込んでディクショナリに格納するコードを書こう.
以下の内容の ex06constants.py というファイルを作成し,それを修正しましょう.
最後の行の修正も忘れずに.

''注意'':  文章をきちんと読んでもらえばわかりますが, P2 のところに書いてある「文字列を入力したら,単語内の文字をひっくり返して出力してくれるようにする問題を考えます」というのは,P2の最終目標ではなく,この課題と次の課題(ex05B)全体での目標です.
P2 で(またはP4までで)「文字列を入力したら,単語内の文字をひっくり返して出力してくれる」処理を完成させろと言っているわけではありません.
#pre{{
# 空のディクショナリを作る
constants = {}

# ファイルを読み込む → 各行を分解 → 1つ目をキー,2列目を値(浮動小数点数値)としてディクショナリに登録
with open('ex06constants.txt', 'r', encoding='utf-8') as file:

提出場所: [[この科目の Moodle コース>https://www-tlab.math.ryukoku.ac.jp/moodle/course/view.php?id=5]] の「ex05課題A」
# キーの一覧を使ってループし,ディクショナリの内容を表示.p.194参照
for k in constants.keys():
    print(k)   # キー k の値と,そのキーに対応した数値を小数点以下2桁まで表示させるように修正しよう

** ex05B [#kadaiB]
# 以下を修正して自分の学籍番号と氏名を出力させるようにしといてください
print('A01055 ほげほげお')
}}


ex05A のつづきで,文字列を入力したら単語内の文字をひっくり返して出力してくれるプログラムを作りましょう.
名前は ex05reverse.py としてください(''名前間違えないように'').
*** Step2 [#a0983c64]

(1) 以下の内容のファイル ex06readscore.py を作りましょう

*** step1 [#u5a410d8]
#pre{{
##### このファイルの中身は変更する必要ないはずです #####

### 関数 readScore() の定義
#
def readScore(fn):

次のような関数 reverseSentence() の定義を書いて,動作確認しよう.
- 関数名は reverseSentence
- 引数は1つ(文字列),戻り値は文字列
- 実行例(1)
 S1 = "    ぼく    ほげお       \tほげ ほげ〜\n"
 R1 = reverseSentence(S1)
 print(R1)
 くぼ おげほ げほ 〜げほ
- 実行例(2)
 print(reverseSentence("sihT si a .nep"))
 This is a pen.
- ヒント:  部分文字列ごとにひっくりがえす.「ex05 Notebook その3」思い出そう.
    idL = []     # 空のリストを作る.ID用
    scoreL = []  # 空のリストを作る.スコア用

    with open(fn, 'r', encoding='utf-8') as f:  # ファイルを読み込みモードで開く
        for line in f:  # ファイルから1行ずつ読み込んでループ
            i, s = line.split()  # 空白区切りで分割.1つ目を i に,残り(2つ目)を s に 
            idL.append(i)           # idL の末尾に i を追加
            scoreL.append(float(s)) # scoreL の末尾に float(s) を追加

*** step2 [#l0f62b73]
    return idL, scoreL

プログラムの末尾に,次のコードを挿入して実行しよう.読み込むファイルはこちら: [[ex05msg.txt>AProg:ex05msg.txt]]

# 授業で説明していないが,以下の if の条件式は,このプログラムが他から import された時は
# False, 直接起動されたときは True になる.したがって,if ブロックの中は後者の場合のみ
# 実行され,他のプログラムから import されたときは無視される
if __name__ == '__main__':

    # 動作確認
    x, y = readScore('gamescores.txt')
    print(len(x), len(y))
}}

(2) 実行して動作確認しましょう.このプログラムは gamescores.txt を読み込みます.同じフォルダ/ディレクトリ内に存在しないといけません.見つからないひとはこちらへ: [[AProg/2021/ex03#kadaiB]]

(3) [[AProg/2021/ex03#kadaiB]] で作った ex03score.py をコピーして,ex06score.py というファイルを作り,次のことをやりましょう.
- 関数 readScore の定義を削除する
- 先頭に, ex06readscore.py を import する文を書く
 import ex06readscore

(4) 上記のことをやっただけでは, 関数 readScore を呼び出してる行でエラーになります.ここを修正しましょう.
ex06readscore.py で定義されている関数 readScore を呼び出すようにしてください.
ヒント: ''モジュール名.関数名'' で,この場合のモジュール名は...(モジュールって何?ってひとは,[[第3回授業>AProg/2021#ex03]] のその4のnotebookと動画で復習してください).

(5) 動作確認しましょう.ex03Bが満点でなかったひとは,指摘された問題点の修正も忘れずに.

(6) ex06score.py の最後に,ex06constants.py と同様に自分の学籍番号氏名を出力する行を追加しといてください.


***提出法 [#n5b828ce]

上記の課題で作ったプログラムのうち,以下の二つを提出してください.ファイル名を間違えないよう注意.

- ex06constants.py
- ex06score.py


提出場所: [[この科目の Moodle コース>https://www-tlab.math.ryukoku.ac.jp/moodle/course/view.php?id=5]] の「ex06課題A」





** ex06B [#kadaiB]

''顔検出しよう''

*** step1 [#ece4e74d]

(0) この課題では,OpenCV という画像処理・コンピュータビジョンのためのライブラリを利用します.
以下のようにして,追加でインストールしましょう.
#pre{{
fn = "ex05msg.txt"
with open(fn, "r", encoding="utf-8") as f:  # ファイル名 fn のファイルを読み込みモードで開く
    for line in f:        # ファイルから1行ずつ読み込んでループ
        print(line)       # そのまま表示
pip3  install  opencv-python
}}

上記の for 文の中を修正して,読み込んだファイルの各行に reverseSentence() を適用した結果を出力するようにしてください.

//&size(8){なんかのりでほげおに新たな設定が爆誕...};
(1) 右のリンク先のファイルをこの授業のためのディレクトリに保存しましょう: [[facedetect.py>https://github.com/takatakamanbou/AProg/blob/main/facedetect.py]]  (保存法は .ipynb のファイルと同じです)

*** step3 [#p8f8df2e]
(2)  正しい場所に保存したら,実行しましょう.
ネットワークからファイルをダウンロードするはずです.「終了」と出てたらok

プログラムの末尾に次のようなコードを追加して動作確認しましょう(姓名や学籍番号は自分ので).
確認できたら,提出しましょう.
(3) 複数人の顔が真正面を向いて写っている画像を適当に探して,同じ場所に保存しましょう.

(4) 以下を ex06face.py という名前で保存しましょう.
#pre{{
myID = "A01055   ほげ   ほげお"   #  学籍番号,姓,名を空白区切りで
print(reverseSentence(reverseSentence(myID)))
import cv2
import facedetect

# 画像を読み込む
image = cv2.imread( ここに画像ファイル名を指定 )
print("画像サイズ: {0[1]} x {0[0]}".format(image.shape))

# 顔検出を実行
posizeList = facedetect.facedetect(image)

# 顔の位置と大きさを表示
for i, posize in enumerate(posizeList):
    print("{0}人目: {1}".format(i+1, posize))

# 画像を書き出す
cv2.imwrite("hoge.png", image)

# 以下を修正して自分の学籍番号と氏名を出力させるようにしといてください
print('A01055 ほげほげお')
}}

(5) 「ここに画像ファイル名を指定」のところを書き換えて,実行してみましょう.
- 上記の画像読み込み関数 cv2.imread は,JPEG, PNG, GIF, BMP 等いろいろな画像形式を扱えます.
- 実行すると hoge.png という画像ファイルができますが,現時点では入力に指定したものと中身は同じです.
- うまく検出できたら,検出された顔の位置などを表す4つ一組の数値が,それぞれの人物ごとに表示されるはずです.
-- あまり大きい顔/小さい顔は検出できないかもしれません
-- 顔の向きによってもうまく検出できないことがあります.
- 4つの数値が何を表しているか考えましょう.コンピュータが扱う画像の世界では,画像の左上が原点で,右に向かってx軸,下に向かってy軸をとった座標系が使われることが多いです.このプログラムで得られる座標もそうなってます.

提出場所: [[この科目の Moodle コース>https://www-tlab.math.ryukoku.ac.jp/moodle/course/view.php?id=5]] の「ex05課題B」

**ex05S (omake)  [#kadaiS]
*** step2 [#n2a7fcd0]

//&color(#ff0000){工事中}; 

&color(red){''これはおまけ課題です.やらなくても減点はありません.やったら棒茄子?''};
ex06face.py を修正して,検出した顔に四角い枠をつけた画像を hoge.png として出力するようにしよう.

- 以下の説明にしたがって作ったプログラムのファイルを提出してください
- 期限と提出場所: 1104木の授業終了までに Teams チャットで takataka へ
枠線を描くには,OpenCV の cv2.rectangle() 関数を使いましょう.
引数 color および thickness を指定して,緑色で線の太さ 3 にしてください.

参考: https://note.nkmk.me/python-opencv-draw-function/

''画像処理してみよう''

&ref(http://www-tlab.math.ryukoku.ac.jp/~takataka/course/AProg/blackuni3.png,nolink);


*** 提出法 [#p8f8df2e]

提出場所: [[この科目の Moodle コース>https://www-tlab.math.ryukoku.ac.jp/moodle/course/view.php?id=5]] の「ex06課題B」

- facedetect.py の提出は必要ありません
- ファイル名間違えないように,最後に自分の学籍番号氏名を出力するように
**ex06C [#kadaiC]

//&color(#ff0000){工事中};

''県庁所在地クイズを作ろう''


+ [[ex06kencho.txt>AProg:ex06kencho.txt]] をいつもの場所に保存して,エディタで内容を確認しなさい.
+ このファイルを読み込んで,次のように「県庁所在地クイズ」ができるプログラムを作ろう(以下の実行例の「★」以降はコメント).プログラムのファイル名は ex06kencho.py としてください.
#pre{{
何問やる? 50      ★ 「50」はキーボードからの入力.1以上47以下の整数でなければ入力やり直しになる
何問やる? 0
何問やる? 5
1問目: 和歌山県の県庁所在地は? 和歌山市   ★ 「和歌山市」と入力して Enter,以下同様
正解!
2問目: 熊本県の県庁所在地は? くまもん
ちゃうで
3問目: 長野県の県庁所在地は? 長野市
正解!
4問目: 秋田県の県庁所在地は? 秋田犬
ちゃうで
5問目: 岡山県の県庁所在地は? 岡山市
正解!
5問中3問正解やったで

A01055 ほげほげお
}}
+ ディクショナリ使うのが素直な方針でしょう.いきなり全体を考えるのは大変なので,次の段階分けを参考にしたらよいでしょう.

- Step1:  ファイルを読み込んでディクショナリに登録するだけのプログラム.改行文字の除去を忘れずに.
- Step2: ディクショナリのキーを格納したリストを作る.
 keyList = list(hoge.keys())   # この例では hoge がディクショナリ 
- Step3: とりあえず札幌からの順番のままで最初の5道県でクイズができる(正解不正解を判定して出力する)ものにする
- Step4: キーのリストをランダムにならべかえる(random.shuffleがよいかも)
- Step5: 細かいところをちゃんとする.問題数決められるように,最後に正解数出すように,etc.
>
&color(red){''読み込むファイルに記載されている情報が増減してもプログラムを書き換えないで済むようなものにすること.''};
<


提出場所: [[この科目の Moodle コース>https://www-tlab.math.ryukoku.ac.jp/moodle/course/view.php?id=5]] の「ex06課題C」
- ファイル名間違えないように,最後に自分の学籍番号氏名を出力するように
**ex06S (omake)  [#kadaiS]

//&color(#ff0000){工事中}; 

&color(red){''これはおまけ課題です.やらなくても減点はありません.やったら棒茄子?''};

+ 以下では OpenCV という,''コンピュータビジョン''(コンピュータに人間のような視覚をもたせる方法を考える研究開発分野)のためのライブラリを利用します.次のようにしてインストールしてください(macのひとはpip3).
 pip install  opencv-python
+ 上記の画像を手元に保存しなさい.
+ 次のプログラムを実行しなさい.ファイル名は ex05S.py としよう.
''三目並べ = oxゲーム = Tic-Tac-Toe を作ろう''


***step1 [#u85846b7]

+ 次の内容のプログラム ex06sammoku.py を(この通りに)作って実行しなさい.
#pre{{
### AProg2021-ex06  三目並べ = oxゲーム = Tic-Tac-Toe

import cv2           # OpenCV モジュール
# 盤面の状態を表すディクショナリ
mark = {0:" ", 1:"o", -1:"x"}

# 画像の読み込み
img = cv2.imread('blackuni3.png')
if img is None:
    print('File Not Found')
print(img.shape)  # 正しく読み込めたら, img は NumPy の3次元配列になる(カラーの場合)

# 画像を表示
cv2.imshow("hoge", img)
cv2.waitKey(0)   # 画像を表示したウィンドウ内で何かキーが押されるまで待つ
### リストのリストで表された盤面情報を o,x で表示する
#
def printBoard(board):

# 画像を書き込み
cv2.imwrite("hoge.png", img)
    print(board)   # 実行例のように縦横に o や x が並ぶようにしよう


# printBoard の動作確認
board = [[0, 1, -1], [1, 0, -1], [0, 0, 0]]
printBoard(board)
}}
+ 上記の画像とは別の画像を使って実行してみよう.
+ 上記を書き換えて遊ぼう.ただし,次の処理を必ず行うこと.情報収集は「opencv python  ほげ」でウェブ検索したりがよいだろう.
-- 左右and/or上下反転
-- 色反転(画素値を反転させる)
-- ググると bitwise_notを使う方法が出てくるでしょう.それを使う場合,それでなぜ画素値の反転ができるのかを考えて,コメントとして書いてください
-- bitwise_not を使わない場合,「255から元の画素値を引く」で実現できます.こちらのやり方する場合も,それでなぜできるのかをコメントに書きましょう
-- 画像の大きさを変える
-- 適当に上記のもの以外の何か面白い処理を追加
+ printBoard() の出力が以下のようになるよう修正しなさい.~
&ref(http://www-tlab.math.ryukoku.ac.jp/~takataka/course/AProg/board.png,nolink);
+ このプログラムに,次のような仕様の関数 isValid() の定義を追加しなさい
-- 関数名と引数は以下の通り .board は盤面を表すリストのリスト,(x, y) が盤面位置((横方向,縦方向)
 isValid(board, x, y)
-- 位置 (x, y) が有効(盤面の範囲内かつまだoxがついてない)なら True, さもなくば False

(おまけのおまけ)カメラ付きのPCまたはウェブカメラを持ってるひとは,以下のプログラムを実行してみるとよいでしょう.
***step2 [#g4c90e7b]

+Step1 の成果と以下を組み合わせなさい.さらに,このままでは入力しても ox がつかないままなので,ちゃんと ox がつくように修正しなさい.
#pre{{
import cv2
### AProg2021-ex06  三目並べ = oxゲーム = Tic-Tac-Toe

cap = cv2.VideoCapture(0)
# 盤面の状態を表すディクショナリ
mark = {0:" ", 1:"o", -1:"x"}

while(True):
    rv, frame = cap.read()
    cv2.imshow('hoge', frame)
    if cv2.waitKey(1) == ord('q'):
        break
        
cap.release()
cv2.destroyAllWindows()
### リストのリストで表された盤面情報を o,x で表示する
#
def printBoard(board):

    #中身は自分で.mark 使うこと


### 位置 (x, y) が有効(盤面の範囲内かつまだoxがついてない)なら True, さもなくば False
#
def isValid(board, x, y):

    #中身は自分で


### 入力を受け付ける.有効な位置でなければ再入力してもらう
# 
def procUserInput(board):

    while True:
        msg = "どこに置く? 「0 1」のようにスペース入れて縦横の数を入力してね: "
        s = input(msg).split()
        if len(s) == 2:
            y, x = int(s[0]), int(s[1])
            if isValid(board, x, y):
                return y, x
            else:
                print("そこには置けへんで.", end="")
        print("入力し直して")



# 3 x 3 の盤面
board = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

# o の番なら 1, x の番なら -1
turn = 1

while True:

    printBoard(board)
    if turn == 1:
        print(" o の番ほげ.", end="")
    else:
        print(" x の番ほげ.", end="")

    y, x = procUserInput(board)

    turn *= -1
}}
+ 以下の関数 checkGameOver() を使って勝敗判定できるようにしなさい.勝ち負け引き分けが決まったら,盤面を表示したのち「oの勝ち」,「xの勝ち」,「引き分け」と表示してプログラムが終了するようにしよう.
#pre{{
### ゲーム終了かどうか判定.戻り値は次の通り.この関数は修正不要
#  
# -2: 引き分けでゲーム終了,   -1: xの勝利
#  0: まだゲーム終了でない      1: oの勝利
#
def checkGameOver(board):

    boardSize = len(board)

    # 横一行 mark がそろっていたら mark を返す
    for i in range(boardSize):
        mark = board[i][0]
        if mark == 0:
            continue
        j = 1
        while j < boardSize and board[i][j] == mark:
            j += 1
        if j == boardSize:
            return mark

    # 縦一列 mark がそろっていたら mark を返す
    for j in range(boardSize):
        mark = board[0][j]
        if mark == 0:
            continue
        i = 1
        while i < boardSize and board[i][j] == mark:
            i += 1
        if i == boardSize:
            return mark

    # 右下がりに mark がそろっていたら mark を返す
    mark = board[0][0]
    if mark != 0:
        i = 1
        while i < boardSize and board[i][i] == mark:
            i += 1
        if i == boardSize:
            return mark

    # 右上がりに mark がそろっていたら mark を返す
    mark = board[boardSize-1][0]
    if mark != 0:
        i = 1
        while i < boardSize and board[boardSize-1-i][i] == mark:
            i += 1
        if i == boardSize:
            return mark

    # 盤面が埋まってたら引き分け
    for i in range(boardSize):
        for j in range(boardSize):
            if board[i][j] == 0:
                return 0

    return -2
}}

***step3 [#g4c90e7b]

コンピュータと対戦できるように改造しよう.先手番 o は常に人間側(あなた)で後手番 x は乱数使ってランダムに手を打たせるようにしたらよい.

***step4 [#d28f0147]

ここまでのプログラムをうまく作っていたら,盤面を表すリストのリストを 3x3 ではなく 4x4, 5x5 等の適当なサイズにしても動作するようになっているはずです.動作を確認して,そうなっていなければ修正しなさい.

***提出法 [#h4e2bc50]

1118木1講時の時間中に,対面で高橋に見せてください.


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS