Optimize movesEqual

This commit is contained in:
Trevor Slocum 2024-10-18 12:13:38 -07:00
parent 91065b63f1
commit 9a8d60f945
2 changed files with 136 additions and 81 deletions

122
board.go
View file

@ -945,85 +945,45 @@ func PseudoPips(player int8, space int8, variant int8) int {
}
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
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]) { // 4,3
return true
}
}
if a[1][0] == b[2][0] && a[1][1] == b[2][1] { // 3
if (a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) || // 2,4
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) { // 4,2
return true
}
}
if a[1][0] == b[3][0] && a[1][1] == b[3][1] { // 4
if (a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) || // 3,2
(a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]) { // 2,3
return true
}
}
}
if a[0][0] == b[1][0] && a[0][1] == b[1][1] { // 2
if a[1][0] == b[0][0] && a[1][1] == b[0][1] { // 1
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
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]) { // 4,3
return true
}
}
if a[1][0] == b[2][0] && a[1][1] == b[2][1] { // 3
if (a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) || // 4,1
(a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) { // 1,4
return true
}
}
if a[1][0] == b[3][0] && a[1][1] == b[3][1] { // 4
if (a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) || // 3,1
(a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]) { // 1,3
return true
}
}
}
if a[0][0] == b[2][0] && a[0][1] == b[2][1] { // 3
if a[1][0] == b[0][0] && a[1][1] == b[0][1] { // 1
if (a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) || // 2,4
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) { // 4,2
return true
}
}
if a[1][0] == b[1][0] && a[1][1] == b[1][1] { // 2
if (a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) || // 1,4
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) { // 4,1
return true
}
}
if a[1][0] == b[3][0] && a[1][1] == b[3][1] { // 4
if (a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) || // 2,1
(a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) { // 1,2
return true
}
}
}
if a[0][0] == b[3][0] && a[0][1] == b[3][1] { // 4
if a[1][0] == b[0][0] && a[1][1] == b[0][1] { // 1
if (a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) || // 3,2
(a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]) { // 2,3
return true
}
}
if a[1][0] == b[1][0] && a[1][1] == b[1][1] { // 2
if (a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]) || // 1,3
(a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) { // 3,1
return true
}
}
if a[1][0] == b[2][0] && a[1][1] == b[2][1] { // 3
if (a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) || // 1,2
(a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) { // 2,1
return true
}
}
}
return false
return true &&
(a[0][0] == b[0][0] && a[0][1] == b[0][1] && // 1
((a[1][0] == b[1][0] && a[1][1] == b[1][1] && // 2
((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
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]))) || // 4,3
(a[1][0] == b[2][0] && a[1][1] == b[2][1] && // 3
((a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) || // 2,4
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]))) || // 4,2
(a[1][0] == b[3][0] && a[1][1] == b[3][1] && // 4
((a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) || // 3,2
(a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]))))) || // 2,3
(a[0][0] == b[1][0] && a[0][1] == b[1][1] && // 2
((a[1][0] == b[0][0] && a[1][1] == b[0][1] && // 1
((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
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]))) || // 4,3
(a[1][0] == b[2][0] && a[1][1] == b[2][1] && //3
((a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) || // 4,1
(a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]))) || // 1,4
(a[1][0] == b[3][0] && a[1][1] == b[3][1] && //4
((a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) || // 3,1
(a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]))))) || // 1,3
(a[0][0] == b[2][0] && a[0][1] == b[2][1] && //3
((a[1][0] == b[0][0] && a[1][1] == b[0][1] && //1
((a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) || // 2,4
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]))) || // 4,2
(a[1][0] == b[1][0] && a[1][1] == b[1][1] && //2
((a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[3][0] && a[3][1] == b[3][1]) || // 1,4
(a[2][0] == b[3][0] && a[2][1] == b[3][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]))) || // 4,1
(a[1][0] == b[3][0] && a[1][1] == b[3][1] && //4
((a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]) || // 2,1
(a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]))))) || // 1,2
(a[0][0] == b[3][0] && a[0][1] == b[3][1] && //4
((a[1][0] == b[0][0] && a[1][1] == b[0][1] && //1
((a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) || // 3,2
(a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]))) || // 2,3
(a[1][0] == b[1][0] && a[1][1] == b[1][1] && //2
((a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[2][0] && a[3][1] == b[2][1]) || // 1,3
(a[2][0] == b[2][0] && a[2][1] == b[2][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]))) || // 3,1
(a[1][0] == b[2][0] && a[1][1] == b[2][1] && //3
((a[2][0] == b[0][0] && a[2][1] == b[0][1] && a[3][0] == b[1][0] && a[3][1] == b[1][1]) || // 1,2
(a[2][0] == b[1][0] && a[2][1] == b[1][1] && a[3][0] == b[0][0] && a[3][1] == b[0][1]))))) // 2,1
}

View file

@ -32,6 +32,31 @@ func TestAvailableHighRoll(t *testing.T) {
}
}
func TestMovesEqual(t *testing.T) {
moves := [][2]int8{{1, 2}, {3, 4}, {5, 6}, {5, 7}}
indexes := permutations([]int{0, 1, 2, 3})
toMoves := func(i int) [4][2]int8 {
in := indexes[i]
return [4][2]int8{moves[in[0]], moves[in[1]], moves[in[2]], moves[in[3]]}
}
for i := range moves {
for j := range moves {
a := toMoves(i)
b := toMoves(j)
if i != j && !movesEqual(a, b) {
t.Errorf("expected true, got false: %v / %v", a, b)
}
}
}
if !movesEqual(toMoves(0), toMoves(0)) {
t.Errorf("expected true, got false: %v / %v", toMoves(0), toMoves(0))
}
a, b := toMoves(0), [4][2]int8{{3, 4}, {5, 6}, {5, 7}, {1, 8}}
if movesEqual(a, b) {
t.Errorf("expected false, got true: %v / %v", a, b)
}
}
func TestMoveBackgammon(t *testing.T) {
b := NewBoard(VariantBackgammon)
b[SpaceRoll1] = 1
@ -474,6 +499,49 @@ func BenchmarkAvailable(b *testing.B) {
}
}
func BenchmarkMovesEqual(b *testing.B) {
var moves [][4][2]int8
type testCase struct {
roll1, roll2, roll3, roll4 int8
}
cases := []*testCase{
{1, 1, 1, 1},
{2, 2, 2, 2},
{3, 3, 3, 3},
{4, 4, 4, 4},
{5, 5, 5, 5},
{6, 6, 6, 6},
{1, 2, 0, 0},
{2, 3, 0, 0},
{3, 4, 0, 0},
{4, 5, 0, 0},
{5, 6, 0, 0},
}
for _, c := range cases {
board := NewBoard(VariantBackgammon)
board[SpaceRoll1] = c.roll1
board[SpaceRoll2] = c.roll2
board[SpaceRoll3] = c.roll3
board[SpaceRoll4] = c.roll4
var available [][4][2]int8
available, _ = board.Available(1)
moves = append(moves, available...)
}
var result bool
for i := 0; i < b.N; i++ {
for j := range moves {
for k := range moves {
result = movesEqual(moves[j], moves[k])
}
}
}
_ = result
}
func BenchmarkAnalyze(b *testing.B) {
type testCase struct {
roll1, roll2, roll3, roll4 int8
@ -534,3 +602,30 @@ func BenchmarkMayBearOff(b *testing.B) {
_ = allowed
}
func permutations(a []int) [][]int {
res := [][]int{}
var _inner func([]int, int)
_inner = func(a []int, n int) {
if n == 1 {
tmp := make([]int, len(a))
copy(tmp, a)
res = append(res, tmp)
} else {
for i := 0; i < n; i++ {
_inner(a, n-1)
if n%2 == 1 {
tmp := a[i]
a[i] = a[n-1]
a[n-1] = tmp
} else {
tmp := a[0]
a[0] = a[n-1]
a[n-1] = tmp
}
}
}
}
_inner(a, len(a))
return res
}