tabula/bei.go

131 lines
3.1 KiB
Go

package tabula
import (
"bufio"
"bytes"
"log"
"net"
"strconv"
"code.rocket9labs.com/tslocum/bei"
)
type BEIServer struct {
}
func NewBEIServer() *BEIServer {
return &BEIServer{}
}
func (s *BEIServer) handleConnection(conn net.Conn) {
analysis := make([]*Analysis, 0, AnalysisBufferSize)
var beiCommand bool
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
if scanner.Err() != nil {
log.Printf("error: failed to read from client: %s", scanner.Err())
conn.Close()
return
}
if !beiCommand && !bytes.Equal(scanner.Bytes(), []byte("bei")) {
log.Printf("error: failed to read from client: failed to receive bei command")
conn.Close()
return
}
switch {
case bytes.Equal(scanner.Bytes(), []byte("bei")):
buf, err := bei.EncodeEvent(&bei.EventOkBEI{
Version: 1,
ID: map[string]string{
"name": "tabula",
},
})
if err != nil {
log.Fatalf("error: failed to encode event: %s", err)
}
conn.Write(buf)
conn.Write([]byte("\n"))
beiCommand = true
case bytes.HasPrefix(scanner.Bytes(), []byte("move ")):
var stateInts []int
for _, v := range bytes.Split(scanner.Bytes()[5:], []byte(",")) {
i, err := strconv.Atoi(string(v))
if err != nil {
log.Printf("error: failed to read from client: failed to decode state: %s", err)
conn.Close()
return
}
stateInts = append(stateInts, i)
}
state, err := bei.DecodeState(stateInts)
if err != nil {
log.Printf("error: failed to read from client: failed to decode state: %s", err)
conn.Close()
return
}
b := Board{}
for i, v := range state.Board {
b[i] = int8(v)
}
b[SpaceRoll1] = int8(state.Roll1)
b[SpaceRoll2] = int8(state.Roll2)
if state.Roll1 == state.Roll2 {
b[SpaceRoll3], b[SpaceRoll4] = int8(state.Roll1), int8(state.Roll2)
}
// TODO entered, acey
b[SpaceEnteredPlayer] = 1
b[SpaceEnteredOpponent] = 1
available, _ := b.Available(1)
b.Analyze(available, &analysis)
if len(analysis) == 0 {
log.Printf("error: failed to read from client: zero moves returned for analysis")
conn.Close()
return
}
move := &bei.Move{}
for _, m := range analysis[0].Moves {
if m[0] == 0 && m[1] == 0 {
break
}
move.Play = append(move.Play, &bei.Play{From: int(m[0]), To: int(m[1])})
}
buf, err := bei.EncodeEvent(&bei.EventOkMove{
Moves: []*bei.Move{move},
})
if err != nil {
log.Fatalf("error: failed to encode event: %s", err)
}
conn.Write(buf)
conn.Write([]byte("\n"))
default:
log.Printf("error: received unexpected command from client: %s", scanner.Bytes())
conn.Close()
return
}
}
if scanner.Err() != nil {
log.Printf("error: failed to read from client: %s", scanner.Err())
conn.Close()
return
}
}
func (s *BEIServer) Listen(address string) {
listener, err := net.Listen("tcp", address)
if err != nil {
log.Fatalf("failed to listen on %s: %s", address, err)
}
log.Printf("Listening for connections on %s...", address)
for {
conn, err := listener.Accept()
if err != nil {
log.Fatalf("failed to listen on %s: %s", address, err)
}
go s.handleConnection(conn)
}
}