client/robot.go

153 lines
3.4 KiB
Go

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
}
}
}
}