Store moves as [4][2]int8 instead of [4][2]int
This commit is contained in:
parent
51db50b9ba
commit
a46a92776b
4 changed files with 84 additions and 53 deletions
|
@ -53,7 +53,7 @@ func init() {
|
|||
|
||||
type Analysis struct {
|
||||
Board Board
|
||||
Moves [4][2]int
|
||||
Moves [4][2]int8
|
||||
Past bool
|
||||
Score float64
|
||||
|
||||
|
|
88
board.go
88
board.go
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}*/
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue