FC2ブログ

名もなき黒猫の散歩道

MENU

岩の世界へ -1. 岩波

こんにちは、黒猫です。8月はアメリカではバケーションの季節なこともあって、実は先週旅行へ行ってきました!金曜日夜にサンノゼ付近の知人の家に泊めさせてもらって、午前3時より出発しました。途中、


P8110021.jpg イヴァンパー・ソーラー・エレクトリック・ジェネレーティング・システムを通り過ぎ、

P8110025.jpg ラスベガスのトランプタワーを通り過ぎ、

P8110032.jpg 岩山を縫いくぐって着いたのは、

P8110041.jpg 大荒野!日本ではあり得ない地形と地平線の長さに、ただただ圧倒されるばかりでした。
ここまで12時間以上運転し(運転手の方々、本当にお疲れ様でした、ありがとうございました)、この日はこの近くのPageという街で宿泊。

そして翌日!

P8120067.jpg アンテロープキャニオン
今回の旅行の1つ目のポイントを楽しみました。
アンテロープは、upperとlowerと2種類のスポットがあり、
今回はupperへ向かいました。

アンテロープの入場には予約が必須なのですが、かなり人気が高く、前もって予約しないといけません。
今回はほぼ1週間前に、知人が予約することに偶然成功し、なんとか行けることになって良かったと、楽しみにしていました。
ところが!
なんと出発2, 3日前になって、「この予約はキャンセルにして欲しい」というありえないメールが届き、一気にどん底へ落とされたわけです。
ところが!笑
出発前日に黒猫が、別のupperツアーに空きができていることを偶然発見し、なんとか再び行けることになりました。前日に予約を取れるなんて普通はありえなくて、本当に人生の全ての運を使った気分でした 笑

そんな山あり谷あり山ありの経緯があって行ったupperのアンテロープでしたが、もう、絵の中にいるような気分でした。
P8120087.jpg P8120098.jpg P8120116.jpg P8120132.jpg 
2枚目の写真では、木の棒が引っかかっていたり泥が上の方に付いていたりしますが、これは、大雨が降った後におきる鉄砲水が、このアンテロープを流れるため、その時に流れてきた木の棒や泥が残っているのだそうです。いや、いま鉄砲水来たら死ぬやん、とは思いつつも、圧倒的な景観を楽しんでいました 笑

その後、

P8120158.jpg
グレンキャニオンダム周辺と、

P8120172.jpg ホースシューベンドを見に行きました。
アンテロープはおそらく一番良い時間よりは朝よりだったのですが、そのおかげでこのホースシューは一番良い時間に着くことができて、かなり満足でした。

その後少し走って、

P8120188.jpg ミティア・クレーター(バリンジャー・クレーター)というクレーターを見に行きました。
直径1.2 km 深さ200 mという大型のクレーターで、wikipediaによると、宇宙からの飛来物の衝突によって形成されたことが証明された地形は、このクレーターが初めてらしいです(つまり世界で初めて認められたクレーター)。ちなみに、隕石は鉄製で50 mくらいの大きさで、約5万年前に40,000 km/h 以上の速さで落下し、衝突時に半径3-4 km圏内の生物は即死したようです。なんと恐ろしい。。

そんな感じで各所巡りつつ次の街へ夜に到着し、一行は第2のポイントにたどり着きました。

というわけで次回へ続きます!ここまで読んで頂いてありがとうございました!

スポンサーサイト

じゃんけんを判定する [Python3]

こんにちは。黒猫です。今回はちゃんとPythonを解説したいと思います!

前回の記事で40人でじゃんけんをしてはいけないことがよくわかりました。今回の記事はちょっとプログラミング側の話で、じゃんけんの勝敗をどうやってPythonで判定するのが一番良いのかについて述べたいと思います。

え、何でそんなこと考えないといけないかって?
実は前回の記事のデータ、2〜40人すべての計算が終わるまでになんと1日以上かかっているのです!つまり、いい加減な方法で勝負判定していると、もっと時間がかかってしまって、大変なことになります。こういう地道な努力と気配りがプログラミングでは大事だったりするのです。

では考えていきましょう。
2人程度のじゃんけんをプログラムで認識させるのであれば、じゃんけんの優劣(グーはパーに負けてチョキに勝つ、など)を全て記載して、勝敗を判定させれば良いと思います。

しかしこの方法では、人数が増えてくるとたちまち計算量がハンパなくなってきます。(3人なら3C2 = 3回の勝負判定くらいですが、10人なら10C2 = 45回の勝負判定、20人なら20C2 = 190回の勝負判定、というようにだんだんと増えてくる)
しかも3人以上の時には2人では起こりえない「あいこ」、つまり全員違う手を出す、という可能性も考えねばなりません。

