Support analyzing tabula games
This commit is contained in:
parent
3a825a2f64
commit
dcc16fb334
7 changed files with 417 additions and 71 deletions
|
@ -72,7 +72,7 @@ type Analysis struct {
|
|||
OppHits float64
|
||||
OppScore float64
|
||||
|
||||
player int
|
||||
player int8
|
||||
hitScore int
|
||||
chance int
|
||||
wg *sync.WaitGroup
|
||||
|
@ -90,7 +90,7 @@ func (a *Analysis) _analyze() {
|
|||
if checkers == 1 {
|
||||
hs += PseudoPips(a.player, move[1])
|
||||
}
|
||||
a.Board = a.Board.Move(move[0], move[1], a.player).UseRoll(move[0], move[1], a.player)
|
||||
a.Board = a.Board.UseRoll(move[0], move[1], a.player).Move(move[0], move[1], a.player)
|
||||
}
|
||||
if !a.Past {
|
||||
a.Past = a.Board.Past()
|
||||
|
|
41
bei.go
41
bei.go
|
@ -57,22 +57,23 @@ func (s *BEIServer) handleConnection(conn net.Conn) {
|
|||
|
||||
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
|
||||
var move *bei.Move
|
||||
if len(analysis) > 0 {
|
||||
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])})
|
||||
}
|
||||
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},
|
||||
})
|
||||
result := &bei.EventOkMove{
|
||||
Moves: []*bei.Move{},
|
||||
}
|
||||
if move != nil {
|
||||
result.Moves = append(result.Moves, move)
|
||||
}
|
||||
buf, err := bei.EncodeEvent(result)
|
||||
if err != nil {
|
||||
log.Fatalf("error: failed to encode event: %s", err)
|
||||
}
|
||||
|
@ -160,16 +161,18 @@ func parseState(buf []byte) (Board, error) {
|
|||
}
|
||||
b[SpaceRoll1] = int8(state.Roll1)
|
||||
b[SpaceRoll2] = int8(state.Roll2)
|
||||
if state.Roll1 == state.Roll2 {
|
||||
if int8(state.Variant) != VariantTabula && state.Roll1 == state.Roll2 {
|
||||
b[SpaceRoll3], b[SpaceRoll4] = int8(state.Roll1), int8(state.Roll2)
|
||||
} else {
|
||||
b[SpaceRoll3] = int8(state.Roll3)
|
||||
}
|
||||
if int8(state.Variant) != VariantBackgammon {
|
||||
b[SpaceVariant] = int8(state.Variant)
|
||||
if !state.Entered1 {
|
||||
b[SpaceEnteredPlayer] = 0
|
||||
if state.Entered1 {
|
||||
b[SpaceEnteredPlayer] = 1
|
||||
}
|
||||
if !state.Entered2 {
|
||||
b[SpaceEnteredOpponent] = 0
|
||||
if state.Entered2 {
|
||||
b[SpaceEnteredOpponent] = 1
|
||||
}
|
||||
} else {
|
||||
b[SpaceEnteredPlayer] = 1
|
||||
|
|
187
board.go
187
board.go
|
@ -55,7 +55,7 @@ func (b Board) SetValue(space int, value int8) Board {
|
|||
}
|
||||
|
||||
// Move moves a checker on the board.
|
||||
func (b Board) Move(from int8, to int8, player int) Board {
|
||||
func (b Board) Move(from int8, to int8, player int8) Board {
|
||||
if b[from] == 0 || (player == 1 && b[from] < 0) || (player == 2 && b[from] > 0) {
|
||||
log.Panic("illegal move: no from checker", from, to, player)
|
||||
} else if b[to] != 0 {
|
||||
|
@ -76,11 +76,18 @@ func (b Board) Move(from int8, to int8, player int) Board {
|
|||
delta = -1
|
||||
}
|
||||
b[from], b[to] = b[from]-delta, b[to]+delta
|
||||
if (player == 1 && from == SpaceHomePlayer && b[SpaceEnteredPlayer] == 0 && b[SpaceHomePlayer] == 0) || (player == 2 && from == SpaceHomeOpponent && b[SpaceEnteredOpponent] == 0 && b[SpaceHomeOpponent] == 0) {
|
||||
if player == 1 {
|
||||
b[SpaceEnteredPlayer] = 1
|
||||
} else {
|
||||
b[SpaceEnteredOpponent] = 1
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// checkers returns the number of checkers that belong to the spcified player at the provided space.
|
||||
func checkers(player int, v int8) int8 {
|
||||
func checkers(player int8, v int8) int8 {
|
||||
if player == 1 && v > 0 {
|
||||
return v
|
||||
} else if player == 2 && v < 0 {
|
||||
|
@ -89,9 +96,11 @@ func checkers(player int, v int8) int8 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (b Board) MayBearOff(player int) bool {
|
||||
func (b Board) MayBearOff(player int8) bool {
|
||||
if b[SpaceVariant] != VariantBackgammon && ((player == 1 && b[SpaceEnteredPlayer] == 0) || (player == 2 && b[SpaceEnteredOpponent] == 0)) {
|
||||
return false
|
||||
} else if b[SpaceVariant] == VariantTabula && !b.SecondHalf(player) {
|
||||
return false
|
||||
}
|
||||
barSpace := SpaceBarPlayer
|
||||
if player == 2 {
|
||||
|
@ -100,46 +109,78 @@ func (b Board) MayBearOff(player int) bool {
|
|||
if checkers(player, b[barSpace]) != 0 {
|
||||
return false
|
||||
}
|
||||
if player == 1 {
|
||||
for space := 24; space > 6; space-- {
|
||||
if checkers(player, b[space]) != 0 {
|
||||
return false
|
||||
if b[SpaceVariant] != VariantTabula {
|
||||
if player == 1 {
|
||||
for space := 24; space > 6; space-- {
|
||||
if checkers(player, b[space]) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for space := 1; space < 19; space++ {
|
||||
if checkers(player, b[space]) != 0 {
|
||||
return false
|
||||
} else {
|
||||
for space := 1; space < 19; space++ {
|
||||
if checkers(player, b[space]) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (b Board) spaceDiff(player int, from int8, to int8) int8 {
|
||||
func (b Board) spaceDiff(player int8, from int8, to int8) int8 {
|
||||
switch {
|
||||
case from < 0 || from > 27 || to < 0 || to > 27:
|
||||
return 0
|
||||
case to == SpaceBarPlayer || to == SpaceBarOpponent:
|
||||
return 0
|
||||
case (from == SpaceBarPlayer || from == SpaceBarOpponent) && (to == SpaceBarPlayer || to == SpaceBarOpponent || to == SpaceHomePlayer || to == SpaceHomeOpponent):
|
||||
case (from == SpaceHomePlayer || from == SpaceHomeOpponent || from == SpaceBarPlayer || from == SpaceBarOpponent) && (to == SpaceBarPlayer || to == SpaceBarOpponent || to == SpaceHomePlayer || to == SpaceHomeOpponent):
|
||||
return 0
|
||||
case to == SpaceHomePlayer:
|
||||
if player == 2 {
|
||||
return 0
|
||||
}
|
||||
if b[SpaceVariant] == VariantTabula {
|
||||
if (player == 1 && b[SpaceEnteredPlayer] == 0) || (player == 2 && b[SpaceEnteredOpponent] == 0) || !b.SecondHalf(player) {
|
||||
return 0
|
||||
}
|
||||
return 25 - from
|
||||
}
|
||||
return from
|
||||
case to == SpaceHomeOpponent:
|
||||
if player == 1 {
|
||||
return 0
|
||||
}
|
||||
return 25 - from
|
||||
case from == SpaceHomePlayer || from == SpaceHomeOpponent:
|
||||
if b[SpaceVariant] != VariantBackgammon {
|
||||
if (player == 1 && from == SpaceHomeOpponent) || (player == 2 && from == SpaceHomePlayer) {
|
||||
return 0
|
||||
}
|
||||
switch b[SpaceVariant] {
|
||||
case VariantAceyDeucey:
|
||||
if player == 1 && from == SpaceHomePlayer && b[SpaceEnteredPlayer] == 0 {
|
||||
return 25 - to
|
||||
} else if player == 2 && from == SpaceHomeOpponent && b[SpaceEnteredOpponent] == 0 {
|
||||
return to
|
||||
}
|
||||
case VariantTabula:
|
||||
if (player == 1 && from != SpaceHomePlayer && b[SpaceEnteredPlayer] == 0) || (player == 2 && from != SpaceHomeOpponent && b[SpaceEnteredOpponent] == 0) {
|
||||
return 0
|
||||
}
|
||||
return to
|
||||
}
|
||||
return 0
|
||||
case from == SpaceBarPlayer:
|
||||
if player == 2 {
|
||||
return 0
|
||||
}
|
||||
if b[SpaceVariant] == VariantTabula {
|
||||
return to
|
||||
}
|
||||
return 25 - to
|
||||
case from == SpaceBarOpponent:
|
||||
if player == 1 {
|
||||
return 0
|
||||
}
|
||||
return to
|
||||
default:
|
||||
diff := to - from
|
||||
|
@ -151,7 +192,7 @@ func (b Board) spaceDiff(player int, from int8, to int8) int8 {
|
|||
}
|
||||
|
||||
// HaveRoll returns whether the player has a sufficient die roll for the specified move.
|
||||
func (b Board) HaveRoll(from int8, to int8, player int) bool {
|
||||
func (b Board) HaveRoll(from int8, to int8, player int8) bool {
|
||||
barSpace := SpaceBarPlayer
|
||||
if player == 2 {
|
||||
barSpace = SpaceBarOpponent
|
||||
|
@ -160,6 +201,10 @@ func (b Board) HaveRoll(from int8, to int8, player int) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if b[SpaceVariant] == VariantTabula && to > 12 && to < 25 && ((player == 1 && b[SpaceEnteredPlayer] == 0) || (player == 2 && b[SpaceEnteredOpponent] == 0)) {
|
||||
return false
|
||||
}
|
||||
|
||||
delta := b.spaceDiff(player, from, to)
|
||||
if delta == 0 {
|
||||
return false
|
||||
|
@ -190,8 +235,8 @@ func (b Board) HaveRoll(from int8, to int8, player int) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// UseRoll uses a die roll.
|
||||
func (b Board) UseRoll(from int8, to int8, player int) Board {
|
||||
// UseRoll uses a die roll. UseRoll must be called before making a move.
|
||||
func (b Board) UseRoll(from int8, to int8, player int8) Board {
|
||||
delta := b.spaceDiff(player, from, to)
|
||||
if delta == 0 {
|
||||
b.Print()
|
||||
|
@ -250,7 +295,7 @@ func (b Board) UseRoll(from int8, to int8, player int) Board {
|
|||
return b
|
||||
}
|
||||
|
||||
func (b Board) _available(player int) [][2]int8 {
|
||||
func (b Board) _available(player int8) [][2]int8 {
|
||||
homeSpace := SpaceHomePlayer
|
||||
barSpace := SpaceBarPlayer
|
||||
opponentBarSpace := SpaceBarOpponent
|
||||
|
@ -272,12 +317,11 @@ func (b Board) _available(player int) [][2]int8 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for from := int8(0); from < 28; from++ {
|
||||
if from == SpaceHomePlayer || from == SpaceHomeOpponent || from == opponentBarSpace || checkers(player, b[from]) == 0 || (onBar && from != barSpace) {
|
||||
continue
|
||||
}
|
||||
if player == 1 {
|
||||
if player == 1 && b[SpaceVariant] != VariantTabula {
|
||||
for to := int8(0); to < from; to++ {
|
||||
if to == SpaceBarPlayer || to == SpaceBarOpponent || to == SpaceHomeOpponent || (to == SpaceHomePlayer && !mayBearOff) {
|
||||
continue
|
||||
|
@ -290,11 +334,17 @@ func (b Board) _available(player int) [][2]int8 {
|
|||
}
|
||||
} else { // TODO clean up
|
||||
start := from + 1
|
||||
if from == SpaceBarOpponent {
|
||||
start = 0
|
||||
if from == SpaceBarPlayer || from == SpaceBarOpponent {
|
||||
start = 1
|
||||
}
|
||||
for to := start; to <= 25; to++ {
|
||||
if to == SpaceBarPlayer || to == SpaceBarOpponent || to == SpaceHomeOpponent || (to == SpaceHomeOpponent && !mayBearOff) {
|
||||
for i := start; i <= 25; i++ {
|
||||
to := i
|
||||
if player == 1 && to == SpaceHomeOpponent {
|
||||
to = SpaceHomePlayer
|
||||
} else if player == 2 && to == SpaceHomePlayer {
|
||||
to = SpaceHomeOpponent
|
||||
}
|
||||
if to == SpaceBarPlayer || to == SpaceBarOpponent || (((player == 1 && to == SpaceHomePlayer) || (player == 2 && to == SpaceHomeOpponent)) && !mayBearOff) {
|
||||
continue
|
||||
}
|
||||
v := b[to]
|
||||
|
@ -310,7 +360,7 @@ func (b Board) _available(player int) [][2]int8 {
|
|||
}
|
||||
|
||||
// Available returns legal moves available.
|
||||
func (b Board) Available(player int) ([][4][2]int8, []Board) {
|
||||
func (b Board) Available(player int8) ([][4][2]int8, []Board) {
|
||||
var allMoves [][4][2]int8
|
||||
|
||||
resultMutex := &sync.Mutex{}
|
||||
|
@ -330,7 +380,7 @@ func (b Board) Available(player int) ([][4][2]int8, []Board) {
|
|||
a := b._available(player)
|
||||
maxLen := 1
|
||||
for _, move := range a {
|
||||
newBoard := b.Move(move[0], move[1], player).UseRoll(move[0], move[1], player)
|
||||
newBoard := b.UseRoll(move[0], move[1], player).Move(move[0], move[1], player)
|
||||
newAvailable := newBoard._available(player)
|
||||
if len(newAvailable) == 0 {
|
||||
moves := [4][2]int8{move}
|
||||
|
@ -341,31 +391,35 @@ func (b Board) Available(player int) ([][4][2]int8, []Board) {
|
|||
continue
|
||||
}
|
||||
for _, move2 := range newAvailable {
|
||||
newBoard2 := newBoard.Move(move2[0], move2[1], player).UseRoll(move2[0], move2[1], player)
|
||||
newBoard2 := newBoard.UseRoll(move2[0], move2[1], player).Move(move2[0], move2[1], player)
|
||||
newAvailable2 := newBoard2._available(player)
|
||||
if len(newAvailable2) == 0 {
|
||||
moves := [4][2]int8{move, move2}
|
||||
if !movesFound(moves) {
|
||||
allMoves = append(allMoves, moves)
|
||||
boards = append(boards, newBoard2)
|
||||
maxLen = 2
|
||||
if maxLen <= 2 {
|
||||
maxLen = 2
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, move3 := range newAvailable2 {
|
||||
newBoard3 := newBoard2.Move(move3[0], move3[1], player).UseRoll(move3[0], move3[1], player)
|
||||
newBoard3 := newBoard2.UseRoll(move3[0], move3[1], player).Move(move3[0], move3[1], player)
|
||||
newAvailable3 := newBoard3._available(player)
|
||||
if len(newAvailable3) == 0 {
|
||||
moves := [4][2]int8{move, move2, move3}
|
||||
if !movesFound(moves) {
|
||||
allMoves = append(allMoves, moves)
|
||||
boards = append(boards, newBoard3)
|
||||
maxLen = 3
|
||||
if maxLen <= 2 {
|
||||
maxLen = 3
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, move4 := range newAvailable3 {
|
||||
newBoard4 := newBoard3.Move(move4[0], move4[1], player).UseRoll(move4[0], move4[1], player)
|
||||
newBoard4 := newBoard3.UseRoll(move4[0], move4[1], player).Move(move4[0], move4[1], player)
|
||||
moves := [4][2]int8{move, move2, move3, move4}
|
||||
if !movesFound(moves) {
|
||||
allMoves = append(allMoves, moves)
|
||||
|
@ -379,6 +433,18 @@ func (b Board) Available(player int) ([][4][2]int8, []Board) {
|
|||
var newMoves [][4][2]int8
|
||||
for i := 0; i < len(allMoves); i++ {
|
||||
l := 0
|
||||
if (allMoves[i][3][0] != 0 || allMoves[i][3][1] != 0) && allMoves[i][2][0] == 0 && allMoves[i][2][1] == 0 {
|
||||
allMoves[i][2][0], allMoves[i][2][1] = allMoves[i][3][0], allMoves[i][3][1]
|
||||
allMoves[i][2][0], allMoves[i][2][1] = 0, 0
|
||||
}
|
||||
if (allMoves[i][2][0] != 0 || allMoves[i][2][1] != 0) && allMoves[i][1][0] == 0 && allMoves[i][1][1] == 0 {
|
||||
allMoves[i][1][0], allMoves[i][1][1] = allMoves[i][2][0], allMoves[i][2][1]
|
||||
allMoves[i][2][0], allMoves[i][2][1] = 0, 0
|
||||
}
|
||||
if (allMoves[i][1][0] != 0 || allMoves[i][1][1] != 0) && allMoves[i][0][0] == 0 && allMoves[i][0][1] == 0 {
|
||||
allMoves[i][0][0], allMoves[i][0][1] = allMoves[i][1][0], allMoves[i][1][1]
|
||||
allMoves[i][1][0], allMoves[i][1][1] = 0, 0
|
||||
}
|
||||
for j := 0; j < 4; j++ {
|
||||
if allMoves[i][j][0] == 0 && allMoves[i][j][1] == 0 {
|
||||
break
|
||||
|
@ -393,7 +459,9 @@ func (b Board) Available(player int) ([][4][2]int8, []Board) {
|
|||
}
|
||||
|
||||
func (b Board) Past() bool {
|
||||
if b[SpaceBarPlayer] != 0 || b[SpaceBarOpponent] != 0 {
|
||||
if b[SpaceBarPlayer] != 0 || b[SpaceBarOpponent] != 0 || b[SpaceVariant] == VariantTabula {
|
||||
return false
|
||||
} else if b[SpaceVariant] == VariantAceyDeucey && ((b[SpaceEnteredPlayer] == 0 && b[SpaceHomePlayer] != 0) || (b[SpaceEnteredOpponent] == 0 && b[SpaceHomeOpponent] != 0)) {
|
||||
return false
|
||||
}
|
||||
var playerFirst, opponentLast int
|
||||
|
@ -414,7 +482,42 @@ func (b Board) Past() bool {
|
|||
return playerFirst < opponentLast
|
||||
}
|
||||
|
||||
func (b Board) Pips(player int) int {
|
||||
func (b Board) SecondHalf(player int8) bool {
|
||||
if b[SpaceVariant] != VariantTabula {
|
||||
return false
|
||||
}
|
||||
|
||||
switch player {
|
||||
case 1:
|
||||
if b[SpaceBarPlayer] != 0 {
|
||||
return false
|
||||
} else if b[SpaceEnteredPlayer] == 0 && b[SpaceHomePlayer] != 0 {
|
||||
return false
|
||||
}
|
||||
case 2:
|
||||
if b[SpaceBarOpponent] != 0 {
|
||||
return false
|
||||
} else if b[SpaceEnteredOpponent] == 0 && b[SpaceHomeOpponent] != 0 {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
log.Panicf("unknown player: %d", player)
|
||||
}
|
||||
|
||||
for space := 1; space < 13; space++ {
|
||||
if space == 13 {
|
||||
log.Fatal("CHECK SPACE", space)
|
||||
}
|
||||
v := b[space]
|
||||
if (player == 1 && v > 0) || (player == 2 && v < 0) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (b Board) Pips(player int8) int {
|
||||
var pips int
|
||||
if b[SpaceVariant] != VariantBackgammon {
|
||||
if player == 1 && b[SpaceEnteredPlayer] == 0 {
|
||||
|
@ -434,7 +537,7 @@ func (b Board) Pips(player int) int {
|
|||
return pips
|
||||
}
|
||||
|
||||
func (b Board) Blots(player int) int {
|
||||
func (b Board) Blots(player int8) int {
|
||||
o := opponent(player)
|
||||
var pips int
|
||||
for space := int8(1); space < 25; space++ {
|
||||
|
@ -445,7 +548,7 @@ func (b Board) Blots(player int) int {
|
|||
return pips
|
||||
}
|
||||
|
||||
func (b Board) evaluate(player int, hitScore int, a *Analysis) {
|
||||
func (b Board) evaluate(player int8, hitScore int, a *Analysis) {
|
||||
pips := b.Pips(player)
|
||||
score := float64(pips)
|
||||
var blots int
|
||||
|
@ -460,7 +563,7 @@ func (b Board) evaluate(player int, hitScore int, a *Analysis) {
|
|||
a.hitScore = hitScore
|
||||
}
|
||||
|
||||
func (b Board) Evaluation(player int, hitScore int, moves [4][2]int8) *Analysis {
|
||||
func (b Board) Evaluation(player int8, hitScore int, moves [4][2]int8) *Analysis {
|
||||
a := &Analysis{
|
||||
Board: b,
|
||||
Moves: moves,
|
||||
|
@ -549,7 +652,7 @@ func (b Board) Analyze(available [][4][2]int8, result *[]*Analysis) {
|
|||
}
|
||||
}
|
||||
|
||||
if b.StartingPosition(1) && b[SpaceRoll1] != b[SpaceRoll2] {
|
||||
if b[SpaceVariant] != VariantTabula && b.StartingPosition(1) {
|
||||
r1, r2 := b[SpaceRoll1], b[SpaceRoll2]
|
||||
if r2 > r1 {
|
||||
r1, r2 = r2, r1
|
||||
|
@ -630,7 +733,7 @@ func (b Board) Analyze(available [][4][2]int8, result *[]*Analysis) {
|
|||
})
|
||||
}
|
||||
|
||||
func (b Board) StartingPosition(player int) bool {
|
||||
func (b Board) StartingPosition(player int8) bool {
|
||||
if player == 1 {
|
||||
return b[6] == 5 && b[8] == 3 && b[13] == 5 && b[24] == 2
|
||||
}
|
||||
|
@ -666,14 +769,14 @@ func (b Board) Print() {
|
|||
log.Printf("%+v", b)
|
||||
}
|
||||
|
||||
func opponent(player int) int {
|
||||
func opponent(player int8) int8 {
|
||||
if player == 1 {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func spaceValue(player int, space int8) int {
|
||||
func spaceValue(player int8, space int8) int {
|
||||
if space == SpaceHomePlayer || space == SpaceHomeOpponent || space == SpaceBarPlayer || space == SpaceBarOpponent {
|
||||
return 25
|
||||
} else if player == 1 {
|
||||
|
@ -683,7 +786,7 @@ func spaceValue(player int, space int8) int {
|
|||
}
|
||||
}
|
||||
|
||||
func PseudoPips(player int, space int8) int {
|
||||
func PseudoPips(player int8, space int8) int {
|
||||
v := 6 + spaceValue(player, space) + int(math.Exp(float64(spaceValue(player, space))*0.2))*2
|
||||
if space == SpaceHomePlayer || space == SpaceHomeOpponent || (player == 1 && (space > 6 || space == SpaceBarPlayer)) || (player == 2 && (space < 19 || space == SpaceBarOpponent)) {
|
||||
v += 24
|
||||
|
|
223
board_test.go
223
board_test.go
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestMove(t *testing.T) {
|
||||
func TestMoveBackgammon(t *testing.T) {
|
||||
b := NewBoard(VariantBackgammon)
|
||||
b[SpaceRoll1] = 1
|
||||
b[SpaceRoll2] = 2
|
||||
|
@ -36,32 +36,245 @@ func TestMove(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPast(t *testing.T) {
|
||||
func TestMoveTabula(t *testing.T) {
|
||||
{
|
||||
b := NewBoard(VariantTabula)
|
||||
b[SpaceRoll1] = 1
|
||||
b[SpaceRoll2] = 2
|
||||
|
||||
bc := b.Move(SpaceHomePlayer, 23, 1)
|
||||
got, expected := bc[SpaceHomePlayer], int8(14)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", SpaceHomePlayer, expected, got)
|
||||
}
|
||||
got, expected = bc[23], int8(1)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 23, expected, got)
|
||||
}
|
||||
bc = bc.Move(SpaceHomePlayer, 22, 1)
|
||||
got, expected = bc[SpaceHomePlayer], int8(13)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", SpaceHomePlayer, expected, got)
|
||||
}
|
||||
got, expected = bc[22], int8(1)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 22, expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b := Board{0, 1, 2, 3, 4, 4, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 1, 0, 2}
|
||||
b[SpaceRoll1] = 1
|
||||
b[SpaceRoll2] = 2
|
||||
|
||||
bc := b.UseRoll(1, 2, 1).Move(1, 2, 1)
|
||||
got, expected := bc[1], int8(0)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 1, expected, got)
|
||||
}
|
||||
got, expected = bc[2], int8(3)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 2, expected, got)
|
||||
}
|
||||
|
||||
if !bc.HaveRoll(5, 7, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", false, true)
|
||||
}
|
||||
|
||||
if bc.HaveRoll(12, 13, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", false, true)
|
||||
}
|
||||
|
||||
if !bc.HaveRoll(12, 14, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", true, true)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b := Board{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 0, 0, 2}
|
||||
b[SpaceRoll1] = 1
|
||||
b[SpaceRoll2] = 2
|
||||
|
||||
if b.HaveRoll(12, 13, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", false, true)
|
||||
}
|
||||
|
||||
bc := b.UseRoll(0, 1, 1).Move(0, 1, 1)
|
||||
got, expected := bc[0], int8(0)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 0, expected, got)
|
||||
}
|
||||
got, expected = bc[1], int8(1)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 1, expected, got)
|
||||
}
|
||||
|
||||
if bc.HaveRoll(12, 13, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", false, false)
|
||||
}
|
||||
|
||||
if !bc.HaveRoll(12, 14, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b := Board{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 0, 0, 1, 0, 2}
|
||||
b[SpaceRoll1] = 1
|
||||
b[SpaceRoll2] = 2
|
||||
|
||||
if !b.HaveRoll(12, 14, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", true, false)
|
||||
}
|
||||
|
||||
if b.MayBearOff(1) {
|
||||
t.Errorf("unexpected bear off value: expected %v: got %v", false, true)
|
||||
}
|
||||
|
||||
b = b.Move(12, 14, 1).UseRoll(12, 14, 1)
|
||||
got, expected := b[12], int8(0)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 12, expected, got)
|
||||
}
|
||||
got, expected = b[14], int8(1)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 14, expected, got)
|
||||
}
|
||||
|
||||
if !b.MayBearOff(1) {
|
||||
t.Errorf("unexpected bear off value: expected %v: got %v", true, false)
|
||||
}
|
||||
|
||||
if !b.HaveRoll(14, 15, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", true, false)
|
||||
}
|
||||
|
||||
if b.HaveRoll(14, 16, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", false, true)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b := Board{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -15, 0, 0, 0, 0, 0, 0, 1, 0, 2}
|
||||
b[SpaceRoll1] = 1
|
||||
b[SpaceRoll2] = 2
|
||||
|
||||
if !b.HaveRoll(12, 14, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", true, false)
|
||||
}
|
||||
|
||||
if b.MayBearOff(1) {
|
||||
t.Errorf("unexpected bear off value: expected %v: got %v", false, true)
|
||||
}
|
||||
|
||||
if b.HaveRoll(24, 0, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", false, true)
|
||||
}
|
||||
|
||||
b = b.UseRoll(12, 14, 1).Move(12, 14, 1)
|
||||
got, expected := b[12], int8(0)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 12, expected, got)
|
||||
}
|
||||
got, expected = b[14], int8(1)
|
||||
if got != expected {
|
||||
t.Errorf("unexpected space %d value: expected %d: got %d", 14, expected, got)
|
||||
}
|
||||
|
||||
if !b.MayBearOff(1) {
|
||||
t.Errorf("unexpected bear off value: expected %v: got %v", true, false)
|
||||
}
|
||||
|
||||
if !b.HaveRoll(24, 0, 1) {
|
||||
t.Errorf("unexpected have roll value: expected %v: got %v", true, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPastBackgammon(t *testing.T) {
|
||||
b := NewBoard(VariantBackgammon)
|
||||
got, expected := b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{0, 1, 3, -1, 0, -1, 0, -2, 0, 0, -1, 0, -3, 3, 0, 0, 0, -2, 0, -5, 4, 0, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5}
|
||||
b = Board{0, 1, 3, -1, 0, -1, 0, -2, 0, 0, -1, 0, -3, 3, 0, 0, 0, -2, 0, -5, 4, 0, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 1, 1, 0}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{0, -1, 1, -2, -1, 2, 4, 0, 0, 0, 0, 0, -1, 2, -1, 0, 0, -1, 3, -3, 0, 3, -1, -3, -1, 0, 0, 0, 4, 3, 0, 0}
|
||||
b = Board{0, -1, 1, -2, -1, 2, 4, 0, 0, 0, 0, 0, -1, 2, -1, 0, 0, -1, 3, -3, 0, 3, -1, -3, -1, 0, 0, 0, 4, 3, 0, 0, 1, 1, 0}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{7, 2, 2, 4, 0, -2, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, -4, 0, -2, -1, -1, -1, 0, 0, 0, 6, 2, 0, 0}
|
||||
b = Board{7, 2, 2, 4, 0, -2, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, -4, 0, -2, -1, -1, -1, 0, 0, 0, 6, 2, 0, 0, 1, 1, 0}
|
||||
got, expected = b.Past(), true
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPastAcey(t *testing.T) {
|
||||
b := NewBoard(VariantAceyDeucey)
|
||||
got, expected := b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{0, 1, 3, -1, 0, -1, 0, -2, 0, 0, -1, 0, -3, 3, 0, 0, 0, -2, 0, -5, 4, 0, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 1, 1, 1}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{0, -1, 1, -2, -1, 2, 4, 0, 0, 0, 0, 0, -1, 2, -1, 0, 0, -1, 3, -3, 0, 3, -1, -3, -1, 0, 0, 0, 4, 3, 0, 0, 1, 1, 1}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{7, 2, 2, 4, 0, -2, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, -4, 0, -2, -1, -1, -1, 0, 0, 0, 6, 2, 0, 0, 0, 1, 1}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{7, 2, 2, 4, 0, -2, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, -4, 0, -2, -1, -1, -1, 0, 0, 0, 6, 2, 0, 0, 1, 1, 1}
|
||||
got, expected = b.Past(), true
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPastTabula(t *testing.T) {
|
||||
b := NewBoard(VariantTabula)
|
||||
got, expected := b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{0, 1, 3, -1, 0, -1, 0, -2, 0, 0, -1, 0, -3, 3, 0, 0, 0, -2, 0, -5, 4, 0, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 1, 1, 2}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{0, -1, 1, -2, -1, 2, 4, 0, 0, 0, 0, 0, -1, 2, -1, 0, 0, -1, 3, -3, 0, 3, -1, -3, -1, 0, 0, 0, 4, 3, 0, 0, 1, 1, 2}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
|
||||
b = Board{7, 2, 2, 4, 0, -2, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, -4, 0, -2, -1, -1, -1, 0, 0, 0, 6, 2, 0, 0, 1, 1, 2}
|
||||
got, expected = b.Past(), false
|
||||
if got != expected {
|
||||
t.Errorf("unexpected past value: expected %v: got %v", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlots(t *testing.T) {
|
||||
b := NewBoard(VariantBackgammon)
|
||||
got, expected := b.Blots(1), 0
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"code.rocket9labs.com/tslocum/tabula"
|
||||
)
|
||||
|
@ -35,6 +36,32 @@ func main() {
|
|||
//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}
|
||||
|
||||
analysis := make([]*tabula.Analysis, 0, tabula.AnalysisBufferSize)
|
||||
|
||||
// should be 3/1 then 5/0 in acey, then fix backgammon movement
|
||||
// test cases for issues first then fix until tests pass
|
||||
b := tabula.Board{0, 5, 2, 5, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -2, -2, -2, -3, -3, -2, 0, 1, 0, 0, 0, 5, 2, 0, 0, 1, 1, 1}
|
||||
log.Println(b[24])
|
||||
b.Print()
|
||||
available, _ := b.Available(1)
|
||||
for i := range available {
|
||||
log.Println(available[i])
|
||||
}
|
||||
b.Analyze(available, &analysis)
|
||||
for i := range analysis {
|
||||
log.Println(analysis[i])
|
||||
}
|
||||
log.Println(b)
|
||||
b = b.UseRoll(3, 1, 1).Move(3, 1, 1)
|
||||
log.Println("NEW AVAILABLE")
|
||||
log.Println(b)
|
||||
available, _ = b.Available(1)
|
||||
for i := range available {
|
||||
log.Println(available[i])
|
||||
}
|
||||
log.Println(b)
|
||||
os.Exit(0)
|
||||
|
||||
// Print opening moves.
|
||||
for r1 := 1; r1 <= 6; r1++ {
|
||||
for r2 := 1; r2 <= 6; r2++ {
|
||||
b := tabula.NewBoard(tabula.VariantBackgammon)
|
||||
|
|
2
go.mod
2
go.mod
|
@ -2,4 +2,4 @@ module code.rocket9labs.com/tslocum/tabula
|
|||
|
||||
go 1.17
|
||||
|
||||
require code.rocket9labs.com/tslocum/bei v0.0.0-20240107212214-bcc7b6933a4c
|
||||
require code.rocket9labs.com/tslocum/bei v0.0.0-20240108012722-6db380cc190b
|
||||
|
|
4
go.sum
4
go.sum
|
@ -1,2 +1,2 @@
|
|||
code.rocket9labs.com/tslocum/bei v0.0.0-20240107212214-bcc7b6933a4c h1:fiH72XLcHof1XvVeBw/1NvaS+iIzoZqCTn7Mv0AAYss=
|
||||
code.rocket9labs.com/tslocum/bei v0.0.0-20240107212214-bcc7b6933a4c/go.mod h1:tS60/VNAJphKvDBkSLQhKALa15msIAuWWfEKNc4oFZc=
|
||||
code.rocket9labs.com/tslocum/bei v0.0.0-20240108012722-6db380cc190b h1:Y0a14Kf/hSYepSmp4ZfDeE4CZZGBGBS97CNjCbKJm0c=
|
||||
code.rocket9labs.com/tslocum/bei v0.0.0-20240108012722-6db380cc190b/go.mod h1:tS60/VNAJphKvDBkSLQhKALa15msIAuWWfEKNc4oFZc=
|
||||
|
|
Loading…
Reference in a new issue