main.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "math"
  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. for {
  27. subscribeToGame(pu)
  28. }
  29. }
  30. func subscribeToGame(pu chan *events.PlayerUpdate) {
  31. sub := stomp.Subscribe("game")
  32. gameEndChannels := make(map[int]*[]chan bool)
  33. for {
  34. announcement := <-sub
  35. gs := new(events.GameStart)
  36. json.Unmarshal(announcement.Body, &gs)
  37. fmt.Printf("announcement type: %v for game %v\n", gs.Type, strconv.FormatInt(gs.GameId, 10))
  38. if "GAME_START" == gs.Type {
  39. names := []string{"Zeus", "Joost", "Henk", "Klaas"}
  40. tmp := make([]chan bool, 0, len(names))
  41. gameEndChannels[int(gs.GameId)] = &tmp
  42. for _, name := range names {
  43. gameEndChan := make(chan bool)
  44. tmp := append(*gameEndChannels[int(gs.GameId)], gameEndChan)
  45. gameEndChannels[int(gs.GameId)] = &tmp
  46. go joinGame(gs.GameId, gameEndChan, pu, name)
  47. }
  48. } else {
  49. chans := gameEndChannels[int(gs.GameId)]
  50. for _, channel := range *chans {
  51. channel <- true
  52. }
  53. }
  54. }
  55. }
  56. func subscribeToUpdate(pu chan *events.PlayerUpdate) {
  57. sub := stomp.Subscribe("update")
  58. for {
  59. announcement := <-sub
  60. if "vnd.battlecamp.player" == announcement.ContentType {
  61. p := new(player.Player)
  62. json.Unmarshal(announcement.Body, &p)
  63. playerJoin(p)
  64. } else {
  65. pue := new(events.PlayerUpdate)
  66. json.Unmarshal(announcement.Body, &pue)
  67. pu <- pue
  68. }
  69. }
  70. }
  71. func joinGame(gameId int64, gameEndChan chan bool, pu chan *events.PlayerUpdate, name string) {
  72. //join game
  73. p := &player.Player{
  74. Id: name,
  75. Color: "#238b02",
  76. Type: 1,
  77. }
  78. players := make([]*player.Player, 5)
  79. //retrieve finish
  80. gameUrl := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10)
  81. fmt.Println("getGame:>", gameUrl)
  82. resp, _ := http.Get(gameUrl)
  83. g := new(game.Game)
  84. b, _ := ioutil.ReadAll(resp.Body)
  85. json.Unmarshal(b, &g)
  86. boardSummery := g.Board
  87. fmt.Printf("Finish x=%v y=%v\n", boardSummery.Finish.X, boardSummery.Finish.Y)
  88. //join the game
  89. url := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10) + "/join"
  90. jsonStr, _ := json.Marshal(p)
  91. req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
  92. req.Header.Set("Content-Type", "application/json")
  93. client := &http.Client{}
  94. resp, err := client.Do(req)
  95. if err != nil {
  96. panic(err)
  97. }
  98. v, _ := ioutil.ReadAll(resp.Body)
  99. json.Unmarshal(v, p) //Set my location in the player
  100. fmt.Printf("My start position x %v y %v\n", p.Pos.X, p.Pos.Y)
  101. resp.Body.Close()
  102. for {
  103. select {
  104. case <-gameEndChan:
  105. fmt.Println("Game ended returning")
  106. return
  107. case playerUpdate := <-pu:
  108. if playerUpdate.GameId == gameId {
  109. /* players = playerUpdate.Players // TODO fix multi client
  110. for _, pup := range players {
  111. if pup.Id == p.Id {
  112. p.Pos.X = pup.Pos.X
  113. p.Pos.Y = pup.Pos.Y
  114. fmt.Printf("Set position to x=%v y=%v\n", pup.Pos.X, pup.Pos.Y)
  115. }
  116. }*/
  117. }
  118. default:
  119. move(gameId, p, players, boardSummery)
  120. time.Sleep(100 * time.Millisecond)
  121. }
  122. }
  123. }
  124. type viewport struct {
  125. x, y, width, height int
  126. Board *board.Board
  127. }
  128. func getViewPort(x, y, width, height int, gameId int64, bs *board.Board) *viewport {
  129. x, y, width, height = board.SanitizeViewPort(bs, x, y, width, height)
  130. /*max(x, 0)
  131. x = min(x, bs.Width)
  132. y = max(y, 0)
  133. y = min(y, bs.Height)*/
  134. url := "http://localhost:8080/games/board/" + strconv.FormatInt(gameId, 10) + "?x=" + strconv.Itoa(x) + "&y=" + strconv.Itoa(y) + "&rows=" + strconv.Itoa(height) + "&cols=" + strconv.Itoa(width)
  135. fmt.Println("getViewPort:>", url)
  136. resp, _ := http.Get(url)
  137. board := board.ReadJSON(x, y, resp.Body)
  138. return &viewport{
  139. x: x,
  140. y: y,
  141. width: width,
  142. height: height,
  143. Board: board,
  144. }
  145. }
  146. func (v viewport) Get(x, y int) board.TileType {
  147. return v.Board.Get(x-v.x, y-v.y)
  148. }
  149. const viewPortWidth = 1024
  150. const viewPortHeight = 1024
  151. func max(a, b int) int {
  152. if a >= b {
  153. return a
  154. }
  155. return b
  156. }
  157. func min(a, b int) int {
  158. if a <= b {
  159. return a
  160. }
  161. return b
  162. }
  163. func move(gameId int64, p *player.Player, players []*player.Player, bs *board.Board) {
  164. if bs.Finish.X == p.Pos.X && p.Pos.Y == bs.Finish.Y {
  165. fmt.Println("HELP i'm finished stop me!!")
  166. time.Sleep(1 * time.Second)
  167. return
  168. }
  169. //determine move
  170. viewPortX := 0
  171. viewPortY := 0
  172. if viewPortHeight <= bs.Height || viewPortWidth <= bs.Width {
  173. viewPortX = p.Pos.X - 1
  174. viewPortY = p.Pos.Y - viewPortHeight/2
  175. }
  176. viewPort := getViewPort(viewPortX, viewPortY, viewPortWidth, viewPortHeight, gameId, bs)
  177. //fmt.Printf("viewport x=%v y=%v width %v height %v viewport board width %v height %v\n", viewPort.x, viewPort.y, viewPort.width, viewPort.height, viewPort.Board.Width, viewPort.Board.Height)
  178. direction := "E"
  179. igloY := bs.Finish.Y
  180. if bs.Finish.Y < viewPort.y {
  181. //iglo ten noorden van viewport
  182. fmt.Println("iglo boven")
  183. igloY = 0
  184. /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY <= viewPort.y+viewPortHeight {
  185. igloY++
  186. }*/
  187. } else if bs.Finish.Y > viewPort.y+viewPort.Board.Height {
  188. //iglo ten zuiden van viewport
  189. fmt.Println("iglo onder")
  190. igloY = viewPort.Board.Height - 1
  191. /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY >= viewPort.y+viewPortHeight {
  192. igloY--
  193. }*/
  194. }
  195. igloX := viewPort.Board.Width
  196. if viewPort.x < bs.Finish.X && viewPort.x+viewPort.Board.Width > bs.Finish.X {
  197. igloX = bs.Finish.X
  198. }
  199. //fmt.Printf("Virtuele iglo geplaast op x %v y %v\n", igloX, igloY)
  200. dist := calcDist(igloX, igloY, viewPort)
  201. /*for i := 0;i< viewPort.Board.Height;i++ {
  202. for j := 0;j< viewPort.Board.Width;j++ {
  203. if(j == p.Pos.X && i == p.Pos.Y) {
  204. fmt.Printf("X")
  205. }
  206. if(j == bs.Finish.X && i == bs.Finish.Y) {
  207. fmt.Printf("I")
  208. }
  209. fmt.Printf("%v ", dist[(i*viewPort.Board.Width)+j])
  210. }
  211. fmt.Printf("\n")
  212. }*/
  213. smallestDist := math.MaxInt32
  214. if p.Pos.X+1 < viewPort.width && dist[toIndex(p.Pos.X+1, p.Pos.Y, viewPort.Board.Width)] != 0 {
  215. direction = "E"
  216. smallestDist = dist[toIndex(p.Pos.X+1, p.Pos.Y, viewPort.Board.Width)]
  217. }
  218. if p.Pos.X-1 >= 0 && dist[toIndex(p.Pos.X-1, p.Pos.Y, viewPort.Board.Width)] != 0 && smallestDist > dist[toIndex(p.Pos.X-1, p.Pos.Y, viewPort.Board.Width)] {
  219. direction = "W"
  220. smallestDist = dist[toIndex(p.Pos.X-1, p.Pos.Y, viewPort.Board.Width)]
  221. }
  222. if p.Pos.Y+1 < viewPort.height && dist[toIndex(p.Pos.X, p.Pos.Y+1, viewPort.Board.Width)] != 0 && smallestDist > dist[toIndex(p.Pos.X, p.Pos.Y+1, viewPort.Board.Width)] {
  223. direction = "S"
  224. smallestDist = dist[toIndex(p.Pos.X, p.Pos.Y+1, viewPort.Board.Width)]
  225. }
  226. if p.Pos.Y-1 >= 0 && dist[toIndex(p.Pos.X, p.Pos.Y-1, viewPort.Board.Width)] != 0 && smallestDist > dist[toIndex(p.Pos.X, p.Pos.Y-1, viewPort.Board.Width)] {
  227. direction = "N"
  228. smallestDist = dist[toIndex(p.Pos.X, p.Pos.Y-1, viewPort.Board.Width)]
  229. }
  230. //send move
  231. url := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10) + "/move/" + p.Id + "/" + direction
  232. fmt.Println("move:>", url, smallestDist)
  233. http.Post(url, "text/plain", nil)
  234. //update x,y
  235. switch direction {
  236. case "N":
  237. p.Pos.Y--
  238. case "E":
  239. p.Pos.X++
  240. case "S":
  241. p.Pos.Y++
  242. case "W":
  243. p.Pos.X--
  244. }
  245. //fmt.Printf("new pos x=%v y=%v\n", p.Pos.X, p.Pos.Y)
  246. }
  247. func toXy(index, boardWidth int) (x, y int) {
  248. x = index % boardWidth
  249. y = (index - x) / boardWidth
  250. return x, y
  251. }
  252. func toIndex(x, y, boardWidth int) (index int) {
  253. return y*boardWidth + x
  254. }
  255. func calcDist(igloX, igloY int, viewPort *viewport) map[int]int {
  256. distance := make(map[int]int)
  257. s := NewQueue()
  258. index := toIndex(igloX, igloY, viewPort.Board.Width)
  259. s.Push(index)
  260. distance[index] = -1
  261. for s.Len() != 0 {
  262. i := s.Poll()
  263. x, y := toXy(i, viewPort.Board.Width)
  264. if x+1 < viewPort.Board.Width {
  265. newI := toIndex(x+1, y, viewPort.Board.Width)
  266. if distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock {
  267. distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
  268. s.Push(newI)
  269. }
  270. }
  271. if x-1 >= 0 {
  272. newI := toIndex(x-1, y, viewPort.Board.Width)
  273. if distance[newI] == 0 && viewPort.Board.Get(x-1, y) != board.Rock {
  274. distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
  275. s.Push(newI)
  276. }
  277. }
  278. if y+1 < viewPort.Board.Height {
  279. newI := toIndex(x, y+1, viewPort.Board.Width)
  280. if distance[newI] == 0 && viewPort.Board.Get(x, y+1) != board.Rock {
  281. distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
  282. s.Push(newI)
  283. }
  284. }
  285. if y-1 >= 0 {
  286. newI := toIndex(x, y-1, viewPort.Board.Width)
  287. if distance[newI] == 0 && viewPort.Board.Get(x, y-1) != board.Rock {
  288. distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
  289. s.Push(newI)
  290. }
  291. }
  292. }
  293. return distance
  294. }
  295. /*
  296. type stack []int
  297. func (s stack) Empty() bool { return len(s) == 0 }
  298. func (s stack) Peek() int { return s[len(s)-1] }
  299. func (s *stack) Put(i int) { (*s) = append((*s), i) }
  300. func (s *stack) Pop() int {
  301. d := (*s)[len(*s)-1]
  302. (*s) = (*s)[:len(*s)-1]
  303. return d
  304. }
  305. */
  306. type queuenode struct {
  307. data int
  308. next *queuenode
  309. }
  310. // A go-routine safe FIFO (first in first out) data stucture.
  311. type Queue struct {
  312. head *queuenode
  313. tail *queuenode
  314. count int
  315. }
  316. // Creates a new pointer to a new queue.
  317. func NewQueue() *Queue {
  318. q := &Queue{}
  319. return q
  320. }
  321. // Returns the number of elements in the queue (i.e. size/length)
  322. // go-routine safe.
  323. func (q *Queue) Len() int {
  324. return q.count
  325. }
  326. // Pushes/inserts a value at the end/tail of the queue.
  327. // Note: this function does mutate the queue.
  328. // go-routine safe.
  329. func (q *Queue) Push(item int) {
  330. n := &queuenode{data: item}
  331. if q.tail == nil {
  332. q.tail = n
  333. q.head = n
  334. } else {
  335. q.tail.next = n
  336. q.tail = n
  337. }
  338. q.count++
  339. }
  340. // Returns the value at the front of the queue.
  341. // i.e. the oldest value in the queue.
  342. // Note: this function does mutate the queue.
  343. // go-routine safe.
  344. func (q *Queue) Poll() int {
  345. n := q.head
  346. q.head = n.next
  347. if q.head == nil {
  348. q.tail = nil
  349. }
  350. q.count--
  351. return n.data
  352. }
  353. // Returns a read value at the front of the queue.
  354. // i.e. the oldest value in the queue.
  355. // Note: this function does NOT mutate the queue.
  356. // go-routine safe.
  357. func (q *Queue) Peek() int {
  358. n := q.head
  359. return n.data
  360. }
  361. func playerJoin(p *player.Player) {
  362. }
  363. func initLogging() {
  364. logFile, err := os.Create("server.log")
  365. if err == nil {
  366. log.SetOutput(logFile)
  367. } else {
  368. log.Println("ERROR: Cannot open log file, using console.")
  369. log.Printf("%v=n", err)
  370. }
  371. }