概要
Strategy パターンは、アルゴリズムを容易に入れ替えられる、デザインパターンの一つである。
ソースコード
Hand.m
classdef Hand < handle
properties (Access = public, Constant)
HANDVALUE_GUU(1,1) double {mustBeInteger} = 0;
HANDVALUE_CHO(1,1) double {mustBeInteger} = 1;
HANDVALUE_PAA(1,1) double {mustBeInteger} = 2;
hand(1,3) Hand = [...
Hand(Hand.HANDVALUE_GUU),...
Hand(Hand.HANDVALUE_CHO),...
Hand(Hand.HANDVALUE_PAA)...
];
end
properties (Access = private, Constant)
name(1,3) cell = {
'グー',...
'チョキ',...
'パー',...
};
end
properties (Access = private)
handvalue(1,1) double {mustBeInteger};
end
methods (Access = private)
function obj = Hand(handvalue)
arguments (Input)
handvalue(1,1) double {mustBeInteger}
end
arguments (Output)
obj(1,1) Hand
end
obj.handvalue = handvalue;
end
function out = fight(obj, h)
arguments (Input)
obj(1,1) Hand
h(1,1) Hand
end
arguments (Output)
out(1,1) double {mustBeInteger}
end
if obj.handvalue == h.handvalue
out = 0;
elseif rem((obj.handvalue + 1), 3) == h.handvalue
out = 1;
else
out = -1;
end
end
end
methods (Access = public, Static)
function out = getHand(handvalue)
arguments (Input)
handvalue(1,1) double {mustBeInteger}
end
arguments (Output)
out(1,1) Hand
end
out = Hand.hand(handvalue);
end
end
methods (Access = public)
function out = isStrongerThan(obj, h)
arguments (Input)
obj(1,1) Hand
h(1,1) Hand
end
arguments (Output)
out(1,1) logical
end
out = obj.fight(h) == 1;
end
function out = isWeakerThan(obj, h)
arguments (Input)
obj(1,1) Hand
h(1,1) Hand
end
arguments (Output)
out(1,1) logical
end
out = obj.fight(h) == -1;
end
function out = toString(obj)
arguments (Input)
obj(1,1) Hand
end
arguments (Output)
out(1,:) char {mustBeTextScalar}
end
out = Hand.name{obj.handvalue};
end
end
end
Strategy.m
classdef (Abstract) Strategy < handle
methods (Access = public, Abstract)
out = nextHand(obj)
study(obj, win)
end
end
WinningStrategy.m
classdef WinningStrategy < Strategy
properties (Access = private)
random(1,1) RandStream = matlab.lang.invalidHandle('RandStream')
won(1,1) logical = false
prevHand(1,1) Hand = matlab.lang.invalidHandle('Hand')
end
methods (Access = public)
function obj = WinningStrategy(seed)
arguments (Input)
seed(1,1) double {mustBeInteger}
end
arguments (Output)
obj(1,1) WinningStrategy
end
obj.random = RandStream('twister', 'Seed', seed);
end
function out = nextHand(obj)
arguments (Input)
obj(1,1) WinningStrategy
end
arguments (Output)
out(1,1) Hand
end
if ~obj.won
obj.prevHand = Hand.getHand(randi(obj.random, length(Hand.hand)));
end
out = obj.prevHand;
end
function study(obj, win)
obj.won = win;
end
end
end
ProbStrategy.m
classdef ProbStrategy < Strategy
properties (Access = private)
random(1,1) RandStream = matlab.lang.invalidHandle('RandStream')
prevHandValue(1,1) double {mustBeInteger} = 1
currentHandValue(1,1) double {mustBeInteger} = 1
history(3,3) double {mustBeInteger} = [...
[1, 1, 1];...
[1, 1, 1];...
[1, 1, 1];...
]
end
methods (Access = public)
function obj = ProbStrategy(seed)
arguments (Input)
seed(1,1) double {mustBeInteger}
end
arguments (Output)
obj(1,1) ProbStrategy
end
obj.random = RandStream('twister', 'Seed', seed);
end
function out = nextHand(obj)
arguments (Input)
obj(1,1) ProbStrategy
end
arguments (Output)
out(1,1) Hand
end
bet = randi(obj.random, obj.getSum(obj.currentHandValue));
if bet <= obj.history(obj.currentHandValue, 1)
handvalue = 1;
elseif bet <= obj.history(obj.currentHandValue, 1) + obj.history(obj.currentHandValue, 2)
handvalue = 2;
else
handvalue = 3;
end
obj.prevHandValue = obj.currentHandValue;
obj.currentHandValue = handvalue;
out = Hand.getHand(handvalue);
end
function study(obj, win)
if (win)
obj.history(obj.prevHandValue, obj.currentHandValue) = obj.history(obj.prevHandValue, obj.currentHandValue) + 1;
else
obj.history(obj.prevHandValue, rem(obj.currentHandValue, 3) + 1) = obj.history(obj.prevHandValue, rem(obj.currentHandValue, 3) + 1) + 1;
obj.history(obj.prevHandValue, rem(obj.currentHandValue + 1, 3) + 1) = obj.history(obj.prevHandValue, rem(obj.currentHandValue + 1, 3) + 1) + 1;
end
end
end
methods (Access = private)
function out = getSum(obj, hv)
out = 0;
for k = 1:3
out = out + obj.history(hv, k);
end
end
end
end
Player.m
classdef Player < handle
properties (Access = private)
name(1,:) char
strategy %(1,1) Strategy = matlab.lang.invalidHandle('Strategy')
wincount(1,1) double
losecount(1,1) double
gamecount(1,1) double
end
methods (Access = public)
function obj = Player(name, strategy)
arguments (Input)
name(1,:) char
strategy(1,1) Strategy
end
arguments (Output)
obj(1,1) Player
end
obj.name = name;
obj.strategy = strategy;
end
function out = nextHand(obj)
arguments (Input)
obj(1,1) Player
end
arguments (Output)
out(1,1) Hand
end
out = obj.strategy.nextHand();
end
function win(obj)
arguments (Input)
obj(1,1) Player
end
obj.strategy.study(true);
obj.wincount = obj.wincount + 1;
obj.gamecount = obj.gamecount + 1;
end
function lose(obj)
arguments (Input)
obj(1,1) Player
end
obj.strategy.study(false);
obj.losecount = obj.losecount + 1;
obj.gamecount = obj.gamecount + 1;
end
function even(obj)
arguments (Input)
obj(1,1) Player
end
obj.gamecount = obj.gamecount + 1;
end
function out = toString(obj)
arguments (Input)
obj(1,1) Player
end
arguments (Output)
out(1,:) char
end
out = ['[', obj.name, ':', num2str(obj.gamecount), ' games, ', num2str(obj.wincount), ' win, ', num2str(obj.losecount), ' lose', ']'];
end
end
end
main.m
function main(randomseed1, randomseed2)
if nargin ~= 2
disp('Usage: main randomseed1 randomseed2');
disp('Example: main 314 15');
return;
end
seed1 = str2double(randomseed1);
seed2 = str2double(randomseed2);
player1 = Player('Taro', WinningStrategy(seed1));
player2 = Player('Hana', ProbStrategy(seed2));
for k = 1:10000
nextHand1 = player1.nextHand();
nextHand2 = player2.nextHand();
if nextHand1.isStrongerThan(nextHand2)
disp(['Winner: ', player1.toString()]);
player1.win();
player2.lose();
elseif nextHand2.isStrongerThan(nextHand1)
disp(['Winner: ', player2.toString()]);
player1.lose();
player2.win();
else
disp('Even...');
player1.even();
player2.even();
end
end
disp('Total result:');
disp(player1.toString());
disp(player2.toString());
実行結果
>> main 314 15
(中略)
Total result:
[Taro:10000 games, 3153 win, 3565 lose]
[Hana:10000 games, 3565 win, 3153 lose]