Store moves as [4][2]int8 instead of [4][2]int

This commit is contained in:
Trevor Slocum 2023-12-17 22:47:15 -08:00
parent 51db50b9ba
commit a46a92776b
4 changed files with 84 additions and 53 deletions

View file

@ -53,7 +53,7 @@ func init() {
type Analysis struct {
Board Board
Moves [4][2]int
Moves [4][2]int8
Past bool
Score float64

View file

@ -14,17 +14,17 @@ var (
)
const (
SpaceHomePlayer = 0
SpaceHomeOpponent = 25
SpaceBarPlayer = 26
SpaceBarOpponent = 27
SpaceRoll1 = 28
SpaceRoll2 = 29
SpaceRoll3 = 30
SpaceRoll4 = 31
SpaceEnteredPlayer = 32 // Whether the player has fully entered the board. Only used in acey-deucey games.
SpaceEnteredOpponent = 33 // Whether the opponent has fully entered the board. Only used in acey-deucey games.
SpaceAcey = 34 // 0 - Backgammon, 1 - Acey-deucey.
SpaceHomePlayer int8 = 0
SpaceHomeOpponent int8 = 25
SpaceBarPlayer int8 = 26
SpaceBarOpponent int8 = 27
SpaceRoll1 int8 = 28
SpaceRoll2 int8 = 29
SpaceRoll3 int8 = 30
SpaceRoll4 int8 = 31
SpaceEnteredPlayer int8 = 32 // Whether the player has fully entered the board. Only used in acey-deucey games.
SpaceEnteredOpponent int8 = 33 // Whether the opponent has fully entered the board. Only used in acey-deucey games.
SpaceAcey int8 = 34 // 0 - Backgammon, 1 - Acey-deucey.
)
const (
@ -49,7 +49,7 @@ func (b Board) SetValue(space int, value int8) Board {
}
// Move moves a checker on the board.
func (b Board) Move(from int, to int, player int) Board {
func (b Board) Move(from int8, to int8, player int) 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 {
@ -67,7 +67,7 @@ func (b Board) Move(from int, to int, player int) Board {
}
delta := int8(1)
if player == 2 {
delta = int8(-1)
delta = -1
}
b[from], b[to] = b[from]-delta, b[to]+delta
return b
@ -110,7 +110,7 @@ func (b Board) MayBearOff(player int) bool {
return true
}
func (b Board) spaceDiff(player int, from int, to int) int {
func (b Board) spaceDiff(player int, from int8, to int8) int8 {
switch {
case from < 0 || from > 27 || to < 0 || to > 27:
return 0
@ -145,7 +145,7 @@ func (b Board) spaceDiff(player int, from int, to int) int {
}
// HaveRoll returns whether the player has a sufficient die roll for the specified move.
func (b Board) HaveRoll(from int, to int, player int) bool {
func (b Board) HaveRoll(from int8, to int8, player int) bool {
barSpace := SpaceBarPlayer
if player == 2 {
barSpace = SpaceBarOpponent
@ -154,7 +154,7 @@ func (b Board) HaveRoll(from int, to int, player int) bool {
return false
}
delta := int8(b.spaceDiff(player, from, to))
delta := b.spaceDiff(player, from, to)
if delta == 0 {
return false
}
@ -185,8 +185,8 @@ func (b Board) HaveRoll(from int, to int, player int) bool {
}
// UseRoll uses a die roll.
func (b Board) UseRoll(from int, to int, player int) Board {
delta := int8(b.spaceDiff(player, from, to))
func (b Board) UseRoll(from int8, to int8, player int) Board {
delta := b.spaceDiff(player, from, to)
if delta == 0 {
b.Print()
log.Panic("unknown space diff", from, to, player)
@ -244,7 +244,7 @@ func (b Board) UseRoll(from int, to int, player int) Board {
return b
}
func (b Board) _available(player int) [][2]int {
func (b Board) _available(player int) [][2]int8 {
homeSpace := SpaceHomePlayer
barSpace := SpaceBarPlayer
opponentBarSpace := SpaceBarOpponent
@ -256,23 +256,23 @@ func (b Board) _available(player int) [][2]int {
mayBearOff := b.MayBearOff(player)
onBar := b[barSpace] != 0
var moves [][2]int
var moves [][2]int8
if b[SpaceAcey] == 1 && ((player == 1 && b[SpaceEnteredPlayer] == 0) || (player == 2 && b[SpaceEnteredOpponent] == 0)) && b[homeSpace] != 0 {
for space := 1; space < 25; space++ {
for space := int8(1); space < 25; space++ {
v := b[space]
if ((player == 1 && v >= -1) || (player == 2 && v <= 1)) && b.HaveRoll(homeSpace, space, player) {
moves = append(moves, [2]int{homeSpace, space})
moves = append(moves, [2]int8{homeSpace, space})
}
}
}
for from := 0; from < 28; from++ {
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 {
for to := 0; to < from; to++ {
for to := int8(0); to < from; to++ {
if to == SpaceBarPlayer || to == SpaceBarOpponent || to == SpaceHomeOpponent || (to == SpaceHomePlayer && !mayBearOff) {
continue
}
@ -280,7 +280,7 @@ func (b Board) _available(player int) [][2]int {
if (player == 1 && v < -1) || (player == 2 && v > 1) || !b.HaveRoll(from, to, player) {
continue
}
moves = append(moves, [2]int{from, to})
moves = append(moves, [2]int8{from, to})
}
} else { // TODO clean up
start := from + 1
@ -295,7 +295,7 @@ func (b Board) _available(player int) [][2]int {
if (player == 1 && v < -1) || (player == 2 && v > 1) || !b.HaveRoll(from, to, player) {
continue
}
moves = append(moves, [2]int{from, to})
moves = append(moves, [2]int8{from, to})
}
}
}
@ -304,11 +304,11 @@ func (b Board) _available(player int) [][2]int {
}
// Available returns legal moves available.
func (b Board) Available(player int) ([][4][2]int, []Board) {
var allMoves [][4][2]int
func (b Board) Available(player int) ([][4][2]int8, []Board) {
var allMoves [][4][2]int8
resultMutex := &sync.Mutex{}
movesFound := func(moves [4][2]int) bool {
movesFound := func(moves [4][2]int8) bool {
resultMutex.Lock()
for i := range allMoves {
if movesEqual(allMoves[i], moves) {
@ -327,7 +327,7 @@ func (b Board) Available(player int) ([][4][2]int, []Board) {
newBoard := b.Move(move[0], move[1], player).UseRoll(move[0], move[1], player)
newAvailable := newBoard._available(player)
if len(newAvailable) == 0 {
moves := [4][2]int{move}
moves := [4][2]int8{move}
if !movesFound(moves) {
allMoves = append(allMoves, moves)
boards = append(boards, newBoard)
@ -338,7 +338,7 @@ func (b Board) Available(player int) ([][4][2]int, []Board) {
newBoard2 := newBoard.Move(move2[0], move2[1], player).UseRoll(move2[0], move2[1], player)
newAvailable2 := newBoard2._available(player)
if len(newAvailable2) == 0 {
moves := [4][2]int{move, move2}
moves := [4][2]int8{move, move2}
if !movesFound(moves) {
allMoves = append(allMoves, moves)
boards = append(boards, newBoard2)
@ -350,7 +350,7 @@ func (b Board) Available(player int) ([][4][2]int, []Board) {
newBoard3 := newBoard2.Move(move3[0], move3[1], player).UseRoll(move3[0], move3[1], player)
newAvailable3 := newBoard3._available(player)
if len(newAvailable3) == 0 {
moves := [4][2]int{move, move2, move3}
moves := [4][2]int8{move, move2, move3}
if !movesFound(moves) {
allMoves = append(allMoves, moves)
boards = append(boards, newBoard3)
@ -360,7 +360,7 @@ func (b Board) Available(player int) ([][4][2]int, []Board) {
}
for _, move4 := range newAvailable3 {
newBoard4 := newBoard3.Move(move4[0], move4[1], player).UseRoll(move4[0], move4[1], player)
moves := [4][2]int{move, move2, move3, move4}
moves := [4][2]int8{move, move2, move3, move4}
if !movesFound(moves) {
allMoves = append(allMoves, moves)
boards = append(boards, newBoard4)
@ -370,7 +370,7 @@ func (b Board) Available(player int) ([][4][2]int, []Board) {
}
}
}
var newMoves [][4][2]int
var newMoves [][4][2]int8
for i := 0; i < len(allMoves); i++ {
l := 0
for j := 0; j < 4; j++ {
@ -422,7 +422,7 @@ func (b Board) Pips(player int) int {
} else {
pips += int(checkers(player, b[SpaceBarOpponent])) * PseudoPips(player, SpaceBarOpponent)
}
for space := 1; space < 25; space++ {
for space := int8(1); space < 25; space++ {
pips += int(checkers(player, b[space])) * PseudoPips(player, space)
}
return pips
@ -431,7 +431,7 @@ func (b Board) Pips(player int) int {
func (b Board) Blots(player int) int {
o := opponent(player)
var pips int
for space := 1; space < 25; space++ {
for space := int8(1); space < 25; space++ {
if checkers(player, b[space]) == 1 {
pips += PseudoPips(o, space)
}
@ -454,7 +454,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]int) *Analysis {
func (b Board) Evaluation(player int, hitScore int, moves [4][2]int8) *Analysis {
a := &Analysis{
Board: b,
Moves: moves,
@ -466,7 +466,7 @@ func (b Board) Evaluation(player int, hitScore int, moves [4][2]int) *Analysis {
return a
}
func (b Board) Analyze(available [][4][2]int, result *[]*Analysis) {
func (b Board) Analyze(available [][4][2]int8, result *[]*Analysis) {
if len(available) == 0 {
*result = (*result)[:0]
return
@ -556,7 +556,7 @@ func (b Board) ChooseDoubles(result *[]*Analysis) int {
bestDoubles := 6
bestScore := math.MaxFloat64
var available [][4][2]int
var available [][4][2]int8
for i := 0; i < 6; i++ {
doubles := int8(i + 1)
bc := b
@ -584,17 +584,17 @@ func opponent(player int) int {
return 1
}
func spaceValue(player int, space int) int {
func spaceValue(player int, space int8) int {
if space == SpaceHomePlayer || space == SpaceHomeOpponent || space == SpaceBarPlayer || space == SpaceBarOpponent {
return 25
} else if player == 1 {
return space
return int(space)
} else {
return 25 - space
return int(25 - space)
}
}
func PseudoPips(player int, space int) int {
func PseudoPips(player int, 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
@ -602,7 +602,7 @@ func PseudoPips(player int, space int) int {
return v
}
func movesEqual(a [4][2]int, b [4][2]int) bool {
func movesEqual(a [4][2]int8, b [4][2]int8) bool {
if a[0][0] == b[0][0] && a[0][1] == b[0][1] { // 1
if a[1][0] == b[1][0] && a[1][1] == b[1][1] { // 2
if (a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) || // 3,4

View file

@ -187,7 +187,7 @@ func BenchmarkAvailable(b *testing.B) {
board[SpaceRoll3] = c.roll3
board[SpaceRoll4] = c.roll4
var available [][4][2]int
var available [][4][2]int8
b.ResetTimer()
for i := 0; i < b.N; i++ {
available, _ = board.Available(1)

View file

@ -17,21 +17,24 @@ func main() {
if pips {
fmt.Println("| Space | Pseudopips |")
fmt.Println("| --- | --- |")
for space := 1; space <= 25; space++ {
for space := int8(1); space <= 25; space++ {
fmt.Printf("| %d | %d |\n", space, tabula.PseudoPips(1, space))
}
return
}
b := tabula.NewBoard(true)
b[tabula.SpaceRoll1] = 6
b[tabula.SpaceRoll2] = 6
b[tabula.SpaceRoll3] = 6
b[tabula.SpaceRoll4] = 6
b.Print()
//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}
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)
@ -44,4 +47,32 @@ func main() {
for i, a := range analysis {
log.Printf("%+v %+v", i, a)
}
//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)
}*/
}