什么是策略模式?
- 策略模式即整体地替换算法
- 能够整体地替换算法,让我们轻松地以不同的算法去解决相一个问题
- 动态替换
示范代码(strategy.go)
猜拳游戏
package Strategy
import (
"fmt"
"math/rand"
"time"
)
const (
// 石头
HANDVALUE_GUU int = 0
// 剪刀
HANDVALUE_CHO int = 1
// 布
HANDVALUE_PAA int = 2
)
var (
hands = []*Hand{
NewHand(HANDVALUE_GUU),
NewHand(HANDVALUE_CHO),
NewHand(HANDVALUE_PAA),
}
names = []string{
"石头",
"剪刀",
"布",
}
)
type Hand struct {
handvalue int
}
func NewHand(handvalue int) *Hand {
return &Hand{handvalue: handvalue}
}
func (h *Hand) getHand() *Hand {
return hands[h.handvalue]
}
// 如果h胜过了_h,返回true
func (h *Hand) isStrongerThan(_h *Hand) bool {
return h.fight(_h) == 1
}
// 如果h输给了_h,返回true
func (h *Hand) isWeakerThan(_h *Hand) bool {
return h.fight(_h) == -1
}
// 计分: 平局0 胜利1 失败-1
func (h *Hand) fight(_h *Hand) int {
if h.handvalue == _h.handvalue {
return 0
} else if (h.handvalue+1)%3 == _h.handvalue {
return 1
} else {
return -1
}
}
func (h *Hand) toString() string {
return names[h.handvalue]
}
// 猜拳策略的抽闲方法接口
type Strategy interface {
nextHand() *Hand
study(win bool)
}
// 策略: 如果上一局的手赢了,则下一局手势与上局相同。否则,随机出手势
type WinningStrategy struct {
won bool
prevHand *Hand
}
func NewWinningStrategy() *WinningStrategy {
return &WinningStrategy{
won: false,
prevHand: nil,
}
}
func (s *WinningStrategy) nextHand() *Hand {
if !s.won {
rand.Seed(time.Now().UnixNano())
hand := NewHand(rand.Intn(3))
s.prevHand = hand.getHand()
}
return s.prevHand
}
func (s *WinningStrategy) study(win bool) {
s.won = win
}
// 根据过去的胜负来进行概率计算
type ProbStratege struct {
prevHandValue int
currentHandValue int
// history[上一局出的手势][这一局所处的手势]
history [][]int
}
func NewProbStratege() *ProbStratege {
return &ProbStratege{
prevHandValue: 0,
currentHandValue: 0,
history: [][]int{
{1, 1, 1}, // 连续两次出石头胜利次数 | 连续石头、剪刀胜利次数 | 连续石头、布胜利次数
{1, 1, 1}, // 连续剪刀、石头胜利次数 | 连续两次剪刀胜利次数 | 连续剪刀、布胜利次数
{1, 1, 1}, // 连续布、石头胜利次数 | 连续布、剪刀胜利次数 | 连续两次布胜利次数
},
}
}
func (s *ProbStratege) nextHand() *Hand {
rand.Seed(time.Now().UnixNano())
bet := rand.Intn(s.getSum(s.currentHandValue))
handvalue := 0
if bet < s.history[s.currentHandValue][0] {
handvalue = 0
} else if bet < s.history[s.currentHandValue][0]+s.history[s.currentHandValue][1] {
handvalue = 1
} else {
handvalue = 2
}
s.prevHandValue = s.currentHandValue
s.currentHandValue = handvalue
hand := NewHand(handvalue)
return hand.getHand()
}
func (s *ProbStratege) study(win bool) {
if win {
s.history[s.prevHandValue][s.currentHandValue]++
} else {
s.history[s.prevHandValue][(s.currentHandValue+1)%3]++
s.history[s.prevHandValue][(s.currentHandValue+2)%3]++
}
}
func (s *ProbStratege) getSum(hv int) int {
sum := 0
for i := 0; i < 3; i++ {
sum += s.history[hv][i]
}
return sum
}
type Player struct {
name string
strategy Strategy
winCount int
loseCount int
gameCount int
}
func NewPlayer(name string, strategy Strategy) *Player {
return &Player{
name: name,
strategy: strategy,
winCount: 0,
loseCount: 0,
gameCount: 0,
}
}
func (p *Player) nextHand() *Hand {
return p.strategy.nextHand()
}
func (p *Player) win() {
p.strategy.study(true)
p.gameCount++
p.winCount++
}
func (p *Player) lose() {
p.strategy.study(false)
p.gameCount++
p.loseCount++
}
func (p *Player) even() {
p.gameCount++
}
func (p *Player) toString() string {
return fmt.Sprintf("[%s:%d games,%d win,%d lose]", p.name, p.gameCount, p.winCount, p.loseCount)
}
测试用例(strategy_test.go)
package Strategy
import (
"fmt"
"testing"
)
func TestName(t *testing.T) {
player1 := NewPlayer("Taro", NewWinningStrategy())
player2 := NewPlayer("Hana", NewProbStratege())
for i := 0; i < 1000; i++ {
nextHand1 := player1.nextHand()
nextHand2 := player2.nextHand()
if nextHand1.isStrongerThan(nextHand2) {
fmt.Println("Winner:" + player1.toString())
player1.win()
player2.lose()
} else if nextHand2.isStrongerThan(nextHand1) {
fmt.Println("Winner:" + player2.toString())
player1.lose()
player2.win()
} else {
//fmt.Println("Even")
player1.even()
player2.even()
}
}
fmt.Println("Total result:")
fmt.Println(player1.toString())
fmt.Println(player2.toString())
}