diff --git a/bei.go b/bei.go index a17a882..c0d6b5e 100644 --- a/bei.go +++ b/bei.go @@ -3,6 +3,7 @@ package tabula import ( "bufio" "bytes" + "fmt" "log" "net" "strconv" @@ -47,38 +48,15 @@ func (s *BEIServer) handleConnection(conn net.Conn) { 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) + b, err := parseState(scanner.Bytes()[5:]) if err != nil { - log.Printf("error: failed to read from client: failed to decode state: %s", err) + log.Println(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() @@ -100,6 +78,39 @@ func (s *BEIServer) handleConnection(conn net.Conn) { } conn.Write(buf) conn.Write([]byte("\n")) + case bytes.HasPrefix(scanner.Bytes(), []byte("choose ")): + b, err := parseState(scanner.Bytes()[7:]) + if err != nil { + log.Println(err) + conn.Close() + return + } + + if b[SpaceAcey] != 1 { + log.Println("error: failed to choose roll: state does not represent acey-deucey game") + conn.Close() + return + } + + roll := b.ChooseDoubles(&analysis) + if roll < 1 || roll > 6 { + log.Printf("error: failed to read from client: invalid roll: %d", roll) + conn.Close() + return + } + + buf, err := bei.EncodeEvent(&bei.EventOkChoose{ + Rolls: []*bei.ChooseRoll{ + { + Roll: roll, + }, + }, + }) + 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() @@ -129,3 +140,39 @@ func (s *BEIServer) Listen(address string) { go s.handleConnection(conn) } } + +func parseState(buf []byte) (Board, error) { + var stateInts []int + for _, v := range bytes.Split(buf, []byte(",")) { + i, err := strconv.Atoi(string(v)) + if err != nil { + return Board{}, fmt.Errorf("error: failed to read from client: failed to decode state: %s", err) + } + stateInts = append(stateInts, i) + } + state, err := bei.DecodeState(stateInts) + if err != nil { + return Board{}, fmt.Errorf("error: failed to read from client: failed to decode state: %s", err) + } + 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) + } + b[SpaceEnteredPlayer] = 1 + b[SpaceEnteredOpponent] = 1 + if state.Acey { + b[SpaceAcey] = 1 + if !state.Entered1 { + b[SpaceEnteredPlayer] = 0 + } + if !state.Entered2 { + b[SpaceEnteredOpponent] = 0 + } + } + return b, nil +} diff --git a/board.go b/board.go index 7b2374a..99e01ef 100644 --- a/board.go +++ b/board.go @@ -543,11 +543,94 @@ func (b Board) Analyze(available [][4][2]int8, result *[]*Analysis) { } } + if b.StartingPosition(1) && b[SpaceRoll1] != b[SpaceRoll2] { + r1, r2 := b[SpaceRoll1], b[SpaceRoll2] + if r2 > r1 { + r1, r2 = r2, r1 + } + var opening [4][2]int8 + if r1 == r2 { + switch r1 { + case 1: + opening = [4][2]int8{{24, 23}, {24, 23}, {6, 5}, {6, 5}} + case 2: + opening = [4][2]int8{{13, 11}, {13, 11}, {11, 9}, {11, 9}} + case 3: + opening = [4][2]int8{{13, 10}, {13, 10}, {10, 7}, {10, 7}} + case 4: + opening = [4][2]int8{{13, 9}, {13, 9}, {6, 2}, {6, 2}} + case 5: + opening = [4][2]int8{{13, 8}, {13, 8}, {8, 3}, {8, 3}} + case 6: + opening = [4][2]int8{{24, 18}, {24, 18}, {13, 7}, {13, 7}} + } + } else { + switch r1 { + case 2: + opening = [4][2]int8{{13, 11}, {6, 5}} + case 3: + switch r2 { + case 1: + opening = [4][2]int8{{8, 5}, {6, 5}} + case 2: + opening = [4][2]int8{{13, 11}, {13, 10}} + } + case 4: + switch r2 { + case 1: + opening = [4][2]int8{{24, 23}, {13, 9}} + case 2: + opening = [4][2]int8{{8, 4}, {6, 4}} + case 3: + opening = [4][2]int8{{13, 10}, {13, 9}} + } + case 5: + switch r2 { + case 1: + opening = [4][2]int8{{24, 23}, {13, 8}} + case 2: + opening = [4][2]int8{{24, 22}, {13, 8}} + case 3: + opening = [4][2]int8{{8, 3}, {6, 3}} + case 4: + opening = [4][2]int8{{24, 20}, {13, 8}} + } + case 6: + switch r2 { + case 1: + opening = [4][2]int8{{13, 7}, {8, 7}} + case 2: + opening = [4][2]int8{{24, 18}, {13, 11}} + case 3: + opening = [4][2]int8{{24, 18}, {13, 10}} + case 4: + opening = [4][2]int8{{8, 2}, {6, 2}} + case 5: + opening = [4][2]int8{{24, 18}, {18, 13}} + } + } + } + const priorityScore = -1000000 + for _, a := range *result { + if movesEqual(a.Moves, opening) { + a.Score = priorityScore + break + } + } + } + sort.Slice(*result, func(i, j int) bool { return (*result)[i].Score < (*result)[j].Score }) } +func (b Board) StartingPosition(player int) bool { + if player == 1 { + return b[6] == 5 && b[8] == 3 && b[13] == 5 && b[24] == 2 + } + return b[1] == -2 && b[12] == -5 && b[17] == -3 && b[19] == -5 +} + func (b Board) ChooseDoubles(result *[]*Analysis) int { if b[SpaceAcey] == 0 { return 0 diff --git a/cmd/tabula/main.go b/cmd/tabula/main.go index ede132a..c4131ea 100644 --- a/cmd/tabula/main.go +++ b/cmd/tabula/main.go @@ -4,7 +4,6 @@ import ( "flag" "fmt" "log" - "time" "code.rocket9labs.com/tslocum/tabula" ) @@ -32,54 +31,21 @@ func main() { //b := tabula.Board{0, 0, 0, 0, 0, -1, 8, 0, 4, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, -1, 1, -2, -2, -3, -2, 0, 2, 0, 0, 0, 0, 4, 1, 1, 0} - b := tabula.Board{0, 0, -2, -2, -2, 4, 0, -1, 0, 0, -2, 4, 0, -2, -1, 0, -2, 4, 0, 2, 0, 0, 0, 0, -1, 0, 1, 0, 4, 1, 0, 0, 1, 1, 1} + //b := tabula.Board{0, 0, -2, -2, -2, 4, 0, -1, 0, 0, -2, 4, 0, -2, -1, 0, -2, 4, 0, 2, 0, 0, 0, 0, -1, 0, 1, 0, 4, 1, 0, 0, 1, 1, 1} - t := time.Now() - available, _ := b.Available(1) - - //log.Println(b.Move(15, 19, 2)) - //log.Println(b.Move(15, 19, 2).UseRoll(15, 19, 2)) - - log.Println(available) - //os.Exit(0) - t2 := time.Now() analysis := make([]*tabula.Analysis, 0, tabula.AnalysisBufferSize) - b.Analyze(available, &analysis) - t3 := time.Now() - - log.Println("AVAILABLE TOOK ", t2.Sub(t)) - log.Println("ANALYSIS TOOK ", t3.Sub(t2)) - - log.Println("AVAILABLE", available) - for i, a := range analysis { - log.Printf("%+v %+v", i, a) + for r1 := 1; r1 <= 6; r1++ { + for r2 := 1; r2 <= 6; r2++ { + b := tabula.NewBoard(false) + b[tabula.SpaceRoll1] = int8(r1) + b[tabula.SpaceRoll2] = int8(r2) + if r1 == r2 { + b[tabula.SpaceRoll3] = int8(r1) + b[tabula.SpaceRoll4] = int8(r2) + } + available, _ := b.Available(1) + b.Analyze(available, &analysis) + log.Println("ROLL", r1, r2, analysis[0].Moves) + } } - - //t4 := time.Now() - //_ = b.ChooseDoubles(&analysis) - //log.Println("CHOOSE DOUBLES TOOK ", time.Since(t4)) - - /* - - b := tabula.NewBoard(true) - b[tabula.SpaceRoll1] = 6 - b[tabula.SpaceRoll2] = 6 - b[tabula.SpaceRoll3] = 6 - b[tabula.SpaceRoll4] = 6 - b.Print() - - t := time.Now() - available, _ := b.Available(1) - t2 := time.Now() - analysis := make([]*tabula.Analysis, 0, tabula.AnalysisBufferSize) - b.Analyze(available, &analysis) - t3 := time.Now() - - log.Println("AVAILABLE TOOK ", t2.Sub(t)) - log.Println("ANALYSIS TOOK ", t3.Sub(t2)) - - log.Println("AVAILABLE", available) - for i, a := range analysis { - log.Printf("%+v %+v", i, a) - }*/ } diff --git a/go.mod b/go.mod index 7dd5e26..1a8a5e2 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module code.rocket9labs.com/tslocum/tabula go 1.17 -require code.rocket9labs.com/tslocum/bei v0.0.0-20231220232111-b1d4144d27bb +require code.rocket9labs.com/tslocum/bei v0.0.0-20231222205835-c070d7c7d5f8 diff --git a/go.sum b/go.sum index 5e20046..c7ec23a 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,2 @@ -code.rocket9labs.com/tslocum/bei v0.0.0-20231220232111-b1d4144d27bb h1:gU9+YXaDNq/7OyHJ4Mqu5qAyJFAxmCY++Ptk5T/B7w4= -code.rocket9labs.com/tslocum/bei v0.0.0-20231220232111-b1d4144d27bb/go.mod h1:tS60/VNAJphKvDBkSLQhKALa15msIAuWWfEKNc4oFZc= +code.rocket9labs.com/tslocum/bei v0.0.0-20231222205835-c070d7c7d5f8 h1:QefJxcMg2aneCZuoHPpnDOTsing1mehImilbyyT3SwU= +code.rocket9labs.com/tslocum/bei v0.0.0-20231222205835-c070d7c7d5f8/go.mod h1:tS60/VNAJphKvDBkSLQhKALa15msIAuWWfEKNc4oFZc=