ですので、方法を少し考えないといけません。

じゃんけんで勝負が着くとは、簡単に言えば「あいこ」にならないことです。
「あいこ」とは、

  1.  全員同じ手を出している
  2.  「グー」「チョキ」「パー」が出揃っている

の2通りが考えられます。逆に考えれば、「グー」「チョキ」「パー」のうち、どれか2種類だけが出ていれば勝負が着いている、ということです。

なので、例えばグー、チョキ、パーをそれぞれa, b, cと略記して、例えば10人が出した手をaabbbccabcと表現してやれば、あとはこの文字列を分析して何種類の文字があるのかを調べればよいことになります。

というわけで、以下の3つの方法を考えました。

  1. 集合の要素数で判断
  2. if で場合分け
  3. stripで削る

1. 集合の要素数で判断

Pythonには、“集合 (set)”という概念があります。これは“お互いに異なるデータの集まり”という意味です。例えば、

{あ, い, う}、{10, 21, 32, 43, 54}、{A, 65, え, 猫}

みたいなものはすべて集合ですが、

{あ, い, う, あ}

は、"あ"が2つあるので集合ではありません。この場合は強制的に"あ"が1つ削除されて、{あ, い, う}に変換されます。これを使ってやれば、

{a, a, b, b, b, c, c, a, b, c} --> {a, b, c}
{a, a, b, b, b, a, a, a, b, a} --> {a, b}
{a, a, a, a, a, a, a, a, a, a} --> {a}

というように変換可能ですので、あとは集合のデータの種類数(集合の長さ)を調べてやれば、勝敗が決まったかどうかが分かりそうです(上の例だと2番目だけ勝負が着いている)。

というわけでPythonでこれを書くと以下のようになります。
s = "aabbbccabc"       # じゃんけんの手を示した文字列をsと命名
s_set = set(s)         # 文字列sを集合に変換
if len(s_set) == 2:    # 集合の長さ(LENgth)が2のとき
    print("勝負あり") 
else:                  # 集合の長さが2以外のとき
    print("あいこ")

2. if で場合分け

Pythonには、文字列に目的の文字があるかどうかを検索する方法があります。それを使えば、

if aがある -- yes --> if bがある -- yes --> if cがない -- yes --> 勝負あり
if aがある -- yes --> if bがある -- yes --> if cがない -- no --> あいこ
if aがある -- yes --> if bがある -- no --> if cがない -- no --> 勝負あり
if aがある -- yes --> if bがある -- no --> if cがない -- yes --> あいこ

のように場合分けすることで勝負が着いたかどうかを判断できそうです。というわけでPythonでこれを書くと以下のようになります。
s = "aabbbccabc"             # じゃんけんの手を示した文字列をsと命名
if "a" in s:                 # 文字列sの中に"a"はあるか?
    if "b" in s:             # 文字列sの中に"b"はあるか?
        if "c" not in s:     # 文字列sの中に"c"は無いか?
            print("勝負あり")
        else:                # 文字列sの中に"c"がある時
            print("あいこ") 
    elif "c" in s:           # 文字列sの中に"b"は無いが"c"はあるか?
        print("勝負あり")
    else:                    # 文字列sの中に"b"も"c"も無い
        print("あいこ")
elif "b" in s:               # 文字列sの中に"a"は無いが"b"はあるか?
    if "c" in s:             # 文字列sの中に"c"はあるか?
        print("勝負あり") 
    else:                    # 文字列sの中に"c"が無い時
        print("あいこ")
else:                        # 文字列sの中に"a"も"b"も無い
    print("あいこ") 

3. stripで区切る

Pythonには、ある文字を使って文字列の両端からその文字を引き剥がす(strip)方法があります。例えば以下のような感じです。

"aabaaaacabaaa" -- aでstrip --> "baaaacab" 
"aabaababbbbb" -- bでstrip --> "aabaaba" 
"aaaaaaaaaaaaa" -- aでstrip --> "" 

複数文字を使ってstripすることもできます。

"aabaaaacabaaa" -- aとbでstrip --> "c"
"aabaababbbbb" -- aとbでstrip --> ""
"aabaababbbbb" -- aとcでstrip --> "baababbbbb" 
"aaaaaaaaaaaaa" -- aとbでstrip --> ""
"aaaaaaaaaaaaa" -- aとcでstrip --> ""

この例からわかるように、もし文字列に2種類の文字しか含まれない場合、その2種類の文字でstripしてやった時にのみ、文字列から文字がなくなってしまう、ということがわかります。
これを使えば、stripした後の文字列の長さを数えることで、勝負が着いたかどうかを判定できそうです。というわけでPythonでこれを書くと以下のようになります。
s = "aabbbccabc"                # じゃんけんの手を示した文字列をsと命名
method = ["ab", "bc", "ca"]     # 異なる手のペア(全3組)
ans = []                        # 解析結果の一時保存場所
for i in method:                # methodから1組ずつ取り出して解析(iにab, bc, caのいずれかが代入される)
    p = s                       # コピー作成(元の文字列を変更しないよう)
    ans.append(len(p.strip(i))) # iをpからstripした後のpの文字数(LENgth)を一時保存
if ans.count(0) == 1:           # strip後に文字列pが消えた(文字数 = 0)ときが1回だけあるとき
    print("勝負あり") 
else:                           # 上記以外
    print("あいこ") 


検証
という感じでじゃんけん勝負判定メソッドを3つ用意しました。次は、この実行速度を測ります。これ以上説明を書くと長ったらしいので、測定に使用した本丸のコードは追記に載せます(勝負判定メソッド自体に変化はありません)。どうやってPython3でグラフを書くのかなど、気になる方は見て下さい。

今回は1000人でのじゃんけんを10000回(勝負が着くとは限らない)行って、1回あたりの処理に必要な時間を調べています。結果は以下のような感じになりました。
janken_speedtest.png  
というわけで2つ目の「if で場合分け」法が一番速い、ということが分かりました。他に比べて5倍以上速いですね。すばらしい!

この結果を基に、前回の記事でのシミュレーションはすべて、この「ifで場合分け」法を使って行っています。これでも1日かかるとは。。やはり40人でじゃんけんしてはいけませんね。。笑

実は黒猫は、一番はじめに3.のstripの方法を思いついて計算を開始したのですが、2日経っても計算が終わらなかったので、諦めて改善方法を探ることにしたのが、今回の発端でした。いやはや、プログラムの効率って本当に大事です。。痛感。。


そんな感じで、終わりたいと思います!
私の自己満足にお付き合い頂きありがとうございました!笑

クラスのみんなでじゃんけん [Python3]

こんにちは、黒猫です。もう20年くらい昔、小学生の黒猫はあることを思っていました。

この教室のみんなで一緒にじゃんけんしてみたい」と。

基本的に10人くらい集まってじゃんけんする時は、2人組をたくさん作ってじゃんけんして、その勝った人同士でまたじゃんけんする、というようなことを繰り返すと思います。もちろんこれは、大人数で同時にじゃんけんすると、勝者が決まるまでに時間がかかってしまうことを経験的に知っているためです。

では、もしもクラスの全員(40人)が一緒にじゃんけんをしたらどれくらい時間がかかるのでしょうか?これが今回解きたい問題です。

というわけでいつも通り、Pythonでシミュレーションしてみることにしました!
具体的なコードは次回の記事に書くとして(自己満です 笑)、さっそく結果に行きましょう!

下のグラフでは、横軸は“じゃんけんに参加した人数”、縦軸は“1回勝負が着く(あいこではなくなる)までにじゃんけんをした回数”を示します。各人数、100シミュレーション行って、その平均値を図示しました。
janken_result_100trial_2-40people_v3.png    
100回しかシミュレーションしていないので、かなりブレブレではありますが、だいたいこんな感じでした。というわけで、40人でじゃんけんして1回勝負が着くためには、約320万回かかるみたいですね!1回のじゃんけんに5秒かかるとしたら、1600万秒かかるので、寝食なんてせずに行ったとすれば、だいたい185日かかるみたいですね!は、半年だと。。

というわけで「40人でじゃんけんはやってはいけない」が答えです 笑
ちなみに、16人までを拡大してみるとこんな感じです。
janken_result_100trial_2-40people(upto16).png 
16人程度で既に200回近くかかるので、1勝負つくのに1000秒、つまり約15分かかることになります。まだまだ現実的に行うには厳しいですね。10人でやっと20回くらい、つまり1分半くらいなので、これならまだできるかな?という感じです。

ですので、今回のシミュレーションで、「じゃんけんを一度にするなら、多くても10人まで」ということがわかりました。是非日常生活(?)に役立てて下さい 笑

ではでは今回はこのあたりで。最後まで読んで下さりありがとうございました!プログラミングに興味がある方は、次回の記事も是非見て下さいね!

該当の記事は見つかりませんでした。