pg09
テーマ:数値計算とプログラム
内容 確率シミュレーション
扱う言語は Python を予定していたが、 Scala に変更する
http://qiita.com/oubakiou/items/31fd45ca337d76113a1e Scala採用企業のまとめ
前振り: iPad のダイスアプリ紹介
統合開発環境(IDE: Integrated Development Environment )
eclipse の起動と設定
スタート → コンピュータ → ボリューム(D:) → scala → eclipse.exe をダブルクリックで起動
プロジェクトの保存先の設定
標準の保存先が ../workspace となっているが、変更する。
Browse…のボタンを押して、アカウント名のフォルダ(氏名または学籍番号)を選択 →
マイドキュメント を選択 → 新しいフォルダの作成 ボタンを押す →
フォルダ名を pg09 に変更する → OK を押す
→ OK を押す
eclipse が起動する。
Scala 開発環境の設定
eclipse
-> Package Explorer(パッケージエクスプローラ)を右クリック
-> New(新規)
-> Other...(その他)
->Scala Wizards(ウィザード)
-> ScalaProject(プロジェクト) → Next(次へ)
Project name(プロジェクト名) pg09 と入力 → Finish(完了)
練習用アプリケーション作成:
パッケージエクスプローラ から
pg09 プロジェクト
src フォルダ
→右クリック Scala App(アプリ) 作成
name(名前) Test と入力
→ Finish
2017年度用変更点:
↓のREPLの準備はスキップする。
REPL(Read Eval Print Loop)の準備:
Console(コンソール)(+マークの付いたアイコン) ▼メニュー
→ Scala Console をメニューから選択
2017年度は以下を使用:
Scala ConsoleのREPLは不便な点があるので、Scala Interpreter を利用することにする。
ウインドウ → ビューの表示 → Scala Interpreter
コードを入力後、 Ctrl + Enter で実行。
複数行のコードを書いて、Ctrl + Enterでまとめて実行できる。カーソルの位置はどこにあってもOK
複数の式を評価できる。ブロックにしたり、; で複数の式を記述して実行できる。
※ 1+2;3+4;5+6 の実行結果は 11 になるが、1+2 と 3+4 の式は無駄なコードになるので、warning がでる。
Ctrl + ↑ ↓ で、履歴を辿れる。(行単位でなく、実行単位)
メニューに、コードのリセットや再実行のボタンがある。
:help など ScalaのREPLコマンドは使えない。
文字入力の練習
以下の例で、あ 以外は 漢字入力OFF で入力する。
"あ"
あ
1+2*3
val a = 1234+5678*9012
a*3
scala> 一番下のの行に文字が入力されるように、マウスでクリックする
文字を入力後、Enterを押すと入力内容がプログラムとして実行される
デモ: トラブルが起きたときの対処法(このページ最下部参照)
・複数行コピペして貼り付けると、続けて入力ができなくなり困ったことになるので、避ける。←わざとやって見せる
・回復方法を示す。
REPLコンソールで以下を実行:
scala> 1+1
scala> 2*3
scala> "abc" + "xyz"
scala> "abc" * 3
scala> "abc"(1)
scala> "abc"(0)
scala> "abc" map ( _ + " ")
scala> "abc" map ( _ + " ") mkString
scala> val hw = "Hello world!"
scala> hw.size
scala> hw(0)
scala> List(1,2,3)
scala> val a = List(1,2,3)
scala> a(1)
scala> a.sum
scala> a map ( x => if(x>2) 1 else 0)
scala> a map ( x => if(x>2) 1 else 0) sum
scala> a count (_>2)
ランダムを利用したシミュレーション
import scala.util.Random
Random.nextInt(10)
Random.nextInt(10)
Random.nextInt(100)
Random.nextInt(100)
(1 to 100) map ( _ => Random.nextInt(100) )
(1 to 100) map ( _ => Random.nextInt(100) ) sum
val rand = (1 to 1000) map ( _ => Random.nextInt(100) )
rand に対していろいろな処理を試す
処理は、
結果の集計 sum
ある数値以下か判定して個数を集計 map ( x => if( x < 10 ) 1 else 0) sum
ある数値の個数を集計 map ( x => if( x == 0 ) 1 else 0) sum
ある数値の個数を集計 count( _ == 0)
※map と sum を使用した個数の集計よりもシンプルなコード
文字列化して結合 mkString
ガチャガチャのシミュレーション
Rare 希少 大当り
Uncommon 珍しい 当り
Common 普通 はずれ
scala> val gacha = "R"*3 + "U"*15 + "C"*82
scala> gacha.size
scala> gacha(0)
scala> gacha(50)
scala> gacha(Random.nextInt(100))
何回かガチャを回してみよう
連続ガチャのシミュレーション
scala> val rg = (1 to 100) map ( _ => gacha(Random.nextInt(100)) )
scala> rg count(_ == 'R')
種類ごとに集計する
scala> val kekka = rg map { case 'R' => (1,0,0); case 'U' => (0,1,0); case 'C' => (0,0,1) }
scala> kekka./: (0,0,0) { case ((ar,au,ac),(r,u,c)) => (ar+r,au+u,ac+c) }
解説:
rg map { case 'R' => (1,0,0); 引いたいたカードの各種類 R U C に応じて、 (Rが1枚, Uが1枚, Cが1枚) に変換する
kekka./: (0,0,0) 初期値 RUCの所持枚数は各0枚。 /: は map と同様、 kekkaの各要素に対して順番に処理を繰り返す。map と異なり、各要素ごとに個別に結果を残さずに、処理結果を累積して処理する。全要素の処理後に、累積値を計算結果とする。
(ar,au,ac) 累積中のRUCの枚数。
(r,u,c) kekkaから順に取り出された要素。
(ar+r,au+u,ac+c) 累積方法。 kekkaから順に取り出した要素を、対応する累積値に加える。 例) 累積値 (0,3,10) に対して、 要素が(1,0,0) なら、累積値は (1,3,10)に更新される
時間に余裕があるなら、条件を変えて実験する
例)
ガチャの構成比率の修正
val gacha = "R"*1 + "U"*17 + "C"*82
ガチャの種類を増やす。集計方法も (1,0,0,0) のように4種類分で集計するように変更する。
val gacha = "S"*1 + "R"*3+ "U"*15 + "C"*81
※ SR や UR など2文字で表現されるレアリティーは、今回のコードではうまく動かない
YやXなど1文字に置き換えて表現する
ガチャをひくプログラムを、
scala> gacha(Random.nextInt(gacha.size))
に修正すれば、カードの種類数に応じてガチャを回すプログラムになる。
↑修正後、手動で何回かガチャを回したり(ひく)、連続ガチャのシミュレーションをする。
結果を集計してみよう。
※ 0.1% などの比率を設定したい場合は、ガチャの総種類数を1000など、大きく変更する。さらにガチャの範囲を Random.nextInt(1000) と調整する。
応用編: ガチャはこわい
0が出てくるまで、引き直した回数を求める。
結果が0なら、最初の1回目で0が出たことになる。
Stream.from(1).indexWhere(_ => Random.nextInt(100) == 0)
応用編: ガチャガチャマシンのシミュレーション
今回の課題は、デジタルなガチャなので、アイテムの個数に制限は無く、いくらでもガチャを回せる。
このプログラムを、実在のガチャのように1つアイテムを出すと、機械の中のカプセルが1つ減るようにプログラムを修正する。
※ Scala の文字列処理などを検索して、使えるコードを探して下さい。
提出方法
コンソールのメニューアイコン(フロッピーディスク) を押して
保存したファイルを、編集するか聞いてくるので 「いいえ」 を選択する
デスクトップに保存する(ファイル名は適当でOK)
例)
3116999.log
WebClass の第13回課題にアップロードする。
トラブル対応1
// Entering paste mode (ctrl-D to finish)
コンソールに ↑ と表示されたら、入力が受け付けられなくなる。 赤い四角の停止ボタンを押して、REPLを止める。
できたところまでを、↑↑ の提出方法を参考に保存しておく。
Scalaコンソールを開きなおす。
続けて演習を行う。
トラブル対応2
コンソールのログを保存する際に、「保存したファイルを、編集するかで 「はい」 を選択」した場合、Scalaコンソールが開けない。
eclipse の編集画面(コンソールの上の部分)のタブを、ログファイルから、Test.scala にクリックして切替える。
トラブル対応3
コンソールタブを閉じてしまった場合、 再び表示するには: eclipse のメニュー → ウインドウ → ビューの表示 → その他 → 一般 → コンソール
トラブル対応4
コンソール停止後に演習を再開するとプログラムにエラーが出る
→
import scala.util.Random
val で定義した行
などを再実行する。
トラブルの原因:
複数行でコピペしたときに発生する?
Webからコピペしたときに、先頭文字から選択してコピペすると、改行文字がコピペされることが原因かも。
メモ
素数+アニメーション
マルコフ連鎖
すごろく