package main import ( "bitbucket.org/hackerbots/vector" "code.google.com/p/go.net/websocket" "encoding/json" "errors" "flag" "fmt" "log" "math/rand" "net/http" "time" ) var hp = flag.Int("hp", 150, "") var speed = flag.Float64("speed", 150, "") var acceleration = flag.Float64("acceleration", 10, "") var weaponRadius = flag.Int("wrad", 100, "weapon radius") var scannerRadius = flag.Int("srad", 100, "scanner radius") var server = flag.String("server", "localhost", "server hostname") var port = flag.Int("port", 8666, "server port") var botname = flag.String("name", "gobot", "the name that other players will see") var verbose = flag.Bool("verbose", false, "run verbosly") type infos struct { id string width, height float64 } type Stats struct { Hp int `json:"hp"` Speed float64 `json:"speed"` Acceleration float64 `json:"acceleration"` WeaponRadius int `json:"weapon_radius"` ScannerRadius int `json:"scanner_radius"` } type Scanner struct { Position govector.Point2d `json:"position"` Stats Stats `json:"stats"` } type Robot struct { Id string `json:"id"` Name string `json:"name"` Stats Stats `json:"stats"` TargetSpeed float64 `json:"speed"` Speed float64 `json:"speed"` Health int `json:"health"` Position govector.Point2d `json:"position"` Heading govector.Vector2d `json:"heading"` MoveTo *govector.Point2d `json:"move_to,omitempty"` FireAt *govector.Point2d `json:"fire_at,omitempty"` Scanners []Scanner `json:"scanners"` } type Projectile struct { Id string `json:"id"` Position govector.Point2d `json:"position"` MoveTo govector.Point2d `json:"move_to"` Radius int `json:"radius"` Speed float64 `json:"speed"` Damage int `json:"damage"` } type Splosion struct { Id string `json:"id"` Position govector.Point2d `json:"position"` Radius int `json:"radius"` MaxDamage int `json:"damage"` MinDamage int `json:"damage"` Lifespan int `json:"lifespan"` } type Instruction struct { MoveTo *govector.Point2d `json:"move_to,omitempty"` FireAt *govector.Point2d `json:"fire_at,omitempty"` Stats Stats `json:"stats"` } func connect() (*websocket.Conn, error) { origin := "http://localhost/" url := fmt.Sprintf("ws://%s:%d/ws/", *server, *port) return websocket.Dial(url, "", origin) } func createGame() (string, error) { url := fmt.Sprintf("http://%s:%d/game/start/", *server, *port) resp, err := http.Get(url) if err != nil { return "", err } defer resp.Body.Close() var g struct { Id string `json:"id"` } if err := json.NewDecoder(resp.Body).Decode(&g); err != nil { return "", err } return g.Id, err } func negociate(ws *websocket.Conn, gameid string) (i *infos, err error) { log.Printf("trying to connect to game %s", gameid) err = websocket.JSON.Send(ws, struct { Id string `json:"id"` }{ gameid, }) if err != nil { return nil, err } var idreq struct { Type string `json:"type"` AssignedID string `json:"id"` } err = websocket.JSON.Receive(ws, &idreq) if err != nil || idreq.Type == "failure" { return nil, errors.New(fmt.Sprintf("failure: %+v", idreq)) } log.Printf("%+v", idreq) err = websocket.JSON.Send(ws, struct { Type string `json:"type"` Name string `json:"name"` Useragent string `json:"useragent"` }{ Name: *botname, Useragent: "gobot", Type: "robot", }) if err != nil { return nil, err } type BoardSize struct { Width float64 `json:"width"` Height float64 `json:"height"` } var gameparam struct { BoardSize BoardSize `json:"boardsize"` Type string `json:"type"` } err = websocket.JSON.Receive(ws, &gameparam) log.Printf("gameparam: %+v", gameparam) if gameparam.Type != "gameparam" { return nil, errors.New("didn't receive a good gameparam") } log.Printf("%+v", gameparam) err = websocket.JSON.Send(ws, &struct { ID string `json:"id"` Name string `json:"name"` // TODO: candidate for embedding? Stats Stats `json:"stats"` }{ ID: gameid, Name: *botname, Stats: Stats{ Hp: *hp, Speed: *speed, Acceleration: *acceleration, WeaponRadius: *weaponRadius, ScannerRadius: *scannerRadius, }, }) var handshake struct { ID string `json:"id"` Success bool `json:"success"` Type string `json:"type"` } websocket.JSON.Receive(ws, &handshake) if !handshake.Success { return nil, errors.New("failed to validate correct stats request") } log.Printf("%+v", handshake) return &infos{ id: idreq.AssignedID, width: gameparam.BoardSize.Width, height: gameparam.BoardSize.Height, }, err } func main() { rand.Seed(time.Now().UnixNano()) var err error var gameid string flag.Parse() if flag.NArg() < 1 { gameid, err = createGame() if err != nil { log.Fatal(err) } } else { gameid = flag.Arg(0) } ws, err := connect() if err != nil { log.Fatal(err) } board_info, err := negociate(ws, gameid) if err != nil { log.Fatal(err) } // TODO: var target govector.Point2d moveto := govector.Point2d{ X: rand.Float64() * board_info.width, Y: rand.Float64() * board_info.height, } log.Printf("%+v", moveto) var me Robot log.Printf("negociated well, starting loop") for { var boardstate struct { Robots []Robot `json:"robots"` Projectiles []Projectile `json:"projectiles"` Splosions []Splosion `json:"splosions"` Reset bool `json:"reset"` Type string `json:"type"` Turn int `json:"turn"` } err = websocket.JSON.Receive(ws, &boardstate) if *verbose { log.Printf("%+v", boardstate) } if err != nil { log.Fatal("Connection lost") } for _, bot := range boardstate.Robots { if bot.Id == board_info.id { me = bot break } } if govector.Distance(me.Position, moveto) < 3.0 { log.Printf("old: %+v: %+v", me.Position, moveto) moveto = govector.Point2d{ X: rand.Float64() * board_info.width, Y: rand.Float64() * board_info.height, } log.Printf("new: %+v: %+v", me.Position, moveto) } // TODO: send instructions err = websocket.JSON.Send(ws, Instruction{ MoveTo: &moveto, }) if err != nil { log.Fatal(err) } } }