📓
Strategyパターンを学ぶ【Python】
一言で言うと
簡単に別の種類のConcreteStrategy(具体的な戦略)に変更できる。
コードサンプル
ディレクトリ構造
strategy_pattern
├── hand.py
├── main.py
├── player.py
├── prob_strategy.py
├── strategy.py
└── winning_strategy.py
main.py
import sys
from player import Player
from prob_strategy import ProbStrategy
from hand import Hand
from winning_strategy import WinningStrategy
def main() -> None:
args = sys.argv
if len(args) != 3:
print('python main randomseed1 randomseed2')
exit(0)
seed1: int = int(args[1])
seed2: int = int(args[2])
player1: Player = Player('Taro', WinningStrategy(seed1))
player2: Player = Player('Hana', ProbStrategy(seed2))
for _ in range(10):
next_hand1: Hand = player1.next_hand()
next_hand2: Hand = player2.next_hand()
if next_hand1.is_stronger_than(next_hand2):
print(f'Winner:{player1}')
player1.win()
player2.lose()
elif next_hand1.is_weeker_than(next_hand2):
print(f'Winner:{player2}')
player1.lose()
player2.win()
else:
print('Even...')
player1.even()
player2.even()
print('Total result:')
print(player1)
print(player2)
if __name__ == '__main__':
main()
hand.py
import sys
from player import Player
from prob_strategy import ProbStrategy
from hand import Hand
from winning_strategy import WinningStrategy
def main() -> None:
args = sys.argv
if len(args) != 3:
print('python main randomseed1 randomseed2')
exit(0)
seed1: int = int(args[1])
seed2: int = int(args[2])
player1: Player = Player('Taro', WinningStrategy(seed1))
player2: Player = Player('Hana', ProbStrategy(seed2))
for _ in range(10):
next_hand1: Hand = player1.next_hand()
next_hand2: Hand = player2.next_hand()
if next_hand1.is_stronger_than(next_hand2):
print(f'Winner:{player1}')
player1.win()
player2.lose()
elif next_hand1.is_weeker_than(next_hand2):
print(f'Winner:{player2}')
player1.lose()
player2.win()
else:
print('Even...')
player1.even()
player2.even()
print('Total result:')
print(player1)
print(player2)
if __name__ == '__main__':
main()
player.py
from strategy import Strategy
from hand import Hand
class Player:
__wincount: int = 0
__losecount: int = 0
__gamecount: int = 0
def __init__(self, name: str, strategy: Strategy) -> None:
self.__name: str = name
self.__strategy: Strategy = strategy
def next_hand(self) -> Hand:
return self.__strategy.next_hand()
def win(self) -> None:
self.__strategy.study(True)
self.__wincount += 1
self.__gamecount += 1
def lose(self) -> None:
self.__strategy.study(False)
self.__losecount += 1
self.__gamecount += 1
def even(self) -> None:
self.__gamecount += 1
def __str__(self) -> str:
return f'[{self.__name}:{self.__gamecount} games, ' + \
f'{self.__wincount} win, {self.__losecount} lose]'
strategy.py
from abc import ABCMeta, abstractmethod
from hand import Hand
class Strategy(metaclass=ABCMeta):
@abstractmethod
def next_hand(self) -> Hand:
pass
@abstractmethod
def study(self, win: bool) -> None:
pass
prob_strategy.py
import random
from functools import reduce
from operator import add
from hand import Hand, HandValue
from strategy import Strategy
class ProbStrategy(Strategy):
__prev_hand_value: int = HandValue.ROCK
__current_hand_value: int = HandValue.ROCK
__history: list[list[int]] = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
def __init__(self, seed: int) -> None:
random.seed(seed)
def next_hand(self) -> Hand:
bet: int = random.randint(0, reduce(
add, [self.__history[self.__current_hand_value][i] for i in range(2)])
)
hand_value: int = 0
if bet < self.__history[self.__current_hand_value][HandValue.ROCK.value]:
hand_value = HandValue.ROCK.value
elif bet < self.__history[self.__current_hand_value][HandValue.ROCK.value] + \
self.__history[self.__current_hand_value][HandValue.SCISSORS.value]:
hand_value = HandValue.SCISSORS.value
else:
hand_value = HandValue.PAPER.value
self.__prev_hand_value = self.__current_hand_value
self.__current_hand_value = hand_value
return Hand.get_hand(hand_value)
def study(self, win: bool) -> None:
if win:
self.__history[self.__prev_hand_value][self.__current_hand_value] += 1
else:
self.__history[self.__prev_hand_value][(self.__current_hand_value + 1) % 3] += 1
self.__history[self.__prev_hand_value][(self.__current_hand_value + 2) % 3] += 1
winning_strategy.py
import random
from hand import Hand
from strategy import Strategy
class WinningStrategy(Strategy):
__won: bool = False
__prev_hand: Hand
def __init__(self, seed: int) -> None:
random.seed(seed)
def next_hand(self) -> Hand:
if not self.__won:
self.__prev_hand = Hand.get_hand(random.randint(0, 2))
return self.__prev_hand
def study(self, win: bool) -> None:
self.__won = win
Discussion