LoginSignup
4
2

More than 3 years have passed since last update.

(C#) if文なしでじゃんけん

Last updated at Posted at 2021-03-01

元ネタ

概要

剰余算(%)を活用して、if文なしでの 勝敗の判定 を行う。

剰余算(%)を活用すると、値を円環させた形で値を範囲内に丸めることが出来る。簡単で非常に便利で、応用方法もたくさんあるので、布教の意味も含めて兼ねて書いてみた。

剰余算による対戦結果表

ぶっちゃけExcelでテストした(笑)

player pc (cpu) calc result mod (result) output (label)
0 (✊) 0 (✊) 0 - 0 0 0 [0] あいこ
0 (✊) 1 (✌) 0 - 1 -1 2 [2] 勝ち
0 (✊) 2 (🖐) 0 - 2 -2 1 [1] 負け
1 (✌) 0 (✊) 1 - 0 1 1 [1] 負け
1 (✌) 1 (✌) 1 - 1 0 0 [0] あいこ
1 (✌) 2 (🖐) 1 - 2 -1 2 [2] 勝ち
2 (🖐) 0 (✊) 2 - 0 2 2 [2] 勝ち
2 (🖐) 1 (✌) 2 - 1 1 1 [1] 負け
2 (🖐) 2 (🖐) 2 - 2 0 0 [0] あいこ
  • 2つの手の差のベクトルを自然数に正規化して、テーブルにマッピングさせるイメージ。
  • あいこ負け勝ち、の3パターンのため、3の余りを求めて、0 ~ 2 に丸める。
  • マイナスの場合は 除数 を加えてプラス化さてから余りを求めることで、円環位置をズらさず丸める。

※ ExcelのMOD関数は、はなっからプラス側で値を返すとか、面倒くさいなお前。

ソース

ソース (ピックアップ)

ピックアップ
private static int GetResult(int palyer_hand, int pc_hand) {
    // (1) 基となる差を求める。
    int result = palyer_hand - pc_hand;
    // (2) 除数であまりを求め、±除数の範囲に収める。
    result %= 3;
    // (3) 除数を1回加えることでプラス化。
    result += 3;
    // (4) 再度除数であまりを求め、+除数の範囲に収める。
    result %= 3;
    return result;
}

ソース (全体)

@ri_ さんに倣って、入力想定文字列は グーチョキパー
@tadsan さんに習って、出力は絵文字に置き換え。
(+ 検証用に総当りで結果を出力)

C#
using System;
using System.Collections.Generic;

public class Hello{
    private static readonly Dictionary<string, int> HAND_CODE_DICT = new Dictionary<string, int>() {
        {"グー", 0},
        {"チョキ", 1},
        {"パー", 2},
    };
    private static readonly string[] HAND_LABELS = new string[] {"✊", "✌", "🖐"};
    private static readonly string[] RESULT_LABELS = new string[] {
        "あいこ",
        "あなたの負け",
        "あなたの勝ち"
    };

    private static int GetResult(int palyer_hand, int pc_hand) {
        int result = palyer_hand - pc_hand;
        // -3 < n < 3
        result %= 3;
        // 0 < n < 6
        result += 3;
        // 0 <= n < 3
        result %= 3;
        return result;
    }

    public static void Main(){
        // Your code here!
        System.Console.WriteLine("Hellow C#");

        foreach(string player_hand in new string[]{"グー", "チョキ", "パー"}) {
            foreach(string pc_hand in new string[]{"グー", "チョキ", "パー"}) {
                int player_hand_code = HAND_CODE_DICT[player_hand];
                int pc_hand_code = HAND_CODE_DICT[pc_hand];
                int result_code = GetResult(player_hand_code, pc_hand_code);
                System.Console.WriteLine(string.Format("[{0} v.s. {1}] {2}", new object[] {
                    HAND_LABELS[player_hand_code],
                    HAND_LABELS[pc_hand_code],
                    RESULT_LABELS[result_code],
                }));
            }
        }
    }
}
output
Hellow C#
[✊ v.s. ✊] あいこ
[✊ v.s. ✌] あなたの勝ち
[✊ v.s. 🖐] あなたの負け
[✌ v.s. ✊] あなたの負け
[✌ v.s. ✌] あいこ
[✌ v.s. 🖐] あなたの勝ち
[🖐 v.s. ✊] あなたの勝ち
[🖐 v.s. ✌] あなたの負け
[🖐 v.s. 🖐] あいこ

あとがき

剰余算の活用は、ゲーム系では昔から結構使われるんじゃないかな。シンプルな算術演算のためCPUコストも少なく。コードも複雑にはならないので、結構美味しいテクニック。

私が今まで剰余算をよく使ったのは。

  1. キャラクターのアニメーションのループ
  2. メニュー画面などでの、画面選択肢のループ
  3. キャラクターの向き(角度)のループ
  4. テーブル表示で行を交互に色付け

業務系ではあんま活用したいシーンがない様で。(4)で剰余算使っていたときに、年配のSEに驚かれたことがある。

なお、『連想配列はズルくない?』とも思ったけど、まぁご愛嬌で。(入力文字列をコード化するしてるだけだから許して)

そう言えば、『計算機は計算が得意』 で 『条件分岐は苦手』と言う定説は昔からあるけど。コスト的には何倍あるのだろう?:thinking:

4
2
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
4
2