| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- package main
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "log"
- "math"
- "net/http"
- "os"
- "strconv"
- "time"
- "battlecamp-go/board"
- "battlecamp-go/events"
- "battlecamp-go/flag"
- "battlecamp-go/game"
- "battlecamp-go/player"
- "battlecamp-go/stomp"
- )
- func main() {
- initLogging()
- log.Println("Game bot version 0.1")
- flag.ParseFlags()
- pu := make(chan *events.PlayerUpdate)
- go subscribeToUpdate(pu)
- for {
- subscribeToGame(pu)
- }
- }
- func subscribeToGame(pu chan *events.PlayerUpdate) {
- sub := stomp.Subscribe("game")
- gameEndChannels := make(map[int]*[]chan bool)
- for {
- announcement := <-sub
- gs := new(events.GameStart)
- json.Unmarshal(announcement.Body, &gs)
- fmt.Printf("announcement type: %v for game %v\n", gs.Type, strconv.FormatInt(gs.GameId, 10))
- if "GAME_START" == gs.Type {
- names := []string{"Zeus", "Joost", "Henk", "Klaas"}
- tmp := make([]chan bool, 0, len(names))
- gameEndChannels[int(gs.GameId)] = &tmp
- for _, name := range names {
- gameEndChan := make(chan bool)
- tmp := append(*gameEndChannels[int(gs.GameId)], gameEndChan)
- gameEndChannels[int(gs.GameId)] = &tmp
- go joinGame(gs.GameId, gameEndChan, pu, name)
- }
- } else {
- chans := gameEndChannels[int(gs.GameId)]
- for _, channel := range *chans {
- channel <- true
- }
- }
- }
- }
- func subscribeToUpdate(pu chan *events.PlayerUpdate) {
- sub := stomp.Subscribe("update")
- for {
- announcement := <-sub
- if "vnd.battlecamp.player" == announcement.ContentType {
- p := new(player.Player)
- json.Unmarshal(announcement.Body, &p)
- playerJoin(p)
- } else {
- pue := new(events.PlayerUpdate)
- json.Unmarshal(announcement.Body, &pue)
- pu <- pue
- }
- }
- }
- func joinGame(gameId int64, gameEndChan chan bool, pu chan *events.PlayerUpdate, name string) {
- //join game
- p := &player.Player{
- Id: name,
- Color: "#238b02",
- Type: 1,
- }
- players := make([]*player.Player, 5)
- //retrieve finish
- gameUrl := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10)
- fmt.Println("getGame:>", gameUrl)
- resp, _ := http.Get(gameUrl)
- g := new(game.Game)
- b, _ := ioutil.ReadAll(resp.Body)
- json.Unmarshal(b, &g)
- boardSummery := g.Board
- fmt.Printf("Finish x=%v y=%v\n", boardSummery.Finish.X, boardSummery.Finish.Y)
- //join the game
- url := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10) + "/join"
- jsonStr, _ := json.Marshal(p)
- req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
- req.Header.Set("Content-Type", "application/json")
- client := &http.Client{}
- resp, err := client.Do(req)
- if err != nil {
- panic(err)
- }
- v, _ := ioutil.ReadAll(resp.Body)
- json.Unmarshal(v, p) //Set my location in the player
- fmt.Printf("My start position x %v y %v\n", p.Pos.X, p.Pos.Y)
- resp.Body.Close()
- for {
- select {
- case <-gameEndChan:
- fmt.Println("Game ended returning")
- return
- case playerUpdate := <-pu:
- if playerUpdate.GameId == gameId {
- /* players = playerUpdate.Players // TODO fix multi client
- for _, pup := range players {
- if pup.Id == p.Id {
- p.Pos.X = pup.Pos.X
- p.Pos.Y = pup.Pos.Y
- fmt.Printf("Set position to x=%v y=%v\n", pup.Pos.X, pup.Pos.Y)
- }
- }*/
- }
- default:
- move(gameId, p, players, boardSummery)
- time.Sleep(100 * time.Millisecond)
- }
- }
- }
- type viewport struct {
- x, y, width, height int
- Board *board.Board
- }
- func getViewPort(x, y, width, height int, gameId int64, bs *board.Board) *viewport {
- x, y, width, height = board.SanitizeViewPort(bs, x, y, width, height)
- /*max(x, 0)
- x = min(x, bs.Width)
- y = max(y, 0)
- y = min(y, bs.Height)*/
- 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)
- fmt.Println("getViewPort:>", url)
- resp, _ := http.Get(url)
- board := board.ReadJSON(x, y, resp.Body)
- return &viewport{
- x: x,
- y: y,
- width: width,
- height: height,
- Board: board,
- }
- }
- func (v viewport) Get(x, y int) board.TileType {
- return v.Board.Get(x-v.x, y-v.y)
- }
- const viewPortWidth = 1024
- const viewPortHeight = 1024
- func max(a, b int) int {
- if a >= b {
- return a
- }
- return b
- }
- func min(a, b int) int {
- if a <= b {
- return a
- }
- return b
- }
- func move(gameId int64, p *player.Player, players []*player.Player, bs *board.Board) {
- if bs.Finish.X == p.Pos.X && p.Pos.Y == bs.Finish.Y {
- fmt.Println("HELP i'm finished stop me!!")
- time.Sleep(1 * time.Second)
- return
- }
- //determine move
- viewPortX := 0
- viewPortY := 0
- if viewPortHeight <= bs.Height || viewPortWidth <= bs.Width {
- viewPortX = p.Pos.X - 1
- viewPortY = p.Pos.Y - viewPortHeight/2
- }
- viewPort := getViewPort(viewPortX, viewPortY, viewPortWidth, viewPortHeight, gameId, bs)
- //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)
- direction := "E"
- igloY := bs.Finish.Y
- if bs.Finish.Y < viewPort.y {
- //iglo ten noorden van viewport
- fmt.Println("iglo boven")
- igloY = 0
- /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY <= viewPort.y+viewPortHeight {
- igloY++
- }*/
- } else if bs.Finish.Y > viewPort.y+viewPort.Board.Height {
- //iglo ten zuiden van viewport
- fmt.Println("iglo onder")
- igloY = viewPort.Board.Height - 1
- /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY >= viewPort.y+viewPortHeight {
- igloY--
- }*/
- }
- igloX := viewPort.Board.Width
- if viewPort.x < bs.Finish.X && viewPort.x+viewPort.Board.Width > bs.Finish.X {
- igloX = bs.Finish.X
- }
- //fmt.Printf("Virtuele iglo geplaast op x %v y %v\n", igloX, igloY)
- dist := calcDist(igloX, igloY, viewPort)
- /*for i := 0;i< viewPort.Board.Height;i++ {
- for j := 0;j< viewPort.Board.Width;j++ {
- if(j == p.Pos.X && i == p.Pos.Y) {
- fmt.Printf("X")
- }
- if(j == bs.Finish.X && i == bs.Finish.Y) {
- fmt.Printf("I")
- }
- fmt.Printf("%v ", dist[(i*viewPort.Board.Width)+j])
- }
- fmt.Printf("\n")
- }*/
- smallestDist := math.MaxInt32
- if p.Pos.X+1 < viewPort.width && dist[toIndex(p.Pos.X+1, p.Pos.Y, viewPort.Board.Width)] != 0 {
- direction = "E"
- smallestDist = dist[toIndex(p.Pos.X+1, p.Pos.Y, viewPort.Board.Width)]
- }
- 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)] {
- direction = "W"
- smallestDist = dist[toIndex(p.Pos.X-1, p.Pos.Y, viewPort.Board.Width)]
- }
- 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)] {
- direction = "S"
- smallestDist = dist[toIndex(p.Pos.X, p.Pos.Y+1, viewPort.Board.Width)]
- }
- 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)] {
- direction = "N"
- smallestDist = dist[toIndex(p.Pos.X, p.Pos.Y-1, viewPort.Board.Width)]
- }
- //send move
- url := "http://localhost:8080/games/" + strconv.FormatInt(gameId, 10) + "/move/" + p.Id + "/" + direction
- fmt.Println("move:>", url, smallestDist)
- http.Post(url, "text/plain", nil)
- //update x,y
- switch direction {
- case "N":
- p.Pos.Y--
- case "E":
- p.Pos.X++
- case "S":
- p.Pos.Y++
- case "W":
- p.Pos.X--
- }
- //fmt.Printf("new pos x=%v y=%v\n", p.Pos.X, p.Pos.Y)
- }
- func toXy(index, boardWidth int) (x, y int) {
- x = index % boardWidth
- y = (index - x) / boardWidth
- return x, y
- }
- func toIndex(x, y, boardWidth int) (index int) {
- return y*boardWidth + x
- }
- func calcDist(igloX, igloY int, viewPort *viewport) map[int]int {
- distance := make(map[int]int)
- s := NewQueue()
- index := toIndex(igloX, igloY, viewPort.Board.Width)
- s.Push(index)
- distance[index] = -1
- for s.Len() != 0 {
- i := s.Poll()
- x, y := toXy(i, viewPort.Board.Width)
- if x+1 < viewPort.Board.Width {
- newI := toIndex(x+1, y, viewPort.Board.Width)
- if distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock {
- distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
- s.Push(newI)
- }
- }
- if x-1 >= 0 {
- newI := toIndex(x-1, y, viewPort.Board.Width)
- if distance[newI] == 0 && viewPort.Board.Get(x-1, y) != board.Rock {
- distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
- s.Push(newI)
- }
- }
- if y+1 < viewPort.Board.Height {
- newI := toIndex(x, y+1, viewPort.Board.Width)
- if distance[newI] == 0 && viewPort.Board.Get(x, y+1) != board.Rock {
- distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
- s.Push(newI)
- }
- }
- if y-1 >= 0 {
- newI := toIndex(x, y-1, viewPort.Board.Width)
- if distance[newI] == 0 && viewPort.Board.Get(x, y-1) != board.Rock {
- distance[newI] = max(distance[toIndex(x, y, viewPort.Board.Width)], 0) + 1
- s.Push(newI)
- }
- }
- }
- return distance
- }
- /*
- type stack []int
- func (s stack) Empty() bool { return len(s) == 0 }
- func (s stack) Peek() int { return s[len(s)-1] }
- func (s *stack) Put(i int) { (*s) = append((*s), i) }
- func (s *stack) Pop() int {
- d := (*s)[len(*s)-1]
- (*s) = (*s)[:len(*s)-1]
- return d
- }
- */
- type queuenode struct {
- data int
- next *queuenode
- }
- // A go-routine safe FIFO (first in first out) data stucture.
- type Queue struct {
- head *queuenode
- tail *queuenode
- count int
- }
- // Creates a new pointer to a new queue.
- func NewQueue() *Queue {
- q := &Queue{}
- return q
- }
- // Returns the number of elements in the queue (i.e. size/length)
- // go-routine safe.
- func (q *Queue) Len() int {
- return q.count
- }
- // Pushes/inserts a value at the end/tail of the queue.
- // Note: this function does mutate the queue.
- // go-routine safe.
- func (q *Queue) Push(item int) {
- n := &queuenode{data: item}
- if q.tail == nil {
- q.tail = n
- q.head = n
- } else {
- q.tail.next = n
- q.tail = n
- }
- q.count++
- }
- // Returns the value at the front of the queue.
- // i.e. the oldest value in the queue.
- // Note: this function does mutate the queue.
- // go-routine safe.
- func (q *Queue) Poll() int {
- n := q.head
- q.head = n.next
- if q.head == nil {
- q.tail = nil
- }
- q.count--
- return n.data
- }
- // Returns a read value at the front of the queue.
- // i.e. the oldest value in the queue.
- // Note: this function does NOT mutate the queue.
- // go-routine safe.
- func (q *Queue) Peek() int {
- n := q.head
- return n.data
- }
- func playerJoin(p *player.Player) {
- }
- func initLogging() {
- logFile, err := os.Create("server.log")
- if err == nil {
- log.SetOutput(logFile)
- } else {
- log.Println("ERROR: Cannot open log file, using console.")
- log.Printf("%v=n", err)
- }
- }
|