「JAVA言語で学ぶデザインパターン入門」をC#で書いてみた【Strategyパターン】

「増補改訂版Java言語で学ぶデザインパターン入門」の「Strategyパターン」をC#で書いてみました。

GitHubにもコードを置いています。

参考 DesignPattern【Strategy】GitHub

コード


public enum HANDVALUE
{
    GUU,
    CHOKI,
    PAA,
}

public enum VICTORY_DEFEAT
{
    LOSE = -1,
    DRAW = 0,
    WIN = 1,
}

public class Hand
{
    public static readonly Hand[] Hands =
    {
        new Hand(HANDVALUE.GUU),
        new Hand(HANDVALUE.CHOKI),
        new Hand(HANDVALUE.PAA),
    };
    private static readonly string[] names = { "グー", "チョキ", "パー" };
    private HANDVALUE handvalue;
    private Hand(HANDVALUE handvalue)
    {
        this.handvalue = handvalue;
    }

    public static Hand GetHand(HANDVALUE handvalue)
    {
        return Hands[(int)handvalue];
    }

    public bool IsStrongerTan(Hand hand)
    {
        return Fight(hand) == VICTORY_DEFEAT.WIN;
    }

    public bool IsWeakerThan(Hand hand)
    {
        return Fight(hand) == VICTORY_DEFEAT.LOSE;
    }

    private VICTORY_DEFEAT Fight(Hand hand)
    {
        if (this == hand)
        {
            return VICTORY_DEFEAT.DRAW;
        }
        else if ((((int)this.handvalue) + 1) % 3 == (int)hand.handvalue)
        {
            return VICTORY_DEFEAT.WIN;
        }
        else
        {
            return VICTORY_DEFEAT.LOSE;
        }
    }

    public override string ToString()
    {
        return names[(int)handvalue];
    }
}

public interface IStrategy
{
    Hand NextHand();
    void Study(bool win);
}

public class WinningStrategy : IStrategy
{
    private Random random;
    private bool won = false;
    private Hand prevHand;
    public WinningStrategy(int seed)
    {
        random = new Random(seed);
    }

    public Hand NextHand()
    {
        if (!won)
        {
            prevHand = Hand.GetHand((HANDVALUE)random.Next(3));
        }
        return prevHand;
    }

    public void Study(bool win)
    {
        won = win;
    }
}

public class ProbStrategy : IStrategy
{
    private Random random;
    private HANDVALUE prebHandValue;
    private HANDVALUE currentHandValue;
    private int[,] history =
    {
        {1,1,1, },
        {1,1,1, },
        {1,1,1, },
    };
    public ProbStrategy(int seed)
    {
        random = new Random(seed);
    }

    public Hand NextHand()
    {
        int bet = random.Next(GetSum((int)currentHandValue));
        HANDVALUE handvalue;
        if (bet < history[(int)currentHandValue, 0])
        {
            handvalue = HANDVALUE.GUU;
        }
        else if (bet < history[(int)currentHandValue, 0] + history[(int)currentHandValue, 1])
        {
            handvalue = HANDVALUE.CHOKI;
        }
        else
        {
            handvalue = HANDVALUE.PAA;
        }
        prebHandValue = currentHandValue;
        currentHandValue = handvalue;
        return Hand.GetHand(handvalue);
    }

    public void Study(bool win)
    {
        if (win)
        {
            history[(int)prebHandValue, (int)currentHandValue]++;
        }
        else
        {
            history[(int)prebHandValue, ((int)currentHandValue + 1) % 3]++;
            history[(int)prebHandValue, ((int)currentHandValue + 2) % 3]++;
        }
    }

    private int GetSum(int hv)
    {
        int sum = 0;
        for (int i = 0; i < 3; i++)
        {
            sum += history[hv, i];
        }
        return sum;
    }
}

public class Player
{
    private string name;
    private IStrategy strategy;
    private int wincount;
    private int losecount;
    private int gamecount;
    public Player(string name, IStrategy strategy)
    {
        this.name = name;
        this.strategy = strategy;
    }

    public Hand NextHand()
    {
        return strategy.NextHand();
    }

    public void Win()
    {
        strategy.Study(true);
        wincount++;
        gamecount++;
    }

    public void Lose()
    {
        strategy.Study(false);
        losecount++;
        gamecount++;
    }

    public void Even()
    {
        gamecount++;
    }

    public override string ToString()
    {
        return $"[{name}:{gamecount} games, {wincount} win, {losecount} lose]";
    }
}

class Program
{
    static void Main(string[] args)
    {
        if (args.Length != 2)
        {
            Console.WriteLine("Usage: dotnet Strategy Randomseed1 Randomseed2");
            Console.WriteLine("Example: dotnet Strategy 314 15");
            Environment.Exit(0);
        }
        int seed1 = int.Parse(args[0]);
        int seed2 = int.Parse(args[1]);
        Player player1 = new Player("Taro", new WinningStrategy(seed1));
        Player player2 = new Player("Hana", new ProbStrategy(seed2));
        for (int i = 0; i < 10; i++)
        {
            Hand nextHand1 = player1.NextHand();
            Hand nextHand2 = player2.NextHand();
            if (nextHand1.IsStrongerTan(nextHand2))
            {
                Console.WriteLine($"Winner:{player1}");
                player1.Win();
                player2.Lose();
            }
            else if (nextHand2.IsStrongerTan(nextHand1))
            {
                Console.WriteLine($"Winner:{player2}");
                player1.Lose();
                player2.Win();
            }
            else
            {
                Console.WriteLine("Even...");
                player1.Even();
                player2.Even();
            }
        }
        Console.WriteLine("Total result:");
        Console.WriteLine(player1.ToString());
        Console.WriteLine(player2.ToString());
    }
}

実行結果は以下のようになります。

$dotnet Strategy.dll 314 15

Winner:[Hana:0 games, 0 win, 0 lose]
Winner:[Taro:1 games, 0 win, 1 lose]
Winner:[Hana:2 games, 1 win, 1 lose]
Winner:[Hana:3 games, 2 win, 1 lose]
Winner:[Taro:4 games, 1 win, 3 lose]
Even...
Winner:[Taro:6 games, 2 win, 3 lose]
Winner:[Taro:7 games, 3 win, 3 lose]
Even...
Winner:[Taro:9 games, 4 win, 3 lose]
(中略)
Even...
Winner:[Taro:990 games, 285 win, 376 lose]
Winner:[Taro:991 games, 286 win, 376 lose]
Winner:[Hana:992 games, 376 win, 287 lose]
Even...
Winner:[Hana:994 games, 377 win, 287 lose]
Winner:[Hana:995 games, 378 win, 287 lose]
Even...
Winner:[Taro:997 games, 287 win, 379 lose]
Winner:[Hana:998 games, 379 win, 288 lose]
Even...
Total result:
[Taro:1000 games, 288 win, 380 lose]
[Hana:1000 games, 380 win, 288 lose]

その他のデザインパターンは以下の記事から確認してください。

「JAVA言語で学ぶデザインパターン入門」をC#で書いてみた【一覧】

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA