×

[PR]この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。

C#デザインパターン  - Strategy

ここに掲載したコードは、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』に掲載されているサンプルコードをC#に移植したものです。
解説らしい解説は載せていませんので、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』も合わせてお読みください。

※当ソースは、Visual C# 2008 Express Editionで動作を確認しています。
  Visual Studio 2005をお使いの方は、ブログの記事を残しておきますので、そちらをご覧ください。



■Hand.cs
using System;
using System.Collections.Generic;

namespace Gushwell.Design.Patterns {

    // このクラスはオリジナルとは大きく変更
    public struct Hand {
        public static readonly int GUU = 0; // グーを表す値
        public static readonly int CHO = 1; // チョキを表す値
        public static readonly int PAA = 2; // パーを表す値
        private static readonly string[] name = new string[] { "グー", "チョキ", "パー" };
        
        private int handvalue; // GUU, CHO, PAA が入る 

        // コンストラクタ (GUU, CHO,PAAを引数に渡す)
        public Hand(int handvalue) {
            if (handvalue < 0 || 2 < handvalue)
                throw new ArgumentException();
            this.handvalue = handvalue;
        }

        // handValueを返す
        public int Value {
            get { return handvalue; }
        }

        // グー、チョキ、パーを返す
        public string GetName() {
            return name[handvalue];
        }

        // このHnadに勝つ Handを得る
        public Hand StrongHand() {
            return (Hand)((handvalue + 2) % 3);
        }

        // 値からインスタンスを得る
        public static Hand GetHand(int handvalue) {
            return new Hand(handvalue);
        }

        // Handから intへの型変換
        public static implicit operator Int32(Hand hand) {
            return hand.handvalue;
        }

        // intからHnadへの型変換
        public static implicit operator Hand(int value) {
            return new Hand(value);
        }

        // Handを列挙するためのメソッド(循環)
        public Hand NextHand() {
            int value = handvalue + 1;
            if (value >= 3)
                value = 0;
            return new Hand(value);
        }

        // Handを列挙
        public static IEnumerable<Hand> GetValues() {
            yield return new Hand(GUU);
            yield return new Hand(CHO);
            yield return new Hand(PAA);
        }

        // thisがhより強いときtrue
        public bool IsStrongerThan(Hand h) {
            return Fight(h) == 1;
        }

        // thisがhより弱いときtrue
        public bool IsWeakerThan(Hand h) {
            return Fight(h) == -1;
        }

        // 引き分けは0, thisの勝ちなら1, hの勝ちなら-1
        private int Fight(Hand h) {
            if (this.Equals(h)) {
                return 0;
            } else if (this.Equals(h.StrongHand())) {
                return 1;
            } else {
                return -1;
            }
        }

        // 文字列表現へ変換
        public override string ToString() {
            return this.GetName();
        }


        public override bool Equals(object obj) {
            if (obj is Hand)
                return this.handvalue == ((Hand)obj).handvalue;
            return false;
        }

        public override int GetHashCode() {
            return this.handvalue.GetHashCode();
        }
    }
}



■IStrategy.cs
using System;

namespace Gushwell.Design.Patterns {

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


■WinningStrategy.cs
using System;

namespace Gushwell.Design.Patterns {

    public class WinningStrategy : IStrategy {
        private Random random;
        private bool won = false;
        private Hand prevHand;

        public WinningStrategy(int seed) {
            random = new Random(seed);
        }

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

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




■ProbStrategy.cs
using System;
using System.Linq;
using System.Collections.Generic;

namespace Gushwell.Design.Patterns {

    public class ProbStrategy : IStrategy {
        private Random random;
        private Hand prevHandValue = Hand.GUU;
        private Hand PrevHandValue {
            get { return prevHandValue; }
        }
        private Hand _currentHandValue = Hand.GUU;
        private Hand CurrentHandValue {
            get { return _currentHandValue; }
            set { _currentHandValue = value; }
        }

        private int[][] _history = new int[][] { new int[] { 1, 1, 1 }, 
                                                new int[] { 1, 1, 1 }, 
                                                new int[] { 1, 1, 1 } };

        public ProbStrategy(int seed) {
            random = new Random(seed);
            foreach (var hv1 in Hand.GetValues())
                foreach (var hv2 in Hand.GetValues())
                    _history[hv1][hv2] = 1;
        }

        public virtual Hand NextHand() {
            int bet = random.Next(GetSum(CurrentHandValue));
            Hand handvalue = Hand.GUU;
            if (bet < _history[CurrentHandValue][Hand.GUU]) {
                handvalue = Hand.GUU;
            } else if (bet < _history[CurrentHandValue][Hand.GUU] + _history[CurrentHandValue][Hand.CHO]) {
                handvalue = Hand.CHO;
            } else {
                handvalue = Hand.PAA;
            }
            prevHandValue = CurrentHandValue;
            CurrentHandValue = handvalue;
            return new Hand(handvalue);
        }

        private int GetSum(Hand hv) {
            return _history[hv].Sum();
        }

        public virtual void Study(bool win) {
            if (win) {
                _history[PrevHandValue][CurrentHandValue]++;
            } else {
                _history[PrevHandValue][CurrentHandValue.NextHand()]++;
                _history[PrevHandValue][CurrentHandValue.NextHand().NextHand()]++;
            }
        }
    }
}


■Player.cs
using System;

namespace Gushwell.Design.Patterns {

    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 virtual Hand NextHand() {
            return strategy.NextHand();
        }

        // 勝った
        public virtual void Win() {
            strategy.Study(true);
            wincount++;
            gamecount++;
        }

        // 負けた
        public virtual void Lose() {
            strategy.Study(false);
            losecount++;
            gamecount++;
        }

        // 引き分け
        public virtual void Even() {
            gamecount++;
        }

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




■Program.cs
using System;

namespace Gushwell.Design.Patterns {

    public class Program {
        [STAThread]
        public static void Main(string[] args) {
            if (args.Length != 2) {
                Console.WriteLine("Usage: StrategySample randomseed1 randomseed2");
                Console.WriteLine("Example: StrategySample 314 15");
                return;
            }

            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 < 1000; i++) {
                Hand nextHand1 = player1.NextHand();
                Hand nextHand2 = player2.NextHand();
                Console.WriteLine("{0} {1}", nextHand1.ToString(), nextHand2.ToString());
                if (nextHand1.IsStrongerThan(nextHand2)) {
                    player1.Win();
                    player2.Lose();
                    Console.WriteLine("Winner:" + player1);
                } else if (nextHand2.IsStrongerThan(nextHand1)) {
                    player1.Lose();
                    player2.Win();
                    Console.WriteLine("Winner:" + player2);
                } else {
                    player1.Even();
                    player2.Even();
                    Console.WriteLine("Even...");
                }
            }

            Console.WriteLine("Total result:");
            Console.WriteLine(player1.ToString());
            Console.WriteLine(player2.ToString());
        }
    }
}