12A猫で学んだこと-Memoir-

...What are you learning now?

鳴かずー飛ばずー

こんにちは。StudentSです。 Happy Happy Valentine day! の2月でしたねー!

さて....今月...何ができたか? と考えると、ちょっと悲しくなりますねー
もがいているはず。足掻いているはず...
目に見えなくても少しずつ、できることは増えていると思いたいですねー

最近、github投稿がほとんどないから、何かできたらなーとは思っているのですが...
今やっていることがうまくいくといいなぁ....

今月がいい1か月になりますようにー!

人外2残り、5人昼、猫又潜伏の状況について、考察してみた話

こんにちは。StudentSです。年末は久しぶりにるる鯖に長く滞在させていただきました。
そして、他のサーバーの村のログを読んだり観戦させていただいたりしました。
感想戦で穏やかな方が多い大人数村は面白いですね!
ゲーム特有の状況や個人の趣味趣向と、客観的な事実とを区別して指南してくださるPLさんやGMさんが、私は好きです。

さて、2019年も2020年も1つは人狼関連のエントリを入れることに成功しました。
今回のエントリの結論は、猫又村に慣れている人であれば、採用する戦略としてはほぼ自明な類のものかな、と思います。
ただ、本当に成立するかどうかは少し不確かなところがある、というのが感触でした。
そのもやもやを確かめた、というのが今月の内容です。

導入と結論

このエントリでは、下記のことを主張します。

人外2残り、5人昼、内訳は(露呈してる狂狼)狼猫村村。 猫又潜伏。
この時の村の最善戦略は、黙って、露呈している人外投票することになりそう
シンプルな仮定に基づく解析の結果、本戦略によって村勝率66%を確保できる。

議論の大筋としては、露呈している人外が、確定狂人であったとしても、
(グレー吊りではなく) 猫又潜伏の方が よさそう ということを示すことで、 上記主張を作っています。

よさそう というのが、曖昧な表現となってしまい悲しいのですが、
真面目に考えると本問題はかなり難しくなることを感じました。
その難しさを「COなしはそのまま吊る」というルールを仮定として導入することで、簡略化しています。 この点が、今回のエントリの議論の弱点です。

詳細

状況

  • 5人昼、(露呈している狂)狼猫村村の5生存、猫又潜伏

仮定

  • 吊り先を決めたとき、決定先がCO無しであれば、吊り先を変更することはできない
  • 発言等を考慮せず、CO状況が同じPLから、等しい確率で吊り先を選択する

[戦略A] 猫又潜伏のまま、狂人を吊る

村勝率は下記となる。

\begin{align} \frac{1}{3} + \frac{2}{3} \times \frac{1}{2} = \frac{2}{3}
\end{align}

[戦略B] グレーからの乱拓戦略を使った戦略

次の戦略を採用するものとする。

グレーから乱拓戦術で、吊り先を決める。乱拓で選んだ吊り先からCOがなかった場合、対象者を吊る。猫又COがあった場合、
- 1. 対抗猫のCOがあった場合、狂人を吊って最終日とする
- 2. 対抗猫のCOがない場合、グレー3拓を行って、続けば最終日とする

村陣営の勝率

[戦略B] において、村勝率$W$ は次のパラメータ$\alpha, \beta$ で決定される

  • [村陣営] 2猫又COがあった時に、最初に指定された猫又を吊る確率$\alpha$ (1-$\alpha$ で後からの猫又COを吊る)
  • [狼陣営] 真猫の猫又COがあった時に、対抗猫又COをする確率 $\beta$

この時、$W(\alpha, \beta)$ は下記となる。

\begin{align} W(\alpha, \beta) = \frac{2}{4} \times \frac{1}{2} + \frac{1}{4}\left( \beta\left((1-\alpha) + \frac{1}{2} \alpha \right) + \left(1 - \beta\right) \frac{2}{3} \right) + \frac{1}{4}\left( \alpha + \frac{1}{2}\left( 1 - \alpha \right)\right) \ = \frac{13}{24} + \frac{1}{8}\alpha + \frac{1}{12} \beta - \frac{1}{8}\alpha \beta
\end{align}

$\alpha, \beta$ について最大値、最小値を考えると、
$(\alpha, \beta) = (1, 1)$ の時、$\frac{15}{24}$となる。
この値は $\frac{2}{3}$ より小さいため、 上記設定においては、 [戦略A]の方が[戦略B] よりも優れているといえる。

あとがき

今回の議論のポイントは、

  • 「COなし」は村認定できるか?

という点です。

詳細の解析において、「COなし」を行うのは村陣営しかしないことになっています。 したがって、
(決定先がCO無しであった時に、吊り先を変えることができるという前提下であれば、)
「COなし」を言っているPLを村認定する、という戦略を村側が取ることで
(狼が確実に猫又COをするという前提下であれば、)
村勝率を $\frac{2}{3}$ より高められます。

しかし、当然「COなし」を100%村認定するという戦略を村側が採択すれば、
狼側も「COなし」という選択を取ることで、村勝率を下げられます。

より厳密な解析においては、この部分について、均衡解かどうかを調べていく必要があります。
これが、辛い。 原理的にはできると信じておりますが、
考えなければならないパラメータ数が増加してしまいました。

5人2W猫又2CO、狼の「組織票」を封じることで村勝率を1.2倍にできる

導入と結論

昼時間5人2W残り、猫又2COの状況から、猫又決め打ち ⇒ 最終日2グレー吊りの進行があります。
この際、

  • 村が投票を合わせられないと、組織票が可能な分、狼陣営が有利となる

という主張があります。

狼陣営の「組織票」に対する対抗策は以下があります。

  • 指定役生存時に吊る人を決定しておく
  • 吊り先をランダムに決め、決定者に全員が投票することを村側のプロトコルとして規定しておく。

などです。

しかし、実際の村ではあまり上記の作戦を採用する人をみません。
また、吊り先のランダム決定戦略は実際の村での同意を得るのは難しいでしょう。
したがって、自分も含め多くのプレイヤーは 組織票 の要素を容認して、ゲームの進行をしていることになります。

このエントリでは、次のことについて論じます。

  1. 5人2W猫又2COで、狼側の組織票の要素は狼有利に寄与するか?
  2. 組織票が狼有利に寄与するのであれば、どの程度の寄与があるのか?

パズルとして簡略化した問題を解くことで、

  1. に対する解は、Yes であること、
  2. に対する解は $\frac{1}{24}$ 、狼勝率を上げる(村勝率を下げる)

であることが分かります。 吊り先をランダムに決めたときの勝率は$\frac{1}{4}$なので、
組織票を使わせないことで、

\begin{align} \frac{\frac{1}{4}}{\frac{5}{24}} = \frac{6}{5}
\end{align}

だけ、村勝率を高めることができるとわかります。

StudentSとしては、この事実が分かれば十分です。
パズルの結果からどのようなことを考えるか、感じるかは、プレイヤーの選好次第です。
だけど、せっかくなので無理をして、今の自分の"好み"の主張を作るためこの事実を使ってみたいと思います。

最適戦略を目指さない私たち

プレイヤーに対して次の質問を投げかけることを想像します。

  1. ランダムで吊り先を決めるより、$\frac{1}{24}$以上の高い確率で人外を的中させ、また、他の村人陣営に対してそれを説得させることができますか?
    1. の解に対して、Yesの場合、その言明が正しいことを客観的に主張できますか?
  2. / 2. に対して、Yes という答えを投げかけられるPLは多くないと思っています。
    自分の答えは間違いなくNo です。

それにもかからず、ランダム吊り先決定戦略を取らないのは、
勝率を最重要視する立場からは不合理な行動をとっていることになります。

今の自分はそれでいいと思っているのです。
だって、「ゲームの過程を楽しむのが人狼ゲームに参加する目的」 だから。

ゲーム終了後「進行が悪かった」という過度な批判はバランスを欠きます。
だって、「自分たちが最適進行を取れない時」がたくさんあるのだから。

「ランダムで吊り先を決める」ことを「ゲームとして面白くない」からやらないのであれば、
感想戦で、「ゲームの面白さをなくす」ような暴言を使うことは、一貫性がないですよね!

...こんなところでしょうか。 かなり強引な論理展開も含んでおりますし、意図的に誇張表現にしています。
そもそも、パズルの事実と現実の村での戦略の対応付けの自由度は高いので
上記のような自分の主張が納得感を与えられることには大きな疑問の余地があります。

