package main import ( "bitbucket.org/hackerbots/vector" "code.google.com/p/go.net/websocket" "errors" "fmt" "log" "math/rand" "sync" ) func connect(server string, port int) (*websocket.Conn, error) { origin := "http://localhost/" url := fmt.Sprintf("ws://%s:%d/ws/", server, port) return websocket.Dial(url, "", origin) } type robot struct { server string port int ws *websocket.Conn game GameParam playerId string name string stats StatsRequest // TODO: don't know if I like how this is done ... I would rather send // a signal over a chanel wg *sync.WaitGroup } func (r *robot) negociate() (err error) { log.Printf("%s: trying to connect to game '%s'", r.name, r.game.name) r.ws, err = connect(r.server, r.port) if err != nil { return errors.New(fmt.Sprintf("connection failure: %s", err)) } err = websocket.JSON.Send(r.ws, struct { Id string `json:"id"` }{ r.game.name, }) if err != nil { return err } var idreq struct { Type string `json:"type"` PlayerId string `json:"id"` } err = websocket.JSON.Receive(r.ws, &idreq) if err != nil || idreq.Type == "failure" { return errors.New(fmt.Sprintf("failure: %+v", idreq)) } log.Printf("%s: idreq: %+v", r.name, idreq) err = websocket.JSON.Send(r.ws, struct { Type string `json:"type"` Name string `json:"name"` Useragent string `json:"useragent"` }{ Name: r.name, Useragent: "gobot", Type: "robot", }) if err != nil { return err } err = websocket.JSON.Receive(r.ws, &r.game) if r.game.Type != "gameparam" { return errors.New("didn't receive a good gameparam") } log.Printf("%s: game parameters: %+v", r.name, r.game) conf := ClientConfig{ ID: r.game.name, Stats: map[string]StatsRequest{ r.name: r.stats, }, } err = websocket.JSON.Send(r.ws, conf) var handshake struct { Id string `json:"id"` Success bool `json:"success"` Type string `json:"type"` } websocket.JSON.Receive(r.ws, &handshake) if !handshake.Success { return errors.New("failed to validate correct stats request") } r.playerId = handshake.Id log.Printf("%s: handshake: %+v", r.name, handshake) return nil } func (r *robot) play() { defer r.wg.Done() var err error err = r.negociate() if err != nil { log.Printf("%s: failed to negociate: %s", r.name, err) return } log.Printf("%s: %+v", r.name, r) // TODO: var target govector.Point2d moveto := govector.Point2d{ X: rand.Float32() * r.game.BoardSize.Width, Y: rand.Float32() * r.game.BoardSize.Height, } log.Printf("%s: moveto: %+v", r.name, moveto) log.Printf("%s: starting loop", r.name) for { var boardstate Boardstate err = websocket.JSON.Receive(r.ws, &boardstate) if *verbose { log.Printf("%+v", boardstate) } if err != nil { log.Printf("%s: Connection lost", r.name) return } for _, me := range boardstate.MyRobots { me = boardstate.MyRobots[0] if govector.Distance(me.Position, moveto) < 3.0 { log.Printf("%s: old: %+v: %+v", r.name, me.Position, moveto) moveto = govector.Point2d{ X: rand.Float32() * r.game.BoardSize.Width, Y: rand.Float32() * r.game.BoardSize.Height, } log.Printf("%s: new: %+v: %+v", r.name, me.Position, moveto) } // TODO: send instructions instruction := map[string]Instruction{ me.Id: { MoveTo: &moveto, FireAt: &moveto, }, } err = websocket.JSON.Send(r.ws, instruction) if err != nil { log.Println(err) return } } } }