「増補改訂版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]
その他のデザインパターンは以下の記事から確認してください。