あとがき

非常に久しぶりに人狼のエントリを書いた気がします。
計算自体は、前にやったことの焼き直しになっているかもしれませんが、
昔よりも、文章を書くことは上手くなっている...といいなぁ と思っています。

導出の過程の中で気になっていることは、
「組織票の要因をなくしている」 = 「村側のPLが同じ人に投票できる」として扱っている点です。
この仮定についての反論は、いくつかあるような気がします。

さてさて、今年も1年お疲れ様でした。
Merry Christmas! 良いクリスマスをお過ごしください。
そして、来年が皆様にとって、よい1年になりますように!

詳細

問題

5人、猫又2CO(猫狼)、3グレー(狼狼村)の村勝率を求める。

組織票要因なしの場合 (吊り先ランダム選択、共通投票戦略)

猫又吊り -> グレー吊りでランダム選択戦略を採用する。

\displaystyle \frac{1}{2} \times \frac{1}{2} = \frac{1}{4}

より、村勝率 \displaystyle \frac{1}{4}

組織票要因を考慮した場合

  • 猫又吊り -> グレー吊りの順番で吊りを行う
  • 条件が対等なグレー・猫又CO者には、各プレイヤーがランダムに投票する
    • 重要な点は村人が同じPLではなく、異なるPLに投票する可能性がある点

上記仮定の下で、ゲームの勝率は以下の確率の設定(混合戦略の設定)で決まるとする。

狼陣営の戦略は

  • $a, 0 < a < 1$: 猫吊りの際、グレーの狼が真猫に投票する確率

村陣営(猫又)の戦略は

  • $b, \frac{1}{2} < b$ : 最終日、真猫に投票したグレーに投票する確率
備考

狼側の戦略の設定として、厳密には
4人夜、グレーの村人に真猫又投票者と狼猫又候補投票者がいた場合に、 「狼猫又候補投票者を噛む確率」を設定する必要がある。

しかし、$\frac{1}{2} < b$ の条件で考えると、
狼視点、常に狼猫又候補投票者噛みが良いという結論になるため省いた。

計算

勝率$W(a, b)$は下記の式となる。

\begin{align} W(a, b) = a \left( \frac{1}{4} b \right) + \left( 1 - a \right) \left( \frac{1}{4} \times \frac{1}{2} + \frac{1}{2} \left(1 - b\right) \right) \end{align}

$a$, $b$ について、偏微分をした結果は下記の通り。

\begin{align} \frac{\partial W}{\partial a} = \frac{3}{4} b - \frac{1}{2}, \end{align}

\begin{align} \frac{\partial W}{\partial b} = \frac{3}{4} a - \frac{1}{2}. \end{align}

したがって、

\begin{align} \min_a \left( \max_b W(a, b) \right) = \max_b \left( \min_a W(a, b) \right) = \frac{5}{24}.
\end{align}

(ナッシュ均衡点が、$(a, b)=(\frac{2}{3}, \frac{2}{3})$)

これが意味することは、
狼側が戦略を決定した後、村側が戦略を決定する という順番でも、
村側が戦略を決定した後、狼側が戦略を決定する という順番でも、
村勝率$\frac{5}{24}$ ということになる。

以上より、 組織票要因を考慮した場合のゲーム設定と、
組織票要因を考慮しない場合のゲーム設定での勝率の差は$\frac{1}{24}$であると算出できる。

今月は...

こんばんは! StudentSです。 今月は完全に冬眠の期間でした。

来月は、もう少しクリエイティブなこともできるといいなぁ...

来月が心と体が元気な1か月になりますようにー!

ハニカム構造をmatplotlibで書いてみた

占いCO! StudentSです。
真占いっぽく見えない挙動が多く見受けられますが、
これは、

  • 呪殺対応のために色々準備をしたり
  • 狐候補に〇を出さないように細心の注意を払ったり
  • 2000戦越えの仲間の狼からアドバイスをいただいる
    からではありません!!

素です
挙動不審だからといって、処刑などしないようにお願いします。 生存権を行使します!

さて、PyCheckIOに下記のような問題があり、matplotlibの練習も兼ねて、6角形の描画をやってみることにしました。

py.checkio.org

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import patches

def _range(p):
    assert p.ndim == 2 and p.shape[1] == 2
    xmin, ymin = np.min(p[:, 0]), np.min(p[:, 1])
    xmax, ymax = np.max(p[:, 0]), np.max(p[:, 1])
    return xmin, ymin, xmax, ymax


def make_hexagon(center, length):
    theta = np.arange(0, 6) * 2 * np.pi / 6
    x = np.cos(theta) * length
    y = np.sin(theta) * length
    xy = np.stack([x, y], axis=-1)
    xy = xy + np.array(center)
    return xy

def make_centers(length, n_row=9, n_column=27):
    """
    Return: dict.
        (row_index, column_index) -> ``center``.
    """
    result = dict()
    x, y = 0, 0
    for c in range(n_column):
        x =  3 / 2 * length * c
        y = 0 if c % 2 == 0 else np.sqrt(3) / 2 * length
        for r in range(n_row):
            y += np.sqrt(3) * length
            result[r, c] = (x, y)
    return result

if __name__ == "__main__":
    fig, ax = plt.subplots()
    centers = make_centers(1)
    r = [0, 0, 0, 0]
    for key, center in centers.items():
        p = make_hexagon(center, 1)
        xmin, ymin, xmax, ymax = _range(p)
        r[0] = min(xmin, r[0])
        r[1] = min(ymin, r[1])
        r[2] = max(xmax, r[2])
        r[3] = max(ymax, r[3])
        color = "C1" if (key[0] + key[1]) % 2 == 0 else "C2"
        patch = patches.Polygon(p, edgecolor="black", facecolor=color)
        ax.add_patch(patch)
    ax.set_xlim((r[0], r[2]))
    ax.set_ylim((r[1], r[3]))
    ax.add_patch(patch)
    ax.invert_yaxis()
    ax.tick_params(labelbottom=False, labeltop=False, labelleft=False)
    ax.set_aspect("equal")
    ax.set_title("Example of Hexagons.")
    fig.savefig("output.png", transparent=True)

f:id:StudentS:20191019164323p:plain

あまりエレガントなコードではないですが、とりあえず、ちょっと綺麗な図ができてよかったよかった。 PyCheckIOの問題はまだ解けていないので、これから頑張りますー

Happy Halloween! の季節ですね... 「お菓子をくれなきゃ、いたずらしますよ?」そんなおだやかな会話で、小さな幸せを積み重ねていける1月になりますように。

requests でシリアライズ化されたJSONを送信する時のポカミス

テーマ

requests モジュールでPOSTリクエストを送る時の json / data パラメータの違い

まとめ

  • json 文字列をPOSTリクエストとして送信したいとき
    • json パラメータにシリアライズ可能なオブジェクトを渡す
    • dataJSON文字列を渡すときには、ヘッダのContent-Type```をapplication/json`` を設定する

関連情報

  • requests.models.PreparedRequest.prepared_body が処理内容
    • ドキュメントに記載されている通りの処理

お茶目な失敗例

JSONシリアライズ化したオブジェクトを送りたいと思いつつ、 下記のようなことをやってしまっていたのが、今回調べた理由...

import json
import requests

target = {"key": "value"}

# dataに辞書型を渡したときにに、JSONではなく、``form-encoded`` となる
requests.post("http://localhost", data=target)

# 文字列として送信されてしまう
requests.post("http://localhost", json=json.dumps(target))

可愛い失敗でした。 てへぺろ

2019年8月夏休みはまだ終わらない

こんばんは。StudentSです。
夏、暑いですね.... 体調に気をつけていきたいものです。

夏休みでも、vimを使うことは大切だと思っています... ちょっとずつでも、vimとの会話力は上がっていくはず....

最近、よく使うコマンドはこれですね...

  • :%s/\s*$//g

下記のリンク等で紹介されていますが、行末の空白やタブを削除するコマンドです。

vimで行末のタブやスペースの空白を削除する方法 - neovim/vim入門

markdown の文章を書くときに、改行をするために、2つのスペースを入れることが多く、
普通の文章を書く時にも、行末スペースが癖になってしまっていることがあります。
機械的に修正できるのは助かります...

vim力を高めることができれば、PCを使った活動が楽しくなると信じて....
vimを自信をもってつかえるようになりたい...

来月がいい一か月になりますようにー!
皆様も残暑にお気をつけくださいー!