2016年2月7日日曜日

SHOW BY ROCK!!を始めて50日経過

30日経過。ランクは103。
そして50日経過。ランクは142。
ビンゴの初回ストッパーがログイン30日なのにその後は20日おきっぽいですね。
まぁ一カ月強、二か月未満。次は70日なので二か月弱ですか。

育成はまぁ割と順調なのかな?早いのか遅いのかはわかりませんが・・・。
分かった事をいくつか。

その1、ハートとランクについて

クールタイムは睡眠を考えると6時間から8時間は欲しい所でしょう。
と言うわけで計算してみました。
8時間は60*8=480、6時間なら60*6=360。

ハートは3分で1回復なので3で割れば必要なハートが分かります。
8時間クールなら480/3=160、6時間クールなら360/3=120ですね。

後はハートの初期値20を引いてやれば必要な増加ハート数が分かります。
8時間クールなら160-20=140、6時間クールなら120-20=100ですね。

2ランク毎にハートが一つ上がるのでこの値を2倍にすれば必要なランクが分かります。
8時間クールなら140*2=240、6時間クールなら100*2=200ですね。

30日までで103という事は103/30で一日の上昇は約3.4ランク。
ですが50日までに上がったランクは39なので39/20で1.95ランク。
となると200まで行くまでに一日に上がるランクは1くらいかそれを切りそうですね。

その2、EXPについて

そこで気になってくるのがEXPですね。
EXPがランク(スコア)で固定の為解り易いです。
属性ブロマイド集めはイージーが最も効率が良い訳ですがEXPは違います。

曜日イベント

ハートを5消費して神ランククリアでマスコン・フルコン関係なく最大50。
その為、曲に寄りますが8万~9万程度スコアがとれればそれ以降叩かなくてもEXPは同じです。
1ハート毎効率は50/5=10EXP

ノーマルとハードは属性合計が10万でもSランクが大半になります。
ノーマルの場合15を消費してSランクが120EXPとなり、120/15=8EXPと効率が悪いです。
神ランクが取れる曲がある場合でも150EXPなので、150/15=10EXPとイージーと同等になるだけです。

ハードの場合はSランククリアでも400が入る為、400/30=約13.3EXPと最も効率が良いです。
さらに神ランククリアができる曲がある場合500/30=16.6EXPとかなり効率が良くなります。

固有イベント

ハードは★6~7で推奨ソウルは20000と低い為、基本的に神ランククリアになる。
ただし、ロングマーカーを疎かにしすぎたりするとSランクになったりもする。

EXPは114固定でEXP効率が16Exp/Hとかなり良い。
ハードの神クリアには微妙に及ばないが十分なEXP効率を得られる。

EXP表

イベント名称難易度消費♥推奨ソウルSランク(EXP/♥)神ランク(EXP/♥)
曜日イベント(月~日)EASY (★2)5400040(8)50(10)
曜日イベント(月~日)NORMAL(★5)1520000120(8)150(10)
曜日イベント(月~日)HARD (★7)3060000400(13.3)500(16.6)
固有イベントEASY (★2~3)710000-(-)105(15)
固有イベントNORMAL(★4~6)820000-(-)136(17)
固有イベントHARD (★5~7)920000115(12.7)144(16)
固有イベントEXPERT(★7~8)1035000121(12.1)-(-)
BVLイベント(★2)24000-(-)40(20)
BVLイベント(★4)415000-(-)80(20)
BVLイベント(★6)64000096(16)120(20)
BVLイベント(★8)865000128(16)160(20)
歌えイベント(★2)24000-(-)50(25)
歌えイベント(★4)415000-(-)100(25)
歌えイベント(★6)650000-(-)150(25)

※曜日イベントはボスから生き残ればOK(報酬には撃破が必要)

EXP効率まとめ

歌えスペシャルSHOW BY ROCK!!イベント(2016/5/11追記)

私が初めてからのイベントではもっとハート毎EXP効率が高い。
問題があるとすれば★6が最大なので何度もプレイする根気が必要になる。

BUD VIRGING LOGICイベント(2016/2/16追記)

どの難易度でも20という効率の良さ。
こうなると最も消費が速い★8回しが良く、しかも今回のファーストソング「ソラウソ」の★8は難易度が低めで回しやすい。
しかも推奨ソウルが65000あるが他属性ミス消しを入れてもフレンド含め80000前後あれば神ランクでクリアできる。
勿論★8が厳しい場合や回転数増加を気にしなければどの難易度でも♥に対する効率は同じなので低い★で回しても良い。
(まぁ★2で回すと単純に★8の4倍回す必要が出る為、★6が良いとは思う)

最後に追加された「Forbidden」はスコア効率が低い。
ソラウソ・オヤスミパラノイアで神ランククリアになるデッキでも「Forbidden」ランククリアになる為EXPを考えるならプレイしないほうが良い。

固有イベント

ノーマルが最も効率が高くなる様です。特設での創聖神やイヤホイでのUR固定報酬などない場合はEXPの為にノーマルを延々と回すというのがよさそうですね。

曜日イベント

ブロマイドが欲しい場合はイージーを回してEXPが欲しい場合はハード回そう!っていうのが最終結果です。

ただし、楽譜とサウンドル(土日イベント)は高難易度の方が上位報酬になりますので基本的にはハードを回すのが良いという感じです。
特に楽譜の三つ目はイージーでもでますが、圧倒的にハードプレイ時の報酬確率が高い為ハードが良いと感じました。

現在23バンドで進化4で2つ使うという事が分かっているので、23*2=46個取得した時点で楽譜集めは終了となります。
必要数楽譜がそろった場合土曜日はツアー進行日となります。

逆にサウンドルはいくらあってもイベントで湯水のごとく使う為日曜はツアーよりも稼げるだけ稼いだほうが良いです。

また、ポイントチャレンジ系においてサウンドルによるイベントブースト系とイベントプレイを比べた場合イベントプレイをした方が良い事が経験から分かっている為、イベント中は曜日イベントは全て無視、サウンドルが尽きようがイベントの回数をこなした方が良いです。

私の場合スコチャはクリアできる曲をクリアだけして残りはスルー(スコチャは555位に入れる訳が無い為)

その3、ハード(★7)で神ランクを獲れる曲について

言い直すと、出来るだけスコア回収率が高い曲についてです。
尚且つボスを撃破し、完走できる曲が良いです。

ボス戦ではフィーバーが発生しない為、
ボス戦のフィーバーが頻度上昇とフィーバー2倍は死にスキルです。
1.2倍や高スコアアップが有効です。

今後追加しますが以下曲がお勧め・・・。
──────────────────────────────

POPSPICE(ELECTRIC DANCE SYSTEM)

水/ラペッジ
クリアランク境界:S【174,197】、神【179,320】

ソウル合計10万程度あればロングマーカーを極力押していれば神ランクを獲れる。
(属性60%がリーダーで1枚は他属性でも構わないという条件)

参考:https://play.lobi.co/video/0e32408b4186bc77e3ddc3d37a3559852215280a
動画ではマスコンが取れたものを録画したがEXPの境界はあくまでもクリアランク
コンボが途切れようが大体叩けていれば神ランクなので
属性60%上昇+回復という耐久の組み合わせブロマイドでも良い。
──────────────────────────────

ボクらのShiny Star☆

木/トライクロニカ
クリアランク境界:S【】、神【161,079】

ソウル合計10万程度あればロングマーカーを極力押していれば神ランクを獲れる。
(属性60%がリーダーで1枚は他属性でも構わないという条件)

----------
InSight(未クリア)/Get the sound(未クリア):細かい打鍵が多く厳しい
──────────────────────────────

秋雨純情歌


火/徒然
クリアランク境界:S【190,894】、神【196,955】

ソウル合計10万程度あればロングマーカーを極力押していれば神ランクを獲れる。
プレイ中190kあたり止めてもクリアボーナスで神ランクまでスコア上乗せが足りるっぽい。

(属性60%がリーダーで1枚は他属性でも構わないという条件)
──────────────────────────────
らぶむ

2015年12月26日土曜日

SHOW BY ROCK!!ガチャ2

ドーン!50個たまっても少し我慢しようと思っていたんですがダメでした。
そして、前回のレトリーに続きチュチュもきました!!
ただ・・・なんでクリスマス版が来ないんだ・・・。(期間的に3回目の10連は無理そう)

そして前回話していた通り光が飽和しすぎている。
ですがさらに今回はなんとURがもう一枚。「うるとらすたっど!フェネリィ」が一緒にでました。
前回10連で出なかった分を考えると確率の収束と考えるべきでしょうか。

光:UR:テンションMAX・チュチュ♪
火:UR:うるとらすたっど!フェネリィ
火:SR:梅にでゅらでゅら
火:R:すたっど・れいんぼー!L
火:R:ゼブリ・ナレコーディング中
火:R:吽の趣味
火:R:フェネリィ・ヒマを持て余し中光:R:負けるな!バイガンバーV!
闇:R:今はやってませんけど。デモンスモッグ
緑:R:文化祭本番!しばりん

うーんこれで覚醒可能ブロマイドが4枚に!

現在の編成

2015年12月25日金曜日

Xperia Z5とSHOW BY ROCK!!

どうも黒い野良猫です。

ついに・・・スマホを契約してきました。
と言うのも「SHOW BY ROCK!!」のBD全巻・予約特典・CD全巻と大量のチケットコードがあり、最も早くきれるのが予約特典の12月25日だったため。

えぇ、完全にゲーム機ですね。
それでチケットの内容について

■まずBDは固定URブロマイド

光:UR:ぷるぷる♪シアン&レトリー
光:UR:ぴゅるちゅ♪チュチュ&モア♡
光:UR:ぷるぷる!夏合宿♪
火:UR:徒然なる豪華特典でありんす♪
光:UR:クリクリ♪JCアイドル宣言!
光:UR:ぷるぷる!み~んなありがとにゃん♪

各巻の表紙がブロマイドになっています。
4巻以外は全て光で、4巻のみ火となっています。

属性に偏りがありすぎて光はALLBD特典編成となりました。
まぁ、現在クリスマスイベントが光イベントなので凄くはかどります。

また、全ブロマイド3ミス帳消しがパッシブなので始めたばかりの私には重宝しています。
逆にアクティブがPリズムワイドが2つ被っていたりするためいずれ変える事にはなりそうです。



■次に予約特典UR確定チケットx3

水:UR:コリエンテ・SSマインド
水:UR:タートルBIG・SSマインド
光:UR:テンションMAX・レトリー♪

欲しかったのはもちろんクリスマスURでしたが、まぁコリエンテとレトリーは覚醒できるようなのでまずまずの結果。
光がBD特典で飽和気味です。
水は2枚もURが来たのでしばらくはこれで乗り切ろうと思います。



■最後にCD特典SSR以上確定チケットx9(一枚多くCD購入してます)

闇:SSR:漆黒の翼・クロウ
水:SSR:オールナイト・ミックス
水:SSR:オールナイト・アシッドモンド
水:SSR:ワンマンライブ・キンタウルス
水:SSR:天空遺跡ライブ・ミトミトン
火:SSR:つぎはぎ・ワンマンライブ
火:SSR:がしがし・ワンマンライブ
緑:SSR:森然と光のサダフルン
光:SSR:光の戦士・バイオレッド

まぁわかっていましたがSSRしか出ませんでした。
URが一枚でもきてくれればなぁ・・・。
バイオレッドは属性アップで割と良いのですが光はUR5枚以上あるので



■初めての10連ガチャ

序盤ツアーとビンゴだけで取り敢えず50個かろうじてたまって即10連。

闇:SSR:漆黒の翼・アイオーン
水:SSR:シャボボン・シークレットライブ
緑:SR:音の森のサダフルン
他残りはN

UR確率アップとは一体・・・ぐぬぬ。・・・ぬぬぬ・・・。



◆現行編成

・闇
闇:SSR:漆黒の翼・アイオーン
闇:SSR:漆黒の翼・クロウ
闇:N:Lv15 ビンゴ用の奴
闇:N:Lv15 ビンゴ用の奴
闇:N:Lv15 ビンゴ用の奴


・火
火:UR:Lv50:徒然なる豪華特典でありんす♪
火:SSR:つぎはぎ・ワンマンライブ
火:SSR:がしがし・ワンマンライブ
火:N:Lv15 ビンゴ用の奴
火:N:Lv15 ビンゴ用の奴

・水
水:UR:コリエンテ・SSマインド
水:UR:タートルBIG・SSマインド
水:SSR:オールナイト・ミックス
水:SSR:オールナイト・アシッドモンド
水:SSR:シャボボン・シークレットライブ
予備
 水:SSR:ワンマンライブ・キンタウルス
 水:SSR:天空遺跡ライブ・ミトミトン


・緑
緑:SSR:森然と光のサダフルン
緑:SR:音の森のサダフルン
緑:N:Lv15 ビンゴ用の奴
緑:N:Lv15 ビンゴ用の奴
緑:N:Lv15 ビンゴ用の奴

・光
光:UR:Lv50:ぷるぷる!み~んなありがとにゃん♪
光:UR:Lv50:ぷるぷる♪シアン&レトリー
光:UR:Lv50:ぴゅるちゅ♪チュチュ&モア♡
光:UR:Lv50:ぷるぷる!夏合宿♪
光:UR:Lv50:クリクリ♪JCアイドル宣言!
予備
 光:UR:テンションMAX・レトリー♪



◆始めて5日程度の感想

ゲームシステムはだいたい理解しました。
ただ音ゲーマーではない私には現状イージーがなんとかなる程度。
星4くらいをミスキャンセル3回込みでフルコンって所です。

ハードは現状だとだいぶキツイ。
少なからずチャレンジクリアできる率は限りなく低い。

クリスマスイベントに合わせ光バンドは全てLv20に
ただまだ平日しかプレイしてないので譜面が無い為今はこれが精いっぱい。

ブロマイドの光は取り敢えず金曜でALL Lv50となりました。
BD特典URがあレトリーを持て余してる感。

緑と闇は現状所持ブロマイド的に特に鬼門

こんなところですかね。

2015年12月11日金曜日

Paiza Online Hackathon 7

恋愛SLG:プログラミングで彼女をつくる|paizaオンラインハッカソン7

https://paiza.jp/poh/ando

※【眼帯・ニーソ】は2015/12/14あたりに問題追加実装された
※【猫耳・猫セット・メイド服】は2016/03/??あたりに問題追加実装された
上記は後から実装されたされたため追記しています。

<言語:Python2>(※注意:二段になっているコードも全て一行です)
釣り目   
眼帯    
ショートヘア
ロングヘア 
ポニテ   
ツインテ  
セーラー  
カーディガン
追加問題  2015年12月追加
ニーソ   
追加問題  2016年3月追加
猫耳    
猫セット  
メイド服  

さて、上の問題はたぶん各1・2分でとけるんじゃないかと思います。(まぁ、眼帯が少し考えるかもしれない)

問題らしい問題はアクセサリだけ。

■眼帯が意味不明な人向け解説
左端にprintが来るという事は処理を全て右側処理しきっているわけですがごちゃごちゃしすぎ・・・。

確かに。と言うわけでこのゴミみたいなコードのリスト内包をちゃんと変数に代入して表示してみましょう


これでだいぶ処理が解り易くなりました。更にリスト内包を展開します。


見ての通り、最初のリスト内包以外はforの意味は有りません。
2回目のリスト内包はinputで得た集合を代入せず直接取り出し計算するために使い、
3回目のリスト内包は集合の解除→ソート→リスト内文字列化を行いつつifの変わりに使っています。
最後にjoinでリストをスペース区切りに結合してprintから出力しています。

当たり前ですがリスト内包の使い方としてはあまり正しくありません。
リスト内包の特徴はリストを生成に特化したforでだからです。
しかも処理毎にリストに格納される為「listdata[0]」として都度リストから展開する必要もあります。


めがね

概要:


サンタ服

概要:
「前面:X」x「側面:Y」x「高さ:Z」の立方体から切り分けた時に最も小さい立方体の体積を求める。
ただし上面と水平方向には切り分けない為最も小さい平面に高さZをかければよい。
切り分けの入力は「0or1 距離」で
0の場合は側面と並行に切り分ける場合。
1の場合は前面と並行に切り分ける場合。
距離はその端からの距離が入力される。
条件として0センチの切り分けは無い。二度同じ場所は切り分けない。片方向しか切り分けない場合がある。値は全て整数。

図形をぱっと見た時に三方向に切り分けるのかなと思って後回しにしていましたが高さの切り分けがないのでなんて事は無い面積問題ですね。
切られる距離は前か横からなので順番がわからない以上最後にソートして各距離間をだせばOK。

https://paiza.jp/poh/ando/share/3c2d1b45
提出言語:Python2
提出コードバイト数:329
Test case1 成功実行時間: 0.03 秒
Test case2 成功実行時間: 0.03 秒
Test case3 成功実行時間: 0.02 秒
Test case4 成功実行時間: 0.02 秒
Test case5 成功実行時間: 0.04 秒



水着

概要:
入力Nの階乗の答えから末尾にある0を全て取り除き、その値から末尾9ケタを取得する。
取得した9ケタの頭が0の場合はその頭の0も取り除く。
Nの範囲「1 ≦ N ≦ 1000000」

考え方は「カーディガン」問題の延長にある。
ただし、Pythonでは桁が多すぎて安直な回答では問題4からタイムアウトする確率が非常に高い。

たとえば【階乗の値を文字列化rstripで末尾0削除し、後ろから9ケタ取得後int化により先頭0を除去】と、した場合

Test cace1:○ 0.02秒
Test cace2:○ 0.02秒
Test cace3:○ 3.97秒
Test cace4:× 15.00秒 ※タイムアウト
Test cace5:× -秒
全く持って処理速度が足りない。

さて、「math」で「1000000」の時点で処理速度が追いつかない。
階乗処理は自作しなければならないことが確定した。
0がどんどん増えていくため先ずそれを抑止する事を考えてみる。
かける前に自身に0が付く場合先に除外しておけば良い。
階乗では全て掛け算で、0が増える場合は「2*5」が含まれる場合である。 それを取り除けば末尾0の数を調べる必要が無い。

考え方
・かける前に10で割れるだけ割っておく。
・2で割れるだけ割り、それをカウントしておく。
・5で割れるだけ割り、その分だけ2のカウントを減らしていく。
・最後に2のカウント分累乗をかければ末尾に0の無い階乗結果になる。
・末尾9ケタを取りintで先頭0を削除する。

Test cace1:○ 0.02秒
Test cace2:○ 0.02秒
Test cace3:○ 3.55秒
Test cace4:× 15.00秒 ※タイムアウト
Test cace5:× -秒
微妙に早くなった。たぶんこれは2の掛け算をギリギリまで行わずに最後に累乗で追加するからからだろう。
だが、結局全く持って処理速度が足りない。


まともにやりあっていては駄目だ・・という事で今回たまたまツイッターでこの問題について少しリプライのやり取りがあり、手直しして組み直したものがあるのでそれを紹介します。
考え方的には上位の桁を無視して下の桁だけで計算させるというもの。
殆ど元のツイートを参考に短く組み直しただけに近いので偉そうなことは言えませんがなんだかんだでそれなりの長さと速度になったのではないでしょうか。
9桁ギリギリだと桁ぶれが発生してエラーになる為11桁にする事で全ケース通過をするようにしてある。
85byte https://paiza.jp/poh/ando/mypage/5e7d53b6

Test cace1:○ 0.03秒
Test cace2:○ 0.02秒
Test cace3:○ 0.10秒
Test cace4:○ 0.70秒
Test cace5:○ 0.84秒

蛇足等
ニーソ短い版 https://paiza.jp/poh/ando/mypage/5e7d53b6?c=8047e40d
提出言語:Python2 提出コードバイト数:43 All cace:0.02秒

カーディガン短い版 その他版
提出言語:Python2 提出コードバイト数:41


眼帯まだましな方


例の邪道版

2015年10月8日木曜日

Pythonのリスト内包表記その2

リスト内包表記を知らなかった私が、前回(http://blackstraycatreboot.blogspot.jp/2015/10/python.html)リスト内包表記はリストの条件付き再リスト化と覚えたばかりだが他にも直接文字列を列挙したりできるらしい。

つい最近
【漫画版: 女子高生プログラマーの大バトル!〜コボール文明の逆襲〜|paizaオンラインハッカソン6】>【遺跡発掘ゲームで古代コボール王Ⅳ世を撃破せよ!|緑川つばめ】
(https://paiza.jp/poh/joshibato/tsubame)の簡単な問題にて

入力値+その値左側(10の位)+その入力の右側(1の位)を足して終わりという簡単な問題
初回は単純に


n=raw_input()
print int(n[:1])+int(n[1:])+int(n)


一度変数に格納してスライスで分解し、intへ変換しつつprint出力しました。
しかし、面白味が無かったので入力値を直接回答叩き込みたくなった。

ところが変数は分解しなければならず、入力値に直接スライスでは値をそのまま返せない。
変数のコピーさえあれいいのに・・・

そこで指定値for系で学んだリストの生成方法を思い出した
ループさせる場合【 for x in range(N) 】みたいな生成が一般的だが【 for x in[0]*N 】の方が生成が早くさらに【 for x in[None]*N 】の方が速い。
今回速度はさて置き、リストは【 [指定値]*数値 】でリストを生成すれば元値を複製できる。


[raw_input()]*3


これで入力値を3つに複製できた。
ですが値を切り出し、さらに数値にして合算する必要がある。

そしてついに話戻ってリスト内包表記!これならリストを列挙しつつしかも最終的な値を直接返せる!
リストに対するint変換は入力値周りで覚えたmapによりintに変換できるし、さらにそれに対して他の問題でやったリスト合算sumが使える。

なるほどこれは簡単に見えて総合問題なんだな(絶対違う)という事に。
だがしかし、ここで少し手が止まる。


print [x for x in[raw_input()]*3]


三回入力値を得られたが処理に変化を加える為の方法がない。
ここで1・2分くらい悩んでenumerateを思い出した。
リスト要素に対し値と要素番号を得られる。これでどうにかしよう。


print [b[::] for i,b in enumerate[raw_input()]*3]

スライスで切り抜くには【 変数[開始インデックス:終了インデックス:ステップ] 】となる。
だがここでまた思案。

iに入ってくるのは0・1・2これを要所に設定した場合格納値は(入力が27の場合)

b[i::]→["27","7",""]
b[:i:]→["","2","27"]
b[::i]→エラー(ステップに0は指定できない

んー惜しい・・・。

開始+0、終了+1なら(入力が27の場合)

b[i:i+1:]→["2","7",""]

んーこれでは全体が入らない。
同時に平行で移動する関係上範囲が一定なのは仕方がない

今が
b[0:1] #2
b[1:2] #7
b[2:3] #""


なので
b[0:1] #2
b[1:2] #7
b[0:2] #27
とかになってくれれば・・・ん?

これ、オーバー通る?
b[0:3] #27
通る

0・1の交互なんて連番なら簡単じゃないか数値の÷2のあまりでいい
じゃあ・・・

b[i%2:i+1:]→["2","7","27"]

キター。
それじゃあ、これにmapかけて

print map(int,[b[(i%2):(i+1)] for i,b in enumerate([raw_input()]*3)])
>>>[2,7,27]

sumで合算してやれば

print sum(map(int,[b[(i%2):(i+1)] for i,b in enumerate([raw_input()]*3)]))
>>>36

できたーーー!時間にして10分なんて難しい総合問題なんだ・・・。




今回の落ち(と、言うか今回はこれの為)
別な問題をやっている時にヒントとかいうのに気付いた

print ''.join([v for k,v in enumerate(raw_input()) if k%2 == 0])

なんか近いのを見たなぁこの黒魔術な感じ、と言うかさっきこの絶対やる必要のない遠まわりな感じの回答したよ。



さておき、今回の落ちが本編なのだが頭に書いた通り、直接文字列を列挙できる。
リスト内包は「リストを再リスト化」しかできないという理解だったが文字列を要素として一文字ずつ取り出すことができる。
上の式では一文字ずつ取り出し、カウンタを2で割ってあまりが0か1かで格納する値を決めて最後に空文字でリストを結合している。

というわけで、リスト内包はリストも文字列もリスト化できるという事でした。
これを書くのに長い毎ふりだったぜ・・・。




蛇足:
ただ、まぁもしもこういう感じにするならわざわざ0を判定するのはあれなので

print ''.join([v for k,v in enumerate(raw_input()) if not k%2])

こうでしょ?・・・いやまあこう言うのが可読性を落とす原因なんだけどね。
(値の返りが何と一致しているから処理されるという明示がなくなる為)
いやでもそもそもこの問題リスト内包してる時点で可読性激落ちですからね。

じゃあどうするのって話だがPythonですからそこは

print raw_input()[::2]

これだけでいいんですよ。

2015年10月7日水曜日

デフォPython高速化

Python2x系で数値読み込みループにinput()は使うな!

何故かと言うとinput()は式を求めているから。

数値を直接得るのに【 num=input() 】はメジャーな使い方である。
だが、これを数千数万とループで受ける場合話は別である。

最初に述べた通りinput()は式を求められている。
「つまりどういうこと?」と言う話だが
【 input() 】=【 eval(raw_input()) 】なのである。

たとえば300,000回程度forで数値入力の読み込みループを行い配列で受ける場合

=input()約2.1秒
=eval(raw_input())約2.1秒
=int(raw_input())約0.5秒

かなりおおざっぱな検証だがこれくらい差がでる。
【 input() 】と【 eval(raw_input()) 】が同じなのは同等の処理を行っているから当然の結果。
【 input() 】と【 int(raw_input()) 】では【 input() 】の方が簡潔に見えるが行わる処理は遠まわりしている事になる。
結果的に2倍以上の差が発生する。
※ちなみにintでは端数切捨てなのでそこは注意。


そもそも読み込みループを行うな!

何故かと言うとPython自体がもうループ処理自体が遅い。
「じゃぁどうするんだよ!」確かにそう言うのも仕方がない。

だが標準入力はほかにもある事を思い出してほしい。
具体的にはには以下のようにする。

import sys
mylist=list(map(int, sys.stdin.read().splitlines()))

readで連続で受け取りsplitlinesで分割。それをさらにmapを使い一括でintに変換する。
どれくらい早くなるのかというと

約0.17秒!int(raw_input())のさらに倍以上早い。
ただし、これは実際のケースではそんなにないのではないかと思う。
この問題に気付かされたのはPOHなので課題専用処理と言っていい。


ループはwhileよりもforを使え!

ループ回数が増える程whileよりもforのほうが処理速度が速い。
処理は処理として使いやすい方を使うのが正しいが処理速度がどうしても欲しい場合whileで行っている処理をforに置き換える事を検討すると良い。



リスト化はリスト内包を使え!

通常forでリストを追加する場合appendをチェックしている。
だがリスト内包を使った場合はリスト化前提の為その処理がない分速い。
しかもその処理時間は6割程度違う。つまり、通常forでリスト化して10秒ならリスト内包なら4秒で終わらせる事が出来る。

とにかく要素追加が遅いという事。逆にリスト等の要素追加でなければここまで差はでない。
ただしmap等forすら回さなくて良い場合はそちらの方が速い。

ループカウンタが不要なら[None]*数値を使え!

forの構造上値を渡しながらループする事になる。
通常であれば
【 for x in range(数値) 】だが、それよりも
【 for x in[0]*数値 】の方が速く、さらにそれよりも
【 for x in[None]*数値 】とした方が速い。

あくまでも大量のループを回すときにに空のリスト生成の方が速いという事。
ただし、rangeと[0]では割とさが出る様だが[0]と[None]では大きな差は無い。

ソートするならlist.sort()を使え!

自身を並べ替える為list.sort()はsorted()よりも若干ですが効率が良いです。
list.sort()の戻り値はNoneでsorted()との混乱を回避する為らしい。
といっても受けた値をソートできる為sorted()使っちゃうよなぁ。







後で追記する

2015年10月6日火曜日

Pythonは黒魔術であってはならない・・・だが

まぁもちろん魔術というのは揶揄した言い方なのですが今回コードゴルフでなるほろーと思ったこととか。

Pythonとは

Pythonはリーダビリティ(可読性)特化言語である。
その為、普通に打ち込みを行っている分にはみなが均一に読みやすいコードになり改修も楽で自身が忘れたコードでも読み返して見やすいそういう作りの言語です。

だが・・・黒魔術はなくならない。

ここで言う黒魔術はリーダビリティを失った何が書いてあるのかぱっと見ではわからないコードの事を指します。
黒魔術の主成分は主にワンライナーとコードゴルフです。
これに特化する事で新たな発見や効率化を生み出しますが基本的には何が書いてあるか解り難い魔術言語となります。
特にRubyは上級黒魔術と言っていいでしょう(何あれ?ホントぱっとみなんだか意味不明)。

と、どうでもいい前置きでしたが、つまりはPythonでも言語方針に反しリーダビリティを投げ捨て、さらには処理速度すら投げ捨ててでも暗黒面に身を染めようじゃないか!というお話。



私は初めからPython 3x系で独学したためほとんどPython 2x系との違いなんて気にしたことがありませんでした。
知ってた違いは
・2系ではxrangeの方が処理が早く、3系ではデフォルトでrangeは2のxrengeの処理で行われる。
・関数等が【 ()括弧 】が必須で2系では【print "aa"】とできたが3系では【print("aa")】でなければエラー
・2系のraw_input()は3系ではinput()になった
程度です。なのでまさか2系に「input()」があるとは・・・閑話休題。


コードテクニック

では闇Python黒魔術を始めましょう。
と言っても「or・and」あたりは胡散臭い処理ですがそれ以外はわりと普通のコードテクだったりします。
また、主にPython 2x系の話となります。

1.使いまわす関数を減らす

Pythonでは関数を変数に代入する事でその変数を関数として使う事が出来ます。
【i=raw_input】と定義すれば今後【i()】だけで呼び出せるのです。

たとえばraw_input()を2回以上使う場合4byte違いがでます。
p=raw_input;a=p();b=p()
a=raw_input();b=raw_input()

rangeの場合は2回では同byteですがメインコードが薄くなります。
r=range;a=r(6);b=r(9)
a=range(6);b=range(9)

intでは2回程度では2byte損です。
int=i;a=i("10");b=i("10")
a=int("10");b=int("10")

2.input()とraw_input()の違いを知る

これは完全にPython 2x系の話になります
input()とraw_input()の違いはinput()は式をそのまま評価します。
【input()】は【eval(raw_input()) 】とするのと同じです。
入力される式が正しくないとエラーが複数発生したり扱いが少し難しいですが入力が文字か数値かだけの場合【input()】で数値として値を受け取る事が可能になります。

今回の様に一度目のみ数値の入力、二回目以降は文字列等の場合かつその数値は数値として受け取りたい場合に非常に有益です。

一度目の入力を数値の5、二度目の入力が文字列”ABC”であれば
使い分けた場合23byte、通常のままの場合32byte、一文字定義で26byteとなり、使い分けた場合が最短になります。

a=input();b=raw_input()
a=int(raw_input());b=raw_input()
p=raw_input;int(i());b=i()

3.暗黙型変換と評価で格納値を変える

暗黙の型変換はifなどの評価において0をfalse、0以外の数値(not 0)がtrueになります。
また、空文字「""」はfalse、文字に値がある場合trueとなります。
それと同時に、リスト番号での評価式はfalseが0となり、trueが1になります。


・数値や文字列がboolで処理される

if 0:print"表示" #表示されない
if 1:print"表示" #表示される
if "":print"表示" #表示されない
if "a":print"表示" #表示される


・評価が値数値で処理される

print ("A","B")[true] #Bが表示される
print ("A","B")[false] #Aが表示される


4.orとandの遅延評価でifを減らす

主に行数を減らすワンライナー向け

orは「どちらか条件ならば」であり処理は左から行われる。
つまり、左が条件に達した時点て確定する。
逆に左がfalseで場合右が値として確定する。

True or "a"
上では左がTrueで確定しTrueとなり、後ろが評価されない。

False or "a"
上では左がfalseとなり"a"が値として確定する。


andはorの逆で「両方が条件ならば」であり同じく左から処理される。
つまり、左が条件に達せない場合後続は処理されない。

True and "a"
上では左がTrueの次の評価に入り"a"が値として確定する。

False and "a"
上では左がFalseであり、その後ろは評価されない。


ifの代わりに使う場合はこのようになる
条件 and True時 or False時


5.リストや配列追加にappend等を使わない

a=[];a.append("ABC")
ではなく

a=[];a+=["abc"]
と記述すれば5byte短くなる

6.処理系以外はセミコロンで並べる

行にif・for・whileが無いなら【 ; 】セミコロンで処理を並べる事が出来る。
だが、リスト内包表現は代入式の為セミコロンで並べる事が出来る。


7.複数の同じ内容の初期化

a=0;b=0;c=0 #これよりも
a,b,c=0,0,0 #これよりも
 a=b=c=0  #こう
 a=b=c="" #文字列ならこう

 a,b,c='1','2','3' #文字限定でよりも
a,b,c='123'      #こう

8.exec('処理'*数値)でループの代替をする

ループ速度と言うか繰り返し実行速度が有益か怪しいが普通にループ処理を書くより短くなる。
また、文字列として処理が入る為一行で書くことが可能になる。

a=0
for x in[None]*10:print(a);a+=1

a=0;exec('print(a);a+=1'*10)

この様に書ける。forがなくなる事でaの初期化をセミコロンで処理を後続に並べる事も出来る。
【 '処理' 】を連続で投げている事になる。
execはきた文字列を処理として展開実行する。
これにより疑似ループが完成するがスコープ周りなど注意が必要。

9.カウンタ無ループfor x in[0]*数値

ル―プカウンタが不要なら

for x in[0]*数値

とする。
inの後に【 [ 】を隣接することで1byte短くなるし、0リスト生成は処理も速い。
ただし[None]*nの方が最速。







後で追記する

【lambda】無名関数さえあれば短くなるしワンライナーもry
【三項演算子】でif・elseを一行にさらに入れ子も
【リスト内包表現】再リスト化・抜出し。for系なのに代入式なので「;(セミコロン)」でつなげる事も可能
【リスト内包表現が1つの場合両端の[]を消しても良い?】


最後に

それ、Pythonじゃなくていいよね?
処理速度ならC++、コード圧縮したい(とにかく短く書きたい)ならRubyで書きませんか?

やっぱり邪道なのです。
折角このPythonという言語自体がリーダビリティをが良いのこれを失わせるなんてとんでもない。
・・・だが(以下ループ)

以上です。