diff --git a/game/ai.go b/game/ai.go index cd1acfa..916d167 100644 --- a/game/ai.go +++ b/game/ai.go @@ -2,8 +2,9 @@ package game import "log" -func chooseCommand(t Team, s State) command { - h := t.Baton.Holder +func chooseCommand(s State, teamID int) command { + t := s.Teams[teamID] + h := t.BatonHolder() if collide(h.Pos+1, h.Lane, s) { if h.Lane <= t.Lane { return left @@ -13,7 +14,7 @@ func chooseCommand(t Team, s State) command { var nextBot *Bot for i, b := range t.Bots { - if b.id == h.id+1 { + if b.ID == h.ID+1 { nextBot = &t.Bots[i] break } diff --git a/game/commands.go b/game/commands.go index 2556e00..df470aa 100644 --- a/game/commands.go +++ b/game/commands.go @@ -1,24 +1,8 @@ package game -import "math/rand" - -func doCommand(cmd command, b *Bot) { - da := 1 - da += rand.Intn(3) - 1 - - switch cmd { - case speedUp: - b.a += da - accelerate(b) - case slowDown: - b.a -= da - accelerate(b) - case left: - b.Lane++ - case right: - b.Lane-- - } -} +import ( + "math/rand" +) type command int @@ -28,3 +12,28 @@ const ( left right ) + +func doCommand(cmd command, s State, teamID int) State { + da := 1 + da += rand.Intn(3) - 1 + + b := activeBot(s.Teams[teamID]) + if b == nil { + return s + } + + switch cmd { + case speedUp: + b.a += da + *b = accelerate(*b) + case slowDown: + b.a -= da + *b = accelerate(*b) + case left: + b.Lane++ + case right: + b.Lane-- + } + + return updateBot(s, teamID, *b) +} diff --git a/game/game.go b/game/game.go index a380de8..dfc7417 100644 --- a/game/game.go +++ b/game/game.go @@ -16,7 +16,7 @@ func NewState() State { var bots []Bot for j := 0; j < numBots; j++ { b := Bot{ - id: i*NumTeams + j, + ID: i*NumTeams + j, Lane: i, Pos: j * (Steps / numBots), } @@ -25,7 +25,7 @@ func NewState() State { teams = append(teams, Team{ id: i, Bots: bots, - Baton: Baton{Holder: &bots[0]}, + Baton: Baton{HolderID: i * NumTeams}, Lane: i, }) } @@ -61,8 +61,17 @@ type Team struct { 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 + ID int Lane int Pos int v int @@ -70,7 +79,7 @@ type Bot struct { } type Baton struct { - Holder *Bot + HolderID int } type Obstacle struct { @@ -78,17 +87,17 @@ type Obstacle struct { Pos int } -func UpdateState(sOld State) State { - s := sOld - +func UpdateState(s State) State { for i, t := range s.Teams { - doCommand(chooseCommand(t, sOld), t.Baton.Holder) - moveBot(t.Baton.Holder, sOld) - maybePassBaton(&s.Teams[i]) + s = doCommand(chooseCommand(s, i), s, i) + if b := activeBot(t); b != nil { + s = moveBot(s, i, *b) + } + s = maybePassBaton(s, i) } for _, t := range s.Teams { - if won(*t.Baton.Holder, s) { + if b := activeBot(t); b != nil && won(*b, s) { s.GameOver = true } } @@ -96,21 +105,57 @@ func UpdateState(sOld State) State { return s } -func maybePassBaton(t *Team) { +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 { - h := t.Baton.Holder - if h.id >= b.id || h.Lane != b.Lane { + if h.ID >= b.ID || h.Lane != b.Lane { continue } if abs(b.Pos-h.Pos) <= passDistance { - log.Printf("team %v pass from %v to %v!", t.id, h.id, b.id) - t.Baton.Holder.v = 0 - t.Baton.Holder.a = 0 - t.Baton.Holder = &t.Bots[i] - t.Bots[i].a = baseAccel - return + log.Printf("team %v pass from %v to %v!", teamID, h.ID, b.ID) + 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 { + t.Bots = append(t.Bots[:i], append([]Bot{b}, t.Bots[i+1:]...)...) + break + } + } + + return updateTeam(s, t) +} + +func updateTeam(s State, t Team) State { + s.Teams = append(s.Teams[:t.id], append([]Team{t}, s.Teams[t.id+1:]...)...) + return s } func won(b Bot, s State) bool { diff --git a/game/physics.go b/game/physics.go index 2116845..2f1478d 100644 --- a/game/physics.go +++ b/game/physics.go @@ -1,6 +1,6 @@ package game -func accelerate(b *Bot) { +func accelerate(b Bot) Bot { if b.a < -maxA { b.a = -maxA } @@ -15,14 +15,18 @@ func accelerate(b *Bot) { if b.v < -maxV { b.v = -maxV } + + return b } -func moveBot(b *Bot, s State) { +func moveBot(s State, teamID int, b Bot) State { for i := 0; i < b.v; i++ { if !collide(b.Pos+1, b.Lane, s) { b.Pos++ } } + + return updateBot(s, teamID, b) } func collide(pos, lane int, s State) bool { diff --git a/gfx/gfx.go b/gfx/gfx.go index c8caf2e..998defd 100644 --- a/gfx/gfx.go +++ b/gfx/gfx.go @@ -50,7 +50,7 @@ func renderBots(s game.State, w *pixelgl.Window, d time.Duration, colors map[*ga im.Circle(botWidth, 0) im.Draw(w) - if &t.Bots[j] == t.Baton.Holder { + if t.Bots[j].ID == t.Baton.HolderID { renderBaton(pos, w) } }