blob: e42349185e31a95ffb1a9b17bf37eba0da3a7c6f [file] [log] [blame]
Robin Thellendedca68c2014-05-20 11:03:02 -07001package impl
2
3import (
Robin Thellendedca68c2014-05-20 11:03:02 -07004 "io"
5 "math/rand"
6 "sync"
7 "time"
8
9 rps "veyron/examples/rockpaperscissors"
10 "veyron/examples/rockpaperscissors/common"
11
12 "veyron2"
13 "veyron2/naming"
14 "veyron2/vlog"
15)
16
17type Player struct {
18 mt naming.MountTable
19 lock sync.Mutex
20 gamesPlayed common.Counter
21 gamesWon common.Counter
22}
23
24func NewPlayer(mt naming.MountTable) *Player {
25 return &Player{mt: mt}
26}
27
28func (p *Player) Stats() (played, won int64) {
29 played = p.gamesPlayed.Value()
30 won = p.gamesWon.Value()
31 return
32}
33
34func (p *Player) InitiateGame() error {
35 judge, err := common.FindJudge(p.mt)
36 if err != nil {
37 vlog.Infof("FindJudge: %v", err)
38 return err
39 }
40 gameID, err := p.createGame(judge)
41 if err != nil {
42 vlog.Infof("createGame: %v", err)
43 return err
44 }
45 vlog.Infof("Created gameID %q on %q", gameID, judge)
46
47 opponent, err := common.FindPlayer(p.mt)
48 if err != nil {
49 vlog.Infof("FindPlayer: %v", err)
50 return err
51 }
52 vlog.Infof("chosen opponent is %q", opponent)
Robin Thellend912059e2014-05-31 18:26:11 -070053 if err = p.sendChallenge(opponent, judge, gameID); err != nil {
Robin Thellendedca68c2014-05-20 11:03:02 -070054 vlog.Infof("sendChallenge: %v", err)
55 return err
56 }
Robin Thellendedca68c2014-05-20 11:03:02 -070057 result, err := p.playGame(judge, gameID)
58 if err != nil {
59 vlog.Infof("playGame: %v", err)
60 return err
61 }
62 if result.YouWon {
63 vlog.Info("Game result: I won! :)")
64 } else {
65 vlog.Info("Game result: I lost :(")
66 }
67 return nil
68}
69
70func (p *Player) createGame(server string) (rps.GameID, error) {
71 j, err := rps.BindRockPaperScissors(server)
72 if err != nil {
73 return rps.GameID{}, err
74 }
75 numRounds := 3 + rand.Intn(3)
76 gameType := rps.Classic
77 if rand.Intn(2) == 1 {
78 gameType = rps.LizardSpock
79 }
80 return j.CreateGame(rps.GameOptions{NumRounds: int32(numRounds), GameType: gameType})
81}
82
Robin Thellend912059e2014-05-31 18:26:11 -070083func (p *Player) sendChallenge(opponent, judge string, gameID rps.GameID) error {
Robin Thellendedca68c2014-05-20 11:03:02 -070084 o, err := rps.BindRockPaperScissors(opponent)
85 if err != nil {
Robin Thellend912059e2014-05-31 18:26:11 -070086 return err
Robin Thellendedca68c2014-05-20 11:03:02 -070087 }
88 return o.Challenge(judge, gameID)
89}
90
91// challenge receives an incoming challenge.
Robin Thellend912059e2014-05-31 18:26:11 -070092func (p *Player) challenge(judge string, gameID rps.GameID) error {
Robin Thellendedca68c2014-05-20 11:03:02 -070093 vlog.Infof("challenge received: %s %v", judge, gameID)
94 go p.playGame(judge, gameID)
Robin Thellend912059e2014-05-31 18:26:11 -070095 return nil
Robin Thellendedca68c2014-05-20 11:03:02 -070096}
97
98// playGame plays an entire game, which really only consists of reading
99// commands from the server, and picking a random "move" when asked to.
100func (p *Player) playGame(judge string, gameID rps.GameID) (rps.PlayResult, error) {
101 j, err := rps.BindRockPaperScissors(judge)
102 if err != nil {
103 return rps.PlayResult{}, err
104 }
105 game, err := j.Play(gameID, veyron2.CallTimeout(10*time.Minute))
106 if err != nil {
107 return rps.PlayResult{}, err
108 }
109 for {
110 in, err := game.Recv()
111 if err == io.EOF {
112 vlog.Infof("Game Ended")
113 break
114 }
115 if err != nil {
116 vlog.Infof("recv error: %v", err)
117 break
118 }
119 if in.PlayerNum > 0 {
120 vlog.Infof("I'm player %d", in.PlayerNum)
121 }
122 if len(in.OpponentName) > 0 {
123 vlog.Infof("My opponent is %q", in.OpponentName)
124 }
125 if len(in.MoveOptions) > 0 {
126 n := rand.Intn(len(in.MoveOptions))
127 vlog.Infof("My turn to play. Picked %q from %v", in.MoveOptions[n], in.MoveOptions)
128 if err := game.Send(rps.PlayerAction{Move: in.MoveOptions[n]}); err != nil {
129 return rps.PlayResult{}, err
130 }
131 }
132 if len(in.RoundResult.Moves[0]) > 0 {
133 vlog.Infof("Player 1 played %q. Player 2 played %q. Winner: %v",
134 in.RoundResult.Moves[0], in.RoundResult.Moves[1], in.RoundResult.Winner)
135 }
136 if len(in.Score.Players) > 0 {
137 vlog.Infof("Score card: %s", common.FormatScoreCard(in.Score))
138 }
139 }
140 result, err := game.Finish()
141 p.gamesPlayed.Add(1)
142 if err == nil && result.YouWon {
143 p.gamesWon.Add(1)
144 }
145 return result, err
146}