Browse Source

moved code out of awkward bots repo

master
Stephen McQuay 7 years ago
parent
commit
e33f2c0c4f
7 changed files with 233 additions and 38 deletions
  1. +1
    -0
      .gitignore
  2. +44
    -10
      game.go
  3. +7
    -8
      http.go
  4. +7
    -8
      player.go
  5. +89
    -10
      protocol.go
  6. +84
    -0
      robot.go
  7. +1
    -2
      spectator.go

+ 1
- 0
.gitignore View File

@ -1,2 +1,3 @@
botserv
*.swp
tags

+ 44
- 10
game.go View File

@ -1,7 +1,6 @@
package main
import (
"bitbucket.org/hackerbots/bot"
v "bitbucket.org/hackerbots/vector"
"log"
"sort"
@ -10,11 +9,46 @@ import (
const maxPlayer = 128
type Config struct {
ID string `json:"id"`
Name string `json:"name"`
// TODO: candidate for embedding?
Stats Stats `json:"stats"`
}
type 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"`
}
func (bs *Boardstate) EmptySlices() {
bs.Robots = bs.Robots[:0]
bs.Projectiles = bs.Projectiles[:0]
bs.Splosions = bs.Splosions[:0]
}
func NewBoardstate() *Boardstate {
return &Boardstate{
Robots: []Robot{},
Projectiles: []Projectile{},
Type: "boardstate",
}
}
type Scanner struct {
Position v.Point2d `json:"position"`
Stats Stats `json:"stats"`
}
type game struct {
id string
players map[*player]bool
projectiles map[*bot.Projectile]bool
splosions map[*bot.Splosion]bool
projectiles map[*Projectile]bool
splosions map[*Splosion]bool
register chan *player
unregister chan *player
turn int
@ -30,8 +64,8 @@ func NewGame(id string, width, height float64) *game {
id: id,
register: make(chan *player),
unregister: make(chan *player, maxPlayer),
projectiles: make(map[*bot.Projectile]bool),
splosions: make(map[*bot.Splosion]bool),
projectiles: make(map[*Projectile]bool),
splosions: make(map[*Splosion]bool),
players: make(map[*player]bool),
turn: 0,
width: width,
@ -46,7 +80,7 @@ func NewGame(id string, width, height float64) *game {
func (g *game) run() {
var t0, t1 time.Time
payload := bot.NewBoardstate()
payload := NewBoardstate()
for {
select {
case <-g.kill:
@ -102,7 +136,7 @@ func (g *game) run() {
}
payload.Robots = append(payload.Robots, p.Robot)
}
sort.Sort(bot.RobotSorter{Robots: payload.Robots})
sort.Sort(RobotSorter{Robots: payload.Robots})
payload.Projectiles = append(payload.Projectiles,
g.nudgeProjectiles()...,
@ -150,8 +184,8 @@ func (g *game) run() {
}
}
func (g *game) nudgeProjectiles() (rprojectiles []bot.Projectile) {
rprojectiles = make([]bot.Projectile, 0)
func (g *game) nudgeProjectiles() (rprojectiles []Projectile) {
rprojectiles = make([]Projectile, 0)
for p := range g.projectiles {
newPos := v.Move(p.Position, p.MoveTo, float64(p.Speed), delta)
@ -170,7 +204,7 @@ func (g *game) nudgeProjectiles() (rprojectiles []bot.Projectile) {
delete(g.projectiles, p)
// Spawn a splosion
splo := &bot.Splosion{
splo := &Splosion{
Id: p.Id,
Position: p.Position,
Radius: p.Radius,

+ 7
- 8
http.go View File

@ -1,7 +1,6 @@
package main
import (
"bitbucket.org/hackerbots/bot"
"code.google.com/p/go.net/websocket"
"encoding/json"
"fmt"
@ -81,7 +80,7 @@ func listGames(w http.ResponseWriter, req *http.Request) {
func addPlayer(ws *websocket.Conn) {
// route to appropriate game ...
var gid bot.GameID
var gid GameID
err := websocket.JSON.Receive(ws, &gid)
if err != nil {
log.Println("problem parsing the requested game id")
@ -94,7 +93,7 @@ func addPlayer(ws *websocket.Conn) {
if !ok {
log.Println("ERROR: game not found")
websocket.JSON.Send(ws, bot.NewFailure("game 404"))
websocket.JSON.Send(ws, NewFailure("game 404"))
return
}
@ -102,18 +101,18 @@ func addPlayer(ws *websocket.Conn) {
conf, err := Negociate(ws, id, game.width, game.height)
if err != nil {
websocket.JSON.Send(ws, bot.NewFailure(err.Error()))
websocket.JSON.Send(ws, NewFailure(err.Error()))
}
if conf != nil {
p := &player{
Robot: bot.Robot{
Robot: Robot{
Stats: conf.Stats,
Id: id,
Name: conf.Name,
Health: conf.Stats.Hp,
Scanners: make([]bot.Scanner, 0)},
send: make(chan *bot.Boardstate),
Scanners: make([]Scanner, 0)},
send: make(chan *Boardstate),
ws: ws,
}
p.reset()
@ -126,7 +125,7 @@ func addPlayer(ws *websocket.Conn) {
log.Printf("game %s: player %v has been disconnected from this game\n", gid.Id, p.Robot.Id)
} else {
s := &Spectator{
send: make(chan *bot.Boardstate),
send: make(chan *Boardstate),
ws: ws,
}
game.sregister <- s

+ 7
- 8
player.go View File

@ -1,7 +1,6 @@
package main
import (
"bitbucket.org/hackerbots/bot"
v "bitbucket.org/hackerbots/vector"
"code.google.com/p/go.net/websocket"
"log"
@ -11,9 +10,9 @@ import (
type player struct {
ws *websocket.Conn
Robot bot.Robot
send chan *bot.Boardstate
Instruction bot.Instruction
Robot Robot
send chan *Boardstate
Instruction Instruction
}
func (p *player) sender() {
@ -31,7 +30,7 @@ func (p *player) recv() {
for {
// XXX: need to mark myself as having received something, also binding
// such action to a particular game turn ID
var msg bot.Instruction
var msg Instruction
err := websocket.JSON.Receive(p.ws, &msg)
if err != nil {
// TODO: perhaps we could be a bit more precise in the handling of
@ -136,7 +135,7 @@ func (p *player) scan(players map[*player]bool) {
}
dist := v.Distance(player.Robot.Position, p.Robot.Position)
if dist < float64(p.Robot.Stats.ScannerRadius) {
s := bot.Scanner{
s := Scanner{
Position: v.Point2d{
X: player.Robot.Position.X,
Y: player.Robot.Position.Y,
@ -147,7 +146,7 @@ func (p *player) scan(players map[*player]bool) {
}
}
func (p *player) fire(projectiles map[*bot.Projectile]bool) *bot.Projectile {
func (p *player) fire(projectiles map[*Projectile]bool) *Projectile {
// XXX: is this to prevent us from having multiple projectiles from the
// same bot?
for proj := range projectiles {
@ -156,7 +155,7 @@ func (p *player) fire(projectiles map[*bot.Projectile]bool) *bot.Projectile {
}
}
return &bot.Projectile{
return &Projectile{
Id: p.Robot.Id,
Position: p.Robot.Position,
MoveTo: *p.Robot.FireAt,

+ 89
- 10
protocol.go View File

@ -1,21 +1,100 @@
package main
import (
"bitbucket.org/hackerbots/bot"
"code.google.com/p/go.net/websocket"
"errors"
"log"
)
func Negociate(ws *websocket.Conn, id string, width, height float64) (*bot.Config, error) {
type GameID struct {
Id string `json:"id"`
}
// > identify
type IdRequest struct {
Type string `json:"type"`
AssignedID string `json:"id"`
Failure
}
func NewIdRequest(id string) *IdRequest {
return &IdRequest{
Type: "idreq",
AssignedID: id,
}
}
// < [robot | spectator], name, client-type, game ID
type ClientID struct {
Type string `json:"type"`
Name string `json:"name"`
Useragent string `json:"useragent"`
}
func (c *ClientID) Valid() (bool, string) {
switch c.Type {
case "robot", "spectator":
return true, ""
}
return false, "usergent must be 'robot' or 'spectator'"
}
type BoardSize struct {
Width float64 `json:"width"`
Height float64 `json:"height"`
}
type GameParam struct {
BoardSize BoardSize `json:"boardsize"`
Type string `json:"type"`
}
// > [OK | FULL | NOT AUTH], board size, game params
func NewGameParam(w, h float64) *GameParam {
return &GameParam{
BoardSize: BoardSize{
Width: w,
Height: h,
},
Type: "gameparam",
}
}
type Handshake struct {
ID string `json:"id"`
Success bool `json:"success"`
Type string `json:"type"`
}
func NewHandshake(id string, success bool) *Handshake {
return &Handshake{
ID: id,
Success: success,
Type: "handshake",
}
}
type Failure struct {
Reason string `json:"reason"`
Type string `json:"type"`
}
func NewFailure(reason string) *Failure {
return &Failure{
Reason: reason,
Type: "failure",
}
}
func Negociate(ws *websocket.Conn, id string, width, height float64) (*Config, error) {
var err error
err = websocket.JSON.Send(ws, bot.NewIdRequest(id))
err = websocket.JSON.Send(ws, NewIdRequest(id))
if err != nil {
return nil, errors.New("generic server error")
}
var clientid bot.ClientID
var clientid ClientID
err = websocket.JSON.Receive(ws, &clientid)
if err != nil {
return nil, errors.New("could not parse id")
@ -24,22 +103,22 @@ func Negociate(ws *websocket.Conn, id string, width, height float64) (*bot.Confi
log.Printf("clientid is invalid: %+v", clientid)
websocket.JSON.Send(
ws,
bot.NewFailure(msg),
NewFailure(msg),
)
return nil, errors.New(msg)
}
log.Printf("clientid: %+v", clientid)
gameParam := bot.NewGameParam(width, height)
gameParam := NewGameParam(width, height)
err = websocket.JSON.Send(ws, gameParam)
if err != nil {
websocket.JSON.Send(ws, bot.NewFailure("generic server error"))
websocket.JSON.Send(ws, NewFailure("generic server error"))
return nil, err
}
log.Printf("gameparam: %+v", gameParam)
switch clientid.Type {
case "robot":
var conf bot.Config
var conf Config
log.Printf("got here?")
for {
log.Printf("%s Waiting for client to send conf ...", id)
@ -50,10 +129,10 @@ func Negociate(ws *websocket.Conn, id string, width, height float64) (*bot.Confi
}
// TODO: verify conf's type
if conf.Stats.Valid() {
_ = websocket.JSON.Send(ws, bot.NewHandshake(id, true))
_ = websocket.JSON.Send(ws, NewHandshake(id, true))
break
} else {
_ = websocket.JSON.Send(ws, bot.NewHandshake(id, false))
_ = websocket.JSON.Send(ws, NewHandshake(id, false))
}
}
conf.Name = clientid.Name

+ 84
- 0
robot.go View File

@ -0,0 +1,84 @@
package main
import (
v "bitbucket.org/hackerbots/vector"
)
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 v.Point2d `json:"position"`
Heading v.Vector2d `json:"heading"`
MoveTo *v.Point2d `json:"move_to,omitempty"`
FireAt *v.Point2d `json:"fire_at,omitempty"`
Scanners []Scanner `json:"scanners"`
}
type RobotSorter struct {
Robots []Robot
}
func (s RobotSorter) Len() int {
return len(s.Robots)
}
func (s RobotSorter) Swap(i, j int) {
s.Robots[i], s.Robots[j] = s.Robots[j], s.Robots[i]
}
func (s RobotSorter) Less(i, j int) bool {
return s.Robots[i].Id < s.Robots[j].Id
}
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"`
}
func (s Stats) Valid() bool {
total := int(s.Speed) + s.Hp + s.WeaponRadius + s.ScannerRadius
if total > 500 {
return false
}
return true
}
type Projectile struct {
Id string `json:"id"`
Position v.Point2d `json:"position"`
MoveTo v.Point2d `json:"move_to"`
Radius int `json:"radius"`
Speed float64 `json:"speed"`
Damage int `json:"damage"`
}
type Splosion struct {
Id string `json:"id"`
Position v.Point2d `json:"position"`
Radius int `json:"radius"`
MaxDamage int `json:"damage"`
MinDamage int `json:"damage"`
Lifespan int `json:"lifespan"`
}
func (s *Splosion) Tick() {
s.Lifespan--
}
func (s *Splosion) Alive() bool {
return s.Lifespan > 0
}
type Instruction struct {
MoveTo *v.Point2d `json:"move_to,omitempty"`
FireAt *v.Point2d `json:"fire_at,omitempty"`
Stats Stats `json:"stats"`
}

+ 1
- 2
spectator.go View File

@ -1,13 +1,12 @@
package main
import (
"bitbucket.org/hackerbots/bot"
"code.google.com/p/go.net/websocket"
)
type Spectator struct {
ws *websocket.Conn
send chan *bot.Boardstate
send chan *Boardstate
}
func (s *Spectator) sender() {

Loading…
Cancel
Save