LoginSignup
3
1

More than 3 years have passed since last update.

例のじゃんけん

Last updated at Posted at 2021-03-01

はじめに

if を使わずにじゃんけんします。
じゃんけんの結果はC#8の機能の switch式 を使って受け取ります。

先駆者様

個人ブログとのクロスポストです。

勝敗判定

じゃんけんのルールとして、-> の右側が強いものとすると、 Rock -> Paper -> Scissors -> Rock の関係性が成り立ち、3つの手を周期として勝敗が決まります。
ここで、Rock を0、Paper を1、Scissors を2として、関係性をそれぞれ1の距離を持った有効グラフだとすると、自分の手と相手の手の距離が1では負け、距離が2では勝ち、距離が0(3)ではあいこのような表現することができます。

rps_dia.png

このことから、相手の手 - 自分の手 を計算することで距離を求めることができます。
しかし、自分の手が2で、相手の手が0だった場合、0 - 2 == -2のように、距離が負数になってしまいます。このとき、じゃんけんは3つの手を周期としているため、自分の手や相手の手を3つ移動させたところで手は変わらず、勝敗は変わりません。つまり、距離に3を足したり、3で剰余を取ったとしても勝敗は変わりません。このことから、(相手の手 - 自分の手 + 3) % 3 とすることで、距離を0、1、2の3つにすることができ、負数と3以上になることを避けることができます。

実装

Rps (じゃんけん) クラスに Hand (グー、チョキ、パー) と Result (引き分け、負け、勝ち) の enum を定義することで、Battle 関数の引数と戻り値にそれぞれ意味を持たせます。

C#の enum は、既定値として int の0をとり、要素が増えるにつれて1増えます。そのため、この場合は、 Rock (0)Paper (1)Scissors (2) のようにそれぞれ値を持つことができます。

Battle 関数は、自分の手と相手の手を渡すことで、Result.DrawResult.LoseResult.Win のいずれかを返します。

public static class Rps
{
    public enum Hand
    {
        Rock,
        Paper,
        Scissors
    }

    public enum Result
    {
        Draw,
        Lose,
        Win
    }

    public static Result Battle(Hand own, Hand opponent)
    {
        var result = ((int)opponent - (int)own + 3) % 3;
        return (Result)result;
    }
}

呼び出し側では、例に倣ってそれぞれの絵文字を割り当てます。
switch式 を使うことで、Battle が返す可能性のあるパターンに、 あいこあなたの負けあなたの勝ち を割り当て、一致した要素を result として受け、自分の手、相手の手と一緒に表示します。 _ => throw new ArgumentOutOfRangeException() では、対象となる値以外の値として判定された際に該当するアームになります。

public static class Program
{
    public static void Main()
    {
        const string draw = "あいこ";
        const string lose = "あなたの負け";
        const string win = "あなたの勝ち";

        var map = new Dictionary<Rps.Hand, string>
        {
            [Rps.Hand.Rock] = "✊", [Rps.Hand.Paper] = "🖐", [Rps.Hand.Scissors] = "✌"
        };

        // var hands = new[] { Rps.Hand.Rock, Rps.Hand.Paper, Rps.Hand.Scissors };
        var hands = Enum.GetValues(typeof(Rps.Hand)).Cast<Rps.Hand>().ToArray();

        foreach (var own in hands)
        foreach (var opponent in hands)
        {
            // Draw, Lose, Winのままなら
            // var result = Rps.Battle(own, opponent).ToString();

            var result = Rps.Battle(own, opponent) switch
            {
                Rps.Result.Draw => draw,
                Rps.Result.Lose => lose,
                Rps.Result.Win => win,
                _ => throw new ArgumentOutOfRangeException()
            };
            Console.WriteLine($"{map[own]} vs {map[opponent]}: {result}");
        }
    }
}

実行結果

rps.png

3
1
0

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
3
1