2022-02-12 23:35:30 +02:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
"github.com/maaslalani/gambit/game"
|
2022-02-15 05:08:25 +02:00
|
|
|
"github.com/maaslalani/gambit/style"
|
2022-02-12 23:35:30 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// NoteMsg is a message that is sent to the client when a message is added to
|
|
|
|
// the game.
|
|
|
|
type NoteMsg string
|
|
|
|
|
|
|
|
// SharedGame is a game that is shared between players. It wraps gambit bubble
|
|
|
|
// tea model and synchronizes messages among players and server.
|
|
|
|
type SharedGame struct {
|
2022-02-15 04:35:07 +02:00
|
|
|
player *Player
|
|
|
|
game *game.Game
|
|
|
|
note string
|
|
|
|
turn bool
|
|
|
|
observer bool
|
|
|
|
whiteToMove *bool
|
|
|
|
sync chan tea.Msg
|
2022-02-12 23:35:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewSharedGame creates a new shared game for a player.
|
|
|
|
func NewSharedGame(p *Player, sync chan tea.Msg, roomTurn *bool, turn, observer bool, pos string) *SharedGame {
|
|
|
|
g := game.NewGameWithPosition(pos)
|
|
|
|
g.SetFlipped(!turn)
|
|
|
|
r := &SharedGame{
|
2022-02-15 04:35:07 +02:00
|
|
|
player: p,
|
|
|
|
game: g,
|
|
|
|
turn: turn,
|
|
|
|
observer: observer,
|
|
|
|
whiteToMove: roomTurn,
|
|
|
|
sync: sync,
|
2022-02-12 23:35:30 +02:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init implements bubble tea model.
|
|
|
|
func (r *SharedGame) Init() tea.Cmd {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendMsg sends a message to the room.
|
|
|
|
func (r *SharedGame) SendMsg(msg tea.Msg) {
|
|
|
|
go func() {
|
|
|
|
r.sync <- msg
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update implements bubble tea model.
|
|
|
|
func (r *SharedGame) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
var cmds []tea.Cmd
|
|
|
|
switch msg := msg.(type) {
|
|
|
|
case game.NotifyMsg:
|
|
|
|
if !r.observer && r.turn != msg.Turn {
|
|
|
|
r.SendMsg(game.MoveMsg{From: msg.From, To: msg.To})
|
|
|
|
if msg.Checkmate {
|
|
|
|
r.SendMsg(NoteMsg(fmt.Sprintf("%s wins!", r.player)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case game.MoveMsg:
|
2022-02-15 03:21:12 +02:00
|
|
|
g, cmd := r.game.Update(msg)
|
|
|
|
r.game = g.(*game.Game)
|
2022-02-12 23:35:30 +02:00
|
|
|
cmds = append(cmds, cmd)
|
|
|
|
case NoteMsg:
|
|
|
|
r.note = string(msg)
|
|
|
|
return r, nil
|
|
|
|
case tea.MouseMsg:
|
2022-02-15 04:35:07 +02:00
|
|
|
if !r.observer && r.turn == *r.whiteToMove {
|
2022-02-12 23:35:30 +02:00
|
|
|
if msg.Type != tea.MouseLeft {
|
|
|
|
return r, nil
|
|
|
|
}
|
2022-02-15 03:21:12 +02:00
|
|
|
g, cmd := r.game.Update(msg)
|
2022-02-12 23:35:30 +02:00
|
|
|
cmds = append(cmds, cmd)
|
2022-02-15 03:21:12 +02:00
|
|
|
r.game = g.(*game.Game)
|
2022-02-12 23:35:30 +02:00
|
|
|
}
|
|
|
|
case tea.KeyMsg:
|
|
|
|
switch msg.String() {
|
|
|
|
case "ctrl+c", "q":
|
2022-02-15 03:21:12 +02:00
|
|
|
g, cmd := r.game.Update(msg)
|
|
|
|
r.game = g.(*game.Game)
|
2022-02-12 23:35:30 +02:00
|
|
|
cmds = append(cmds, cmd)
|
|
|
|
cmds = append(cmds, tea.Quit)
|
|
|
|
case "ctrl+f":
|
2022-02-15 03:21:12 +02:00
|
|
|
g, cmd := r.game.Update(msg)
|
2022-02-12 23:35:30 +02:00
|
|
|
cmds = append(cmds, cmd)
|
2022-02-15 03:21:12 +02:00
|
|
|
r.game = g.(*game.Game)
|
2022-02-12 23:35:30 +02:00
|
|
|
default:
|
2022-02-15 04:35:07 +02:00
|
|
|
if !r.observer && r.turn == *r.whiteToMove {
|
2022-02-15 03:21:12 +02:00
|
|
|
g, cmd := r.game.Update(msg)
|
2022-02-12 23:35:30 +02:00
|
|
|
cmds = append(cmds, cmd)
|
2022-02-15 03:21:12 +02:00
|
|
|
r.game = g.(*game.Game)
|
2022-02-12 23:35:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
2022-02-15 04:35:07 +02:00
|
|
|
if !r.observer && r.turn == *r.whiteToMove {
|
2022-02-15 03:21:12 +02:00
|
|
|
g, cmd := r.game.Update(msg)
|
2022-02-12 23:35:30 +02:00
|
|
|
cmds = append(cmds, cmd)
|
2022-02-15 03:21:12 +02:00
|
|
|
r.game = g.(*game.Game)
|
2022-02-12 23:35:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return r, tea.Batch(cmds...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// View implements bubble tea model.
|
|
|
|
func (r *SharedGame) View() string {
|
|
|
|
s := strings.Builder{}
|
2022-02-15 05:08:25 +02:00
|
|
|
|
|
|
|
turn := "Black's move"
|
|
|
|
if *r.whiteToMove {
|
|
|
|
turn = "White's move"
|
2022-02-12 23:35:30 +02:00
|
|
|
}
|
2022-02-15 05:08:25 +02:00
|
|
|
|
|
|
|
s.WriteString(r.game.View())
|
|
|
|
|
|
|
|
s.WriteRune('\n')
|
|
|
|
s.WriteString(fmt.Sprintf(" %s %s", style.Title("Gambit"), turn))
|
|
|
|
s.WriteRune('\n')
|
|
|
|
s.WriteString(style.Faint(fmt.Sprintf(" Room %s as %s playing %s", r.player.room.id, r.player.session.User(), r.player.ptype)))
|
|
|
|
s.WriteRune('\n')
|
|
|
|
|
2022-02-12 23:35:30 +02:00
|
|
|
return s.String()
|
|
|
|
}
|