game.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package games
  2. import (
  3. "battlecamp-go-server/board"
  4. "battlecamp-go-server/player"
  5. "encoding/json"
  6. "log"
  7. "math/rand"
  8. "os"
  9. "runtime/pprof"
  10. "sync"
  11. "time"
  12. "github.com/go-stomp/stomp"
  13. )
  14. type Game struct {
  15. Id int64 `json:"id"`
  16. StartTime int64 `json:"startTime"`
  17. EndTime int64 `json:"endTime"`
  18. Board *board.Board `json:"board"`
  19. Players []*player.Player `json:"-"`
  20. mutex sync.Mutex
  21. Winner *player.Player `json:"winner,omitempty"`
  22. }
  23. func NewGame(cols, rows int) *Game {
  24. createTime := time.Now().Unix()
  25. f, err := os.Create("cpuprofile.log")
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. pprof.StartCPUProfile(f)
  30. defer pprof.StopCPUProfile()
  31. game := &Game{
  32. StartTime: createTime,
  33. Board: board.NewRemote(cols, rows),
  34. Players: make([]*player.Player, 0),
  35. }
  36. return game
  37. }
  38. func (g *Game) Join(p *player.Player) {
  39. g.mutex.Lock()
  40. g.placePlayer(p)
  41. g.Players = append(g.Players, p)
  42. g.mutex.Unlock()
  43. }
  44. func (g *Game) placePlayer(p *player.Player) {
  45. xRange := g.Board.Width / 5
  46. yRange := g.Board.Height
  47. for {
  48. x := rand.Intn(xRange)
  49. y := rand.Intn(yRange)
  50. if g.isValidPlayerPos(x, y) {
  51. p.Pos.X = x
  52. p.Pos.Y = y
  53. return
  54. }
  55. }
  56. }
  57. type updatePlayers struct {
  58. GameId int64 `json:"gameId"`
  59. Players []*player.Player `json:"players"`
  60. }
  61. type stompGameEnd struct {
  62. Type string `json:"type"`
  63. GameId int64 `json:"gameId"`
  64. Payload string `json:"payload"`
  65. }
  66. func (g *Game) Move(p *player.Player, direction string, sc *stomp.Conn) bool {
  67. if !(direction == "N" || direction == "W" || direction == "S" || direction == "E") {
  68. log.Printf("Illigal direction %v", direction)
  69. return false
  70. }
  71. newX := p.Pos.X
  72. newY := p.Pos.Y
  73. switch direction {
  74. case "N":
  75. newY--
  76. case "W":
  77. newX--
  78. case "S":
  79. newY++
  80. case "E":
  81. newX++
  82. }
  83. //TODO make thread safe
  84. if !g.isValidPlayerPos(newX, newY) {
  85. log.Printf("Illigal player pos oldX %v oldY %v newX %v newY %v dir %v ", p.Pos.X, p.Pos.Y, newX, newY, direction)
  86. return false
  87. }
  88. p.Pos.X = newX
  89. p.Pos.Y = newY
  90. // END TODO make tread safe
  91. up := updatePlayers{
  92. GameId: g.Id,
  93. Players: g.Players,
  94. }
  95. b, _ := json.Marshal(up)
  96. sc.Send("/topic/go-battlecamp.update", "application/json;charset=utf-8", b, stomp.SendOpt.NoContentLength)
  97. if g.isWinner(p) {
  98. g.EndTime = time.Now().Unix()
  99. g.Winner = p
  100. ge := stompGameEnd{
  101. Type: "GAME_END",
  102. GameId: g.Id,
  103. Payload: g.Winner.Id,
  104. }
  105. c, _ := json.Marshal(ge)
  106. sc.Send("/topic/go-battlecamp.game", "application/json;charset=utf-8", c, stomp.SendOpt.NoContentLength)
  107. }
  108. return true
  109. }
  110. func (g *Game) isWinner(p *player.Player) bool {
  111. return g.Board.Finish.X == p.Pos.X && g.Board.Finish.Y == p.Pos.Y
  112. }
  113. func (g *Game) isValidPlayerPos(x, y int) bool {
  114. if x < 0 || y < 0 || x >= g.Board.Width || y >= g.Board.Height {
  115. return false
  116. }
  117. t := g.Board.Get(x, y)
  118. if t == board.Rock {
  119. return false
  120. }
  121. return g.getPlayerAt(x, y) == nil
  122. }
  123. func (g *Game) getPlayerAt(x, y int) *player.Player {
  124. for _, p := range g.Players {
  125. if p.Pos.X == x && p.Pos.Y == y {
  126. return p
  127. }
  128. }
  129. return nil
  130. }
  131. func (g *Game) GetPlayer(playerId string) *player.Player {
  132. for _, p := range g.Players {
  133. if p.Id == playerId {
  134. return p
  135. }
  136. }
  137. return nil
  138. }