LoginSignup
10
3

More than 1 year has passed since last update.

複素数を用いたジャンケン実装

Last updated at Posted at 2022-01-08

最初にコード全体

import cmath

_2pi = 2 * cmath.pi
ROCK = 1
SCISSORS = complex(cmath.cos(_2pi/3), cmath.sin(_2pi/3))
PAPER = complex(cmath.cos(-_2pi/3), cmath.sin(-_2pi/3))


def judge(one, another):
    arg = cmath.phase(another / one)
    if arg == 0:
        return "あいこ"
    elif arg > 0:
        return "勝ち"
    else:
        return "負け"

テストコード
def test():
    assert "勝ち" == judge(ROCK, SCISSORS)
    assert "勝ち" == judge(SCISSORS, PAPER)
    assert "勝ち" == judge(PAPER, ROCK)
    assert "負け" == judge(SCISSORS, ROCK)
    assert "負け" == judge(PAPER, SCISSORS)
    assert "負け" == judge(ROCK, PAPER)
    assert "あいこ" == judge(ROCK, ROCK)
    assert "あいこ" == judge(SCISSORS, SCISSORS)
    assert "あいこ" == judge(PAPER, PAPER)

解説

そもそも複素数を導入したモチベは、円上に✊✌✋を配置すれば三つ巴の強弱関係をうまいこと表現できるのではと思ったからである。

complex型(複素数)で定義しているROCK, SCISSORS , PAPER(それぞれ ✊, ✌, ✋)を複素平面上に図示すると下図のようになる。

\begin{align}
\text{ROCK} &= 1 \\
\text{SCISSORS} &= \cos\left( \frac{2\pi}{3} \right) + i \sin\left( \frac{2\pi}{3} \right) \\
\text{PAPER} &= \cos\left( -\frac{2\pi}{3} \right) + i \sin\left( -\frac{2\pi}{3} \right)
\end{align}
勝ち 負け

これを反時計回りすると「✊は✌に勝ち、✌は✋に勝ち、✋は✊に勝つ」という勝ちパターンが現れ、逆に時計回りすると「✊は✋に負け、✋は✌に負け、✌は✊に負ける」という負けパターンが現れる。

ここで、✊を反時計回りに120°ずらすと✌になるので、✊から✌への偏角

$$ \arg \frac{\text{SCISSORS}}{\text{ROCK}}$$

+120°である。逆に、✌から✊への偏角

$$ \arg \frac{\text{ROCK}}{\text{SCISSORS}}$$

-120°である。
(一般的に、反時計回りはプラスの角度で、時計回りはマイナスの角度として扱われる。また、偏角の主値は $(-180°,~+180°]$ とする。)

つまり、以下の手順で分母にした変数の勝敗を知ることができる。

  1. 対決させたい変数同士で割り算する。
  2. 偏角をとる。
  3. プラスかマイナスかゼロかを判別する。
10
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
3