206 lines
3.0 KiB
Go
206 lines
3.0 KiB
Go
package game
|
|
|
|
import "log"
|
|
|
|
func UpdateState(s State, sOld State) State {
|
|
for i := range s.Teams {
|
|
s = doCommand(chooseCommand(s, i), s, i)
|
|
if b := ActiveBot(s.Teams[i]); b != nil {
|
|
s = moveBot(s, i, *b)
|
|
}
|
|
s = maybePassBaton(s, i)
|
|
}
|
|
|
|
for _, t := range s.Teams {
|
|
if b := ActiveBot(t); b != nil && won(*b, s) {
|
|
log.Printf("team %d won", t.id)
|
|
s.GameOver = true
|
|
}
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func maybePassBaton(s State, teamID int) State {
|
|
t := s.Teams[teamID]
|
|
h := ActiveBot(t)
|
|
if h == nil {
|
|
return s
|
|
}
|
|
|
|
for i, b := range t.Bots {
|
|
if h.ID >= b.ID || h.Position.Lane != b.Position.Lane {
|
|
continue
|
|
}
|
|
if abs(b.Position.Pos-h.Position.Pos) <= passDistance {
|
|
h.v = 0
|
|
h.a = 0
|
|
s = updateBot(s, teamID, *h)
|
|
newH := t.Bots[i]
|
|
newH.a = baseAccel
|
|
t.Baton.HolderID = newH.ID
|
|
s = updateTeam(s, t)
|
|
return updateBot(s, teamID, newH)
|
|
}
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func ActiveBot(t Team) *Bot {
|
|
for _, b := range t.Bots {
|
|
if b.ID == t.Baton.HolderID {
|
|
return &b
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func updateBot(s State, teamID int, b Bot) State {
|
|
t := s.Teams[teamID]
|
|
for i, bb := range t.Bots {
|
|
if bb.ID == b.ID {
|
|
bots := append([]Bot{}, t.Bots[:i]...)
|
|
bots = append(bots, b)
|
|
bots = append(bots, t.Bots[i+1:]...)
|
|
t.Bots = bots
|
|
break
|
|
}
|
|
}
|
|
|
|
s = updateTeam(s, t)
|
|
return s
|
|
}
|
|
|
|
func updateTeam(s State, t Team) State {
|
|
teams := append([]Team{}, s.Teams[:t.id]...)
|
|
teams = append(teams, t)
|
|
teams = append(teams, s.Teams[t.id+1:]...)
|
|
s.Teams = teams
|
|
|
|
return s
|
|
}
|
|
|
|
func won(b Bot, s State) bool {
|
|
return b.Position.Pos >= Steps
|
|
}
|
|
|
|
func gameOver(s State) bool {
|
|
for _, t := range s.Teams {
|
|
if t.won {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func abs(n int) int {
|
|
if n < 0 {
|
|
return -n
|
|
}
|
|
return n
|
|
}
|
|
|
|
type State struct {
|
|
Teams []Team
|
|
Obstacles []Obstacle
|
|
GameOver bool
|
|
}
|
|
|
|
type Team struct {
|
|
id int
|
|
Bots []Bot
|
|
Baton Baton
|
|
won bool
|
|
Lane int
|
|
}
|
|
|
|
func (t Team) BatonHolder() *Bot {
|
|
for _, b := range t.Bots {
|
|
if b.ID == t.Baton.HolderID {
|
|
return &b
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Bot struct {
|
|
ID int
|
|
Position Position
|
|
v int
|
|
a int
|
|
}
|
|
|
|
type Position struct {
|
|
Lane int
|
|
Pos int
|
|
}
|
|
|
|
type Baton struct {
|
|
HolderID int
|
|
}
|
|
|
|
type Obstacle struct {
|
|
Position Position
|
|
}
|
|
|
|
func NewState() State {
|
|
var teams []Team
|
|
for i := 0; i < NumTeams; i++ {
|
|
var bots []Bot
|
|
for j := 0; j < numBots; j++ {
|
|
b := Bot{
|
|
ID: i*NumTeams + j,
|
|
Position: Position{
|
|
Lane: i,
|
|
Pos: j * (Steps / numBots),
|
|
},
|
|
}
|
|
bots = append(bots, b)
|
|
}
|
|
teams = append(teams, Team{
|
|
id: i,
|
|
Bots: bots,
|
|
Baton: Baton{HolderID: i * NumTeams},
|
|
Lane: i,
|
|
})
|
|
}
|
|
|
|
return State{
|
|
Teams: teams,
|
|
Obstacles: []Obstacle{
|
|
{
|
|
Position: Position{
|
|
Lane: 0,
|
|
Pos: Steps / 3,
|
|
},
|
|
},
|
|
{
|
|
Position: Position{
|
|
Lane: 1,
|
|
Pos: Steps * 2 / 3,
|
|
},
|
|
},
|
|
{
|
|
Position: Position{
|
|
Lane: 2,
|
|
Pos: Steps / 2,
|
|
},
|
|
},
|
|
{
|
|
Position: Position{
|
|
Lane: 3,
|
|
Pos: Steps * 3 / 4,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
const (
|
|
Steps = 40
|
|
numBots = 5
|
|
NumTeams = 4
|
|
NumLanes = 4
|
|
)
|