class: title, smokescreen, shelf, no-footer # Perl入学式in千歳 第3回 <div class=footnote> <small> Copyright 2019,2022 (C) Ken'ichi Fukamachi (<A HREF=https://www.fml.org/>fml.org</A>), CC BY-NC-SA. (注: <A HREF="/slides/lang/perl/caution/">諸注意から始めてね</A>) </small> </div class=footnote> --- class: compact # おしながき <div class=footnote> <small> (脚注) 公式テキストは情報量が多すぎるので、じゃんけんともぐらたたきを書くのに大事なところ以外は飛ばしぎみでいきます (テキストはリファレンスとしてご利用ください) </small> </div class=footnote> 1. [諸注意](/slides/lang/perl/caution/) 1. (講師陣の御紹介) 1. 前回までのあらすじ + ウォーミングアップ 1. 第3回(公式テキスト) - オンライン版(最新) - [第2回](https://github.com/perl-entrance-org/workshop-basic-online/blob/master/2nd/slide.md) ... 配列,ハッシュ,関数 - 2019年版 - [第2回](https://github.com/perl-entrance-org/workshop-2019/blob/master/2nd/slide.md) ... 配列 (最後の1/3) - [第3回](https://github.com/perl-entrance-org/workshop-2019/blob/master/3rd/slide.md) ... ハッシュ (前半) 1. [課題] もぐらたたきを作ろう (千歳版の独自拡張) 1. (残りの時間次第)関数までいけるかな? --- class: compact # 講師陣の御紹介 <div class=footnote> <small> 深町: 昨日はC言語でモグラ、今日はPerlでモグラ! なお、シェル版もあるよ?:) Go言語版も作りたいわね </small> </div class=footnote> - 第2回め以降は手練の社会人IT技術者のみなさんがTAとして参加してくれます <br> 各回、自己紹介してもらいますね (毎回やらなくてもよい?:-) --- class: compact # 演習環境の諸注意 - 環境構築(WSL + VSCode) - **注: Windowsの上に、もうひとつOSが乗っているので、 VSCodeの起動時には、VSCodeが、どちらのOS上でファイルの作成や検索をしているか気にしてください** - **メニュー -> ubuntu -> 開いてきたターミナル**上で次のコマンドを実行 ``` code perl-entrace ``` するとVSCodeは確実にWSL(仮想環境)側を見ているはずです - 確認: VSCodeを起動して、 VSCodeからperl-entraceというフォルダが見えているなら、 仮想環境を操作して出来ている(はず) --- class: compact # 前回までのあらすじ(1): Perlの基礎 <div class=footnote> <small> (脚注) Unix上で生活していて、ちょいと書いて手早く仕事をあげる一行プログラムで <>などの省略形が活躍 </small> </div class=footnote> - 変数 - 他の言語と異なり**変数名に種類を意味する特殊な文字をつけます** - 特殊文字を見るだけで変数の種類がほぼ確定できます: 例: `$x @y %z $y[0] $z{KEY}` - 前回は、スカラー変数だけ扱いました。配列(`@`)やハッシュ(`%`)は後ほど - 出力 (print 変数, ...) - 入力 (キーボードから読み込むには `変数=<STDIN>`じつは`変数=<>`と略してOK) - 乱数 (ここは呪文だと思ってコピー&ペーストしてもらいました) - srand ... 初期化。 例: `srand(time|$$)` - rand ... 乱数の生成。 例: `rand(3)`は3未満の2.998378983みたいな実数を返します - int ... 整数にする。 例: `int(rand(3))`は(自然数の)0か1か2を返す - 練習課題として「じゃんけん」を作りました --- class: compact # 前回までのあらすじ(2): 条件文と繰り返し文 - if elsif else - `if (条件)`とか`elsif (条件)`と書きます. これはC言語系とC言語リスペクト系は似たような感じ - **elsif**という呪文はPerl固有 - つねに<B>{ と }で囲み</B>ます - for while - C言語風の書き方も出来ますし, 中身を取り出していってなくなったら終わりという書き方も出来ます ``` [例] 読みこんだdataを変数$bufへ代入し,すかさず出力する(いわゆるcatコマンドの本体) while ($buf = <>) { print $buf;} [例] 配列の中身を順番に出力する(配列は今回やります!) for (@ARGV) { print $_, "\n";} ``` --- class: compact # 条件文(おさらい) ``` if (条件1を書くところ) { 条件1を満たしたときに実行するコード; } elsif (条件2を書くところ) { 条件2を満たしたときに実行するコード; } elsif (条件3を書くところ) { 条件3を満たしたときに実行するコード; } else { どの条件も満たさないときに実行するコード; } # 一行に書いてもよい(というか、どう書いてもよい;Perl詩を書いてもよい:-) if (条件1) { 条件1を満たしたときに実行するコード;} if (条件1) { 条件1を満たしたときに実行するコード;} else { 条件を満たさないコード; } ``` --- class: compact # 条件を書くところ (比較など)(おさらい) <div class=footnote> <small> (脚注1) たいてい文字と数字は別扱いです。 それは、コンピュータの内部で文字をどう表現するか?に関係 <br> (脚注2) ちなみに$a=1, $b=1のとき、$a eq $bは真です。 Perlは自動型変換をする言語なので、 数字を文字の1に自動変換後、$a eq $b を評価し、真という意味になります <br> (脚注3) さらに脱線。 次のコードは? print 1 if "a" == "b"; <br> (脚注4) print 1 if "takagisan" eq "karakaijouzu"; は1と出力?しません;-) (すみません、劇場版公開中記念のネタです) </small> </div class=footnote> ``` 数字の比較 # たいていの言語はコレ (FORTRAN由来C言語で普及かな?それなら1950年代〜) $a == $b # equal 例: $a=1, $b=1なら真(条件を満たす) $a != $b # not equal 例: $a=1, $b=1なら偽(条件を満たさない) $a > $b # ここは数学と一緒 例: $a=1, $b=1なら偽(条件を満たさない) $a < $b # ここは数学と一緒 $a >= $b # 数学記号はないので > と = 例: $a=1, $b=1なら真(条件を満たす) $a <= $b # 数学記号はないので < と = 文字の比較 # ここはPerl特有 ([脱線] シェルにもあるけど逆なので注意) $a eq $b # equal 例: $a="takagisan", $b="takagisan"なら真(条件を満たす) $a ne $b # not equal 例: $a="takagisan", $b="takagisan"なら偽(条件を満たさない) ``` --- class: compact # 繰り返し文(おさらい) <div class=footnote> <small> (脚注) 歴史的に教科書のループ変数は i (iteration の i のはず)ですが、 適宜わかりやすい変数名にしましょう </small> </div class=footnote> 当然C言語風の書き方(1)も出来ますが、 `()`内に繰り返すものを入れる書き方は便利(2)(3) ``` # (1) 3回くり返す for ($i = 0; $i < 3; $i++) { print $i, "\n";} $j = 3; while ($j-- > 0) { print $j, "\n";} # (2) コマンド引数の配列(@ARGV)の要素を一つずつ暗黙の変数$_に入れて繰り返し for (@ARGV) { check_hikisuu($_);} for (@ARGV) { print $_;} # 実行してみよう、引数が表示されます } # (3) "<>"は"<STDIN>"の略;入力があるかぎり暗黙の変数$_に入れつつ繰り返し while (<>) { check_nyuuryoku($_);} while (<>) { print} # キーボードから入れたものをそのまま表示 ($_も;も省略可!) ``` --- class: compact # 第二回の最終(総合)課題(おさらい) <div class=footnote> <small> (脚注) 日本語で「勝ち」などと表示してもよいのですが、たんにprintするだけでは警告が出るので (Encodeモジュールを使って正しいお作法で書けば警告は出ません) ... </small> </div class=footnote> - 前回のジャンケン、条件文、繰り返し文の合わせ技になります。さて、できるかな? - 混乱してきたらワークシートに書き込みながらやってみよう - 課題 1. 勝負の結果によって「kachi」「make」「aiko」と表示しよう 1. 3回ジャンケンしたら終了する 1. [発展]回数は無制限、ただし「9」を入れたら終了する 1. [発展]回数は無制限、ただし「q」を入れたら終了する (ヒント: どの比較の構文を使うのかな?) --- class: title, smokescreen, shelf, no-footer # Perl入学式in千歳 第3回<br>もぐらたたき --- class: compact # 変数とデジタル表現 <div class=footnote> <small> </small> </div> - 今回は、もぐらたたきです - モグラ叩きなので配列を利用します - モグラがいるところを1、いないところは0と決めます(ここは人為的) | 表現 | もぐら | 備考 | |------|------------|--------------------------------| | 0 | いない | C言語では0から数え始める習わし | | 1 | いる | | ![height120px](../../clang/mogura/images/mogura_irasutoya.png) | INDEX (何番目の要素) | 0 | 1 | 2 | 3 | |----------------------|---|---|---|---| | もぐらがいる? | 1 | 0 | 0 | 1 | --- class: compact # 配列 <div class=footnote> <small> (脚注1) 配列を英語で array と言いますの (脚注2) 配列=スカラー変数を並べたもの </small> </div> ![height120px](../../clang/mogura/images/array.png) - たとえば配列として変数@arrayを宣言した場合、たんに**同じ形の箱が連なっている**状態 - たいていは同じ箱を並べるのが配列ですがPerlは箱の形が違ってok。 例: (1, "abc", 10) - 変数の代入や読み出しの対象、 たとえばジャンケンの`$jibun`や`$aite`に相当する変数は、 `$array[1]`といった配列の一つの(箱の)部分になります - `$array[数字]` ... 数字で「何番目の箱か」を指定します (C言語と同じく0から数える習わし) - **変数として常に`$array[数字]`を使えばよい**、それだけです - この変数群には一連のシリーズを代入していくので、**たいていは繰り返し文とセット**で使うことが多いです。繰り返し文には慣れるましょう --- class: compact # Perlの配列操作 - C言語やシェルにない便利な関数がたくさんあります - split, join ... 文字列を配列へ変換、その逆 - revserse, sort ... ソート - pop, shift, push, unshift ... アルゴリズム - 豆知識: splitは、シェルで使うawk(言語)に由来するんだと思いますが、 他の機能はPerlが初出かな? - **ただし、今日のメインテーマのモグラタタキには不要**です。 ハンズオンとしては困ったね(w)、ま、いいですよね。 必要になったら探してみてください、便利な関数いろいろありますんで --- class: compact # Perlの配列操作でよく使う例 <div class=footnote> <small> (脚注1) 同じことをC言語で書いてみると何倍も長いプログラムになります。 そういうとき有り難味がわかる <br> (脚注2) splitの引数にある/\s+/の\s+部分は正規表現というものです。 正規表現は後日やりましょう。 \s+は「空白(長さは1以上)」という意味で、 split関数は「空白」で区切り、区切られた文字たちを配列として返します </small> </div class=footnote> ``` [コードの例] スペース区切りのデータを読み込んで整列させて出力 while (my $buf = <>) { # 読み込んだデータをスカラー変数$bufに代入 chomp $buf; # 余計な改行を削除 my (@buf) = split(/\s+/, $buf); # 配列@bufは空白以外の部品が並んでいる、ここでは @buf = (1, 2, 3) print join("\t", @buf), "\n"; # @bufの要素をタブでつなげて出力(注: chompで削除したから最後に改行が必要) } [実行例] このように空白の入れ具合が乱れているファイルが綺麗になって出てくる 1 2 3 -> 1 2 3 a b c a b c ... ... ``` --- class: compact # Perlの配列操作でよく使う例 <div class=footnote> <small> (脚注1) 成績順に並べて表示したいときは連想配列を使うと便利(後述) <br> (脚注2) シェルの方が短いし速いですけどね! 例: cut -f 1 -d " " data.txt | sort </small> </div class=footnote> ``` [コードの例] 学籍番号の確認をしたいので、番号だけ取り出し、ソートして表示 my (@id_list) = (); # 配列 @id_list を宣言、空に初期化 while (my $buf = <>) { # 読み込んだデータをスカラー変数$bufに代入 chomp $buf; # 余計な改行を削除 my ($id, $score) = split(/\s+/, $buf); push(@id, $id_list); # (b2101) -> (b2101 b2209) -> ... } @id_list = sort @id_list; # reverse sort とすれば逆順 print join("\n", @id_list), "\n"; # ソートした順で [実行例] b2101 30 b2101 b2209 100 -> b2110 b2110 50 b2209 ``` --- class: compact # 課題: もぐらたたき(基礎,乱数なし) <div class=footnote> <small> </small> </div> 課題: ユーザが数字(モグラがいると思う場所)を入力し、 そこにモグラがいたら atari、いなければ hazure と表示してください (技術レベル:乱数なしジャンケン+配列で出来る) ``` // 整数変数の配列 @mogura の宣言と初期化 // もぐらは「いる」「いない」「いない」「いる」 // 入力: キーボードから$jibunに値を読み込む // 条件文と出力 // $jibun の場所にモグラがいるか?(ヒント: 配列の $jibun 番目を確認) // いれば atari、いなければ hazure と出力 ``` - 発展課題 1. 繰り返し3回挑戦できる(1回だけ実行する部分と繰り返す部分がどこか?) 1. 最後に atari の回数を表示しましょう(新しい変数$tensuuとか必要) --- class: compact # 発展課題のヒント ``` // 整数変数の配列 @mogura の宣言と初期化 // もぐらは「いる」「いない」「いない」「いる」 // 繰り返す部分 // 入力: キーボードから$jibunに値を読み込む // 条件文と出力 // $jibun の場所にモグラがいるか?(ヒント: 配列の $jibun 番目を確認) // いれば atari、いなければ hazure と出力 // 条件文: atariの時だけ $tensuu = $tensuu +1 // $tensuuを表示 ``` --- class: title, smokescreen, shelf, no-footer # Perl入学式<br>連想配列 --- class: small,compat # 連想配列 <div class=footnote> <small> (脚注1) 正確には任意のスカラー変数が使えるんだっけ?(それが分かりやすいキーなの?は別) <br> (脚注2) hashは切り刻むことです。ハッシュドビーフのハッシュ </small> </div> ![height120px](../../clang/mogura/images/array.png) - 配列の指定は「何番目の箱」と数字で指定します。 言い方を変えると「**検索のキーに数字しか使えない**」のが配列 - キーに文字列とかも使えるのが連想配列です。 シェルのawkコマンドの**連想メモリ(associative memory)**でUnixワールドに登場! (初出?) - 学籍番号をキーに、成績を管理する表を連想配列で! --- class: small,compat # 例: 配列と連想配列 - 配列は`$変数名[ 数字(キー) ]`ですが、 - 連想配列は`$変数名{ キー }`と書きます(`{}`です) ``` # 配列: 1番めの場所にモグラがいる $mogura[ 1 ] = 1; # 連想配列 別名ハッシュ(hash), 例: 学籍番号 b2901の成績は60点 $seiseki{ b2901 } = 60; @seiseki = ("b2901", 60); # 一気に初期化する方法 # 日本語でもよいけれど、細かい注意がいろいろあるので今は日本語を使わないほうがよい $movie{ 6月10日より公開 } = "からかい上手の高木さん劇場版"; ``` --- class: compat # Perlのハッシュ操作でよく使う例 ``` 例: 成績よい順にデータを表示したい my %score_list = (); # 配列 %scored_list を宣言、空に初期化 while (my $buf = <>) { # 読み込んだデータをスカラー変数$bufに代入 chomp $buf; # 余計な改行を削除 my ($id, $score) = split(/\s+/, $buf); $score_list{ $score } = $buf; # キー=成績, 値="学籍番号 成績" } for my $score (sort {$b <=> $a} keys %score_list) { # キーを取り出し数字逆順ソート print $score_list{ $score }, "\n";# 該当する$bufを出力 } [実行例] b2101 30 b2209 100 b2209 100 -> b2110 50 b2110 50 b2101 30 ``` --- class: compat # 課題 - じゃんけんプログラムを改造します。 - 勝ち、負け、あいこが何回あったか?を表示してください - ヒント: 連想配列のキーを kachi make aiko にすると楽に書けます ``` [出力例] kachi 1 make 2 aiko 0 ``` --- class: title, smokescreen, shelf, no-footer # Perl入学式<br>もぐらたたき課題集 --- class: compact # 課題 <div class=footnote> <small> ポイント: アルゴリズム <br> (脚注) ぱっと考えつく案として (1)浮動小数点が必要なコード (2)整数だけで書けるコードの両方がある </small> </div> - 前の課題を改造して、 コンピュータにモグラの位置を決めさせてください - ヒント: どういう式を書けば、 乱数でモグラの「いる」「いない」を決めることができるでしょうか? (ジャンケンの理屈を少しひねれば出来そうじゃない?) - 1次元モグラの総合課題。改造テーマが2つあります - (a) 配列サイズを 9 にしてください - (b) モグラのいる割合を3割未満にしてください --- class: col-2,compact # 2次元配列 - 1次元配列は箱が横に並んでいます ``` a[0] a[1] a[2] ``` - 2次元配列はマス目つまりスプレッドシート(例:Excel)状で、 これに縦横の場所を指定する数字がつくというだけのことです ``` a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] a[2][0] a[2][1] a[2][2] ``` <wbr> - Excelのマス目はアルファベットと数字ですけど、 たてよこ両方とも数字だって慣れられそうですよね? ``` A1 B1 C1 A2 B2 C2 A3 B3 C3 ``` - 細かい理屈はともかくPerlでもCと同様に書けば使えます(`$`を付けてね!) ``` $a[0][0] = 1; $a[1][2] = 0; ``` --- class: col-2,compact # 課題(2次元) - 1次元モグラを参考にしつつ2次元モグラを作ってください - 二次元なのでユーザは毎回2つ数字を入れます - あとは、ノーヒントでトライ ``` [実行例] $ perl mogura2d.pl 1 2 atari 2 3 hazure 6 8 atari tensuu = 2 ``` --- class: col-2,compact # 課題(2次元) - 分かりやすいように、モグラたたきの現状を二次元のマス目で表示するようにしてください - O ... atari - X ... hazure - . は、まだ叩いていない場所 ``` [実行例 (9x9)] 7 8 atari! 1 2 3 4 5 6 7 8 9 1 . X . . . . . . . 1 2 . X . . . . . X . 2 3 . . X X X . . . . 3 4 . . . . . . . . . 4 5 . . . X . X . X . 5 6 . . . . . . . . . 6 7 . . . . . . . O . 7 8 . . . . . . . . . 8 9 . . . . . . . . . 9 1 2 3 4 5 6 7 8 9 ``` --- class: compact # 発展課題 1. モグラ叩きを何回できるか?を指定できるようにしてください 1. モグラ叩きの回数に上限なし。数字の9を入れたら終了 1. [やや難] 文字の q を入力したら終了にしてください 1. 終了時に、何回勝ったか?も表示してください 1. 終了時に、何勝、何敗、あいこが何回か?を表示してください 1. モグラには下っ端とボスがいて、下っ端とボスではアタリの点数が違うようにしてください。 たとえば下っ端は1点ですがボスは10点。点数の種類も増やしてみましょう 1. モグラ叩きの履歴(ユーザの入力履歴とアタリハズレの情報、勝敗)をとれる 1. 履歴を分析し、ユーザの叩きやすい場所(数字の偏り)を表示してください 1. [やや難]履歴をファイルに保存。次回以降、それを読み出し、総勝敗結果を表示 1. [難]履歴を保存し、次回以降に、それを読み出して分析対象にします。 初期化の際は、ユーザがあまり叩かない場所にモグラを出現させてください