main.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. package main
  2. import (
  3. "math"
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io/ioutil"
  8. "log"
  9. "net/http"
  10. "os"
  11. "strconv"
  12. "time"
  13. "battlecamp-go/board"
  14. "battlecamp-go/events"
  15. "battlecamp-go/flag"
  16. "battlecamp-go/game"
  17. "battlecamp-go/player"
  18. "battlecamp-go/stomp"
  19. )
  20. func main() {
  21. initLogging()
  22. log.Println("Game bot version 0.1")
  23. flag.ParseFlags()
  24. pu := make(chan *events.PlayerUpdate)
  25. go subscribeToUpdate(pu)
  26. subscribeToGame(pu)
  27. }
  28. func subscribeToGame(pu chan *events.PlayerUpdate) {
  29. sub := stomp.Subscribe("game")
  30. for {
  31. announcement := <-sub
  32. gs := new(events.GameStart)
  33. json.Unmarshal(announcement.Body, &gs)
  34. log.Printf("announcement type: %v ", strconv.FormatInt(gs.GameId, 10))
  35. gameEndChan := make(chan bool)
  36. if "GAME_START" == gs.Type {
  37. go joinGame(gs.GameId, gameEndChan, pu)
  38. } else {
  39. gameEndChan <- true
  40. }
  41. }
  42. }
  43. func subscribeToUpdate(pu chan *events.PlayerUpdate) {
  44. sub := stomp.Subscribe("update")
  45. for {
  46. announcement := <-sub
  47. if "vnd.battlecamp.player" == announcement.ContentType {
  48. p := new(player.Player)
  49. json.Unmarshal(announcement.Body, &p)
  50. playerJoin(p)
  51. } else {
  52. pue := new(events.PlayerUpdate)
  53. json.Unmarshal(announcement.Body, &pue)
  54. pu <- pue
  55. }
  56. }
  57. }
  58. func joinGame(gameId int64, gameEndChan chan bool, pu chan *events.PlayerUpdate) {
  59. //join game
  60. p := &player.Player{
  61. Id: "Zeus",
  62. Color: "#238b02",
  63. Type: 1,
  64. }
  65. players := make([]*player.Player, 5)
  66. //retrieve finish
  67. gameUrl := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10)
  68. fmt.Println("getGame:>", gameUrl)
  69. resp, _ := http.Get(gameUrl)
  70. g := new(game.Game)
  71. b, _ := ioutil.ReadAll(resp.Body)
  72. json.Unmarshal(b, &g)
  73. boardSummery := g.Board
  74. fmt.Printf("Finish x=%v y=%v\n", boardSummery.Finish.X, boardSummery.Finish.Y)
  75. //join the game
  76. url := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10) + "/join"
  77. jsonStr, _ := json.Marshal(p)
  78. req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
  79. req.Header.Set("Content-Type", "application/json")
  80. client := &http.Client{}
  81. resp, err := client.Do(req)
  82. if err != nil {
  83. panic(err)
  84. }
  85. v, _ := ioutil.ReadAll(resp.Body)
  86. json.Unmarshal(v, p) //Set my location in the player
  87. fmt.Printf("My start position x %v y %v\n", p.Pos.X, p.Pos.Y)
  88. resp.Body.Close()
  89. //determine to avoind north or south
  90. north := true
  91. if boardSummery.Finish.Y > p.Pos.Y {
  92. north = false
  93. }
  94. for {
  95. select {
  96. case <-gameEndChan:
  97. return
  98. case playerUpdate := <-pu:
  99. if playerUpdate.GameId == gameId {
  100. players = playerUpdate.Players
  101. for _, pup := range players {
  102. if pup.Id == p.Id {
  103. p.Pos.X = pup.Pos.X
  104. p.Pos.Y = pup.Pos.Y
  105. fmt.Printf("Set position to x=%v y=%v\n", pup.Pos.X, pup.Pos.Y)
  106. }
  107. }
  108. }
  109. default:
  110. move(gameId, p, players, boardSummery, north)
  111. time.Sleep(2 * time.Second)
  112. }
  113. }
  114. }
  115. type viewport struct {
  116. x, y, width, height int
  117. Board *board.Board
  118. }
  119. func getViewPort(x, y, width, height int, gameId int64, bs *board.Board) *viewport {
  120. x = max(x, 0)
  121. x = min(x, bs.Width)
  122. y = max(y, 0)
  123. y = min(y, bs.Height)
  124. if x+width > bs.Width {
  125. width = bs.Width - x
  126. }
  127. if y+height > bs.Height {
  128. height = bs.Height - x
  129. }
  130. url := "http://localhost:8080/games/board/" + strconv.FormatInt(gameId, 10) + "?x=" + strconv.Itoa(x) + "&y=" + strconv.Itoa(y) + "&rows=" + strconv.Itoa(width) + "&cols=" + strconv.Itoa(height)
  131. fmt.Println("getViewPort:>", url)
  132. resp, _ := http.Get(url)
  133. board := board.ReadJSON(x, y, resp.Body)
  134. return &viewport{
  135. x: x,
  136. y: y,
  137. width: width,
  138. height: height,
  139. Board: board,
  140. }
  141. }
  142. func (v viewport) Get(x, y int) board.TileType {
  143. fmt.Printf("retrieving from viewport x %v y %v position in viewport x %v y %v", x, y, x-v.x, y-v.y)
  144. return v.Board.Get(x-v.x, y-v.y)
  145. }
  146. const viewPortWidth = 32
  147. const viewPortHeight = 32
  148. func max(a, b int) int {
  149. if a >= b {
  150. return a
  151. }
  152. return b
  153. }
  154. func min(a, b int) int {
  155. if a <= b {
  156. return a
  157. }
  158. return b
  159. }
  160. func move(gameId int64, p *player.Player, players []*player.Player, bs *board.Board, north bool) {
  161. //determine move
  162. viewPortX := p.Pos.X - 1
  163. viewPortY := p.Pos.Y - 1
  164. if north {
  165. viewPortX = viewPortX - viewPortHeight
  166. }
  167. viewPort := getViewPort(viewPortX, viewPortY, viewPortWidth, viewPortHeight, gameId, bs)
  168. direction := "W"
  169. fmt.Printf("p.Pos.X+1 %v p.Pos.Y %v\n", p.Pos.X+1, p.Pos.Y)
  170. if viewPort.Get(p.Pos.X+1, p.Pos.Y) != board.Rock {
  171. direction = "E"
  172. }
  173. var igloY int
  174. if bs.Finish.Y > viewPort.y {
  175. //iglo ten noorden van ons
  176. igloY = 0
  177. /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY <= viewPort.y+viewPortHeight {
  178. igloY++
  179. }*/
  180. } else if(bs.Finish.Y < viewPort.y+viewPortHeight) {
  181. //iglo ten zuiden van ons
  182. igloY = viewPort.Board.Height-1
  183. /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY >= viewPort.y+viewPortHeight {
  184. igloY--
  185. }*/
  186. } else {
  187. igloY = bs.Finish.Y
  188. }
  189. igloX := viewPort.Board.Width
  190. calcDist(igloX, igloY, viewPort)
  191. smallestDist := math.MaxInt32
  192. //send move
  193. url := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10) + "/move/" + p.Id + "/" + direction
  194. fmt.Println("move:>", url, smallestDist)
  195. http.Post(url, "text/plain", nil)
  196. //update x,y
  197. switch direction {
  198. case "N":
  199. p.Pos.Y++
  200. case "E":
  201. p.Pos.X++
  202. case "S":
  203. p.Pos.Y--
  204. case "W":
  205. p.Pos.Y++
  206. }
  207. fmt.Printf("new pos x=%v y=%v\n", p.Pos.X, p.Pos.Y)
  208. }
  209. func toXy(index, boardWidth int) (x, y int) {
  210. x = index % boardWidth
  211. y = (index-x)/boardWidth
  212. return x,y
  213. }
  214. func toIndex(x,y , boardWidth int) (index int) {
  215. return y*boardWidth+x
  216. }
  217. func calcDist(igloX, igloY int, viewPort *viewport) map[int]int {
  218. distance := make(map[int]int)
  219. s := stack{}
  220. index := toIndex(igloX, igloY, viewPort.Board.Width)
  221. s.Put(index)
  222. distance[index] = -1
  223. for !s.Empty() {
  224. i := s.Pop()
  225. x, y := toXy(i, viewPort.Board.Width)
  226. if(x+1 < viewPort.width) {
  227. newI := toIndex(x+1, y, viewPort.Board.Width)
  228. if(distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock) {
  229. distance[newI] = distance[toIndex(x, y, viewPort.Board.Width)] + 1
  230. s.Put(newI)
  231. }
  232. }
  233. if(x-1 > 0) {
  234. newI := toIndex(x-1, y, viewPort.Board.Width)
  235. if(distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock) {
  236. distance[newI] = distance[toIndex(x, y, viewPort.Board.Width)] + 1
  237. s.Put(newI)
  238. }
  239. }
  240. if(y+1 < viewPort.height) {
  241. newI := toIndex(x, y+1, viewPort.Board.Width)
  242. if(distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock) {
  243. distance[newI] = distance[toIndex(x, y, viewPort.Board.Width)] + 1
  244. s.Put(newI)
  245. }
  246. }
  247. if(y-1 > 0) {
  248. newI := toIndex(x, y-1, viewPort.Board.Width)
  249. if(distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock) {
  250. distance[newI] = distance[toIndex(x, y, viewPort.Board.Width)] + 1
  251. s.Put(newI)
  252. }
  253. }
  254. }
  255. return distance
  256. }
  257. type stack []int
  258. func (s stack) Empty() bool { return len(s) == 0 }
  259. func (s stack) Peek() int { return s[len(s)-1] }
  260. func (s *stack) Put(i int) { (*s) = append((*s), i) }
  261. func (s *stack) Pop() int {
  262. d := (*s)[len(*s)-1]
  263. (*s) = (*s)[:len(*s)-1]
  264. return d
  265. }
  266. func playerJoin(p *player.Player) {
  267. }
  268. func initLogging() {
  269. logFile, err := os.Create("server.log")
  270. if err == nil {
  271. log.SetOutput(logFile)
  272. } else {
  273. log.Println("ERROR: Cannot open log file, using console.")
  274. log.Printf("%v=n", err)
  275. }
  276. }