Add bot to play against.

This commit is contained in:
Greyson Parrelli
2026-07-23 15:58:12 -04:00
parent 3825dbacec
commit db1a6ef290
23 changed files with 1852 additions and 23 deletions
+31 -3
View File
@@ -62,6 +62,9 @@ type room struct {
game *game.Game
conns map[*client]struct{}
debug bool // mirrors Server.debug, for broadcastLocked
// botArmed is set while a delayed bot move is scheduled, so only one
// timer exists per room at a time.
botArmed bool
}
// getRoom returns the room for a game ID, loading it from the store if it
@@ -78,6 +81,11 @@ func (s *Server) getRoom(gameID string) (*room, error) {
}
r := &room{game: g, conns: make(map[*client]struct{}), debug: s.debug}
s.rooms[gameID] = r
// If the game was persisted mid-bot-turn (e.g. across a server restart),
// get the bot moving again.
r.mu.Lock()
s.scheduleBotsLocked(r)
r.mu.Unlock()
return r, nil
}
@@ -116,24 +124,45 @@ type joinResponse struct {
func (s *Server) handleCreate(w http.ResponseWriter, req *http.Request) {
var body struct {
Name string `json:"name"`
// Bot, when set, fills the other seat with a computer player:
// "easy" | "medium" | "hard".
Bot string `json:"bot"`
}
if err := json.NewDecoder(req.Body).Decode(&body); err != nil {
httpError(w, http.StatusBadRequest, "invalid JSON body")
return
}
var bot struct {
level float64
name string
}
if body.Bot != "" {
var ok bool
bot, ok = botDifficulty[body.Bot]
if !ok {
httpError(w, http.StatusBadRequest, "unknown bot difficulty")
return
}
}
g := game.New()
p, err := g.AddPlayer(strings.TrimSpace(body.Name))
if err != nil {
httpError(w, http.StatusBadRequest, err.Error())
return
}
if body.Bot != "" {
if _, err := g.AddBot(bot.name, bot.level); err != nil {
httpError(w, http.StatusBadRequest, err.Error())
return
}
}
r := &room{game: g, conns: make(map[*client]struct{}), debug: s.debug}
s.mu.Lock()
s.rooms[g.ID] = r
s.mu.Unlock()
r.mu.Lock()
s.persist(r)
s.commitLocked(r)
r.mu.Unlock()
writeJSON(w, joinResponse{GameID: g.ID, Code: g.Code, PlayerID: p.ID, Token: p.Token})
}
@@ -163,9 +192,8 @@ func (s *Server) handleJoin(w http.ResponseWriter, req *http.Request) {
httpError(w, http.StatusConflict, err.Error())
return
}
s.persist(r)
resp := joinResponse{GameID: r.game.ID, Code: r.game.Code, PlayerID: p.ID, Token: p.Token}
r.broadcastLocked()
s.commitLocked(r)
r.mu.Unlock()
writeJSON(w, resp)
}