package main import ( "math" "bytes" "encoding/json" "fmt" "io/ioutil" "log" "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) subscribeToGame(pu) } func subscribeToGame(pu chan *events.PlayerUpdate) { sub := stomp.Subscribe("game") for { announcement := <-sub gs := new(events.GameStart) json.Unmarshal(announcement.Body, &gs) log.Printf("announcement type: %v ", strconv.FormatInt(gs.GameId, 10)) gameEndChan := make(chan bool) if "GAME_START" == gs.Type { go joinGame(gs.GameId, gameEndChan, pu) } else { gameEndChan <- 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) { //join game p := &player.Player{ Id: "Zeus", 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() //determine to avoind north or south north := true if boardSummery.Finish.Y > p.Pos.Y { north = false } for { select { case <-gameEndChan: return case playerUpdate := <-pu: if playerUpdate.GameId == gameId { players = playerUpdate.Players 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, north) time.Sleep(2 * time.Second) } } } 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 = max(x, 0) x = min(x, bs.Width) y = max(y, 0) y = min(y, bs.Height) if x+width > bs.Width { width = bs.Width - x } if y+height > bs.Height { height = bs.Height - x } 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) 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 { fmt.Printf("retrieving from viewport x %v y %v position in viewport x %v y %v", x, y, x-v.x, y-v.y) return v.Board.Get(x-v.x, y-v.y) } const viewPortWidth = 32 const viewPortHeight = 32 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, north bool) { //determine move viewPortX := p.Pos.X - 1 viewPortY := p.Pos.Y - 1 if north { viewPortX = viewPortX - viewPortHeight } viewPort := getViewPort(viewPortX, viewPortY, viewPortWidth, viewPortHeight, gameId, bs) direction := "W" fmt.Printf("p.Pos.X+1 %v p.Pos.Y %v\n", p.Pos.X+1, p.Pos.Y) if viewPort.Get(p.Pos.X+1, p.Pos.Y) != board.Rock { direction = "E" } var igloY int if bs.Finish.Y > viewPort.y { //iglo ten noorden van ons igloY = 0 /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY <= viewPort.y+viewPortHeight { igloY++ }*/ } else if(bs.Finish.Y < viewPort.y+viewPortHeight) { //iglo ten zuiden van ons igloY = viewPort.Board.Height-1 /*for viewPort.Get(viewPort.x+viewPortWidth, igloY) == board.Rock && igloY >= viewPort.y+viewPortHeight { igloY-- }*/ } else { igloY = bs.Finish.Y } igloX := viewPort.Board.Width calcDist(igloX, igloY, viewPort) smallestDist := math.MaxInt32 //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.Y++ } 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 := stack{} index := toIndex(igloX, igloY, viewPort.Board.Width) s.Put(index) distance[index] = -1 for !s.Empty() { i := s.Pop() x, y := toXy(i, viewPort.Board.Width) if(x+1 < viewPort.width) { newI := toIndex(x+1, y, viewPort.Board.Width) if(distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock) { distance[newI] = distance[toIndex(x, y, viewPort.Board.Width)] + 1 s.Put(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] = distance[toIndex(x, y, viewPort.Board.Width)] + 1 s.Put(newI) } } if(y+1 < viewPort.height) { newI := toIndex(x, y+1, viewPort.Board.Width) if(distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock) { distance[newI] = distance[toIndex(x, y, viewPort.Board.Width)] + 1 s.Put(newI) } } if(y-1 > 0) { newI := toIndex(x, y-1, viewPort.Board.Width) if(distance[newI] == 0 && viewPort.Board.Get(x+1, y) != board.Rock) { distance[newI] = distance[toIndex(x, y, viewPort.Board.Width)] + 1 s.Put(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 } 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) } }