|
|
|
@ -4,7 +4,6 @@ import (
@@ -4,7 +4,6 @@ import (
|
|
|
|
|
"bytes" |
|
|
|
|
"fmt" |
|
|
|
|
"log" |
|
|
|
|
"sort" |
|
|
|
|
"strconv" |
|
|
|
|
"strings" |
|
|
|
|
"sync" |
|
|
|
@ -73,12 +72,13 @@ type Board struct {
@@ -73,12 +72,13 @@ type Board struct {
|
|
|
|
|
moves [][2]int |
|
|
|
|
movesColor int |
|
|
|
|
|
|
|
|
|
validMoves map[int][]int |
|
|
|
|
validMoves map[int][][]int |
|
|
|
|
|
|
|
|
|
from map[int]int |
|
|
|
|
to map[int]int |
|
|
|
|
|
|
|
|
|
selected [2]int |
|
|
|
|
selectedNum int |
|
|
|
|
selectedSpace int |
|
|
|
|
|
|
|
|
|
premove [][2]int |
|
|
|
|
Premovefrom map[int]int |
|
|
|
@ -130,8 +130,8 @@ func (b *Board) GetIntState() []int {
@@ -130,8 +130,8 @@ func (b *Board) GetIntState() []int {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) resetSelection() { |
|
|
|
|
b.selected[0] = 0 |
|
|
|
|
b.selected[1] = 0 |
|
|
|
|
b.selectedSpace = 0 |
|
|
|
|
b.selectedNum = 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) autoSendMoves() { |
|
|
|
@ -142,29 +142,6 @@ func (b *Board) autoSendMoves() {
@@ -142,29 +142,6 @@ func (b *Board) autoSendMoves() {
|
|
|
|
|
if b.v[StateMovablePieces] > 0 { |
|
|
|
|
movable = b.v[StateMovablePieces] |
|
|
|
|
} |
|
|
|
|
if len(b.premove) == 1 { |
|
|
|
|
abs := b.premove[0][1] - b.premove[0][0] |
|
|
|
|
direction := 1 |
|
|
|
|
if abs < 0 { |
|
|
|
|
abs *= -1 |
|
|
|
|
direction = -1 |
|
|
|
|
} |
|
|
|
|
if b.v[StatePlayerDice1] == b.v[StatePlayerDice2] { |
|
|
|
|
for expandDoubles := 4; expandDoubles >= 2; expandDoubles-- { |
|
|
|
|
if abs != b.v[StatePlayerDice1]*expandDoubles { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
from, _ := b.premove[0][0], b.premove[0][1] |
|
|
|
|
|
|
|
|
|
b.premove = nil |
|
|
|
|
for i := 1; i <= expandDoubles; i++ { |
|
|
|
|
b.premove = append(b.premove, [2]int{from + ((b.v[StatePlayerDice1]*i - 1) * direction), from + ((b.v[StatePlayerDice1] * i) * direction)}) |
|
|
|
|
} |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if len(b.premove) < movable { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
@ -370,10 +347,10 @@ func (b *Board) renderSpace(index int, spaceValue int) []byte {
@@ -370,10 +347,10 @@ func (b *Board) renderSpace(index int, spaceValue int) []byte {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Highlight legal moves
|
|
|
|
|
highlightSpace := b.ValidMove(b.selected[0], index) |
|
|
|
|
highlightSpace := b.ValidMove(b.selectedSpace, index) |
|
|
|
|
highlightSpace = false // TODO Make configurable, disable by default
|
|
|
|
|
//+(b.v[StatePlayerDice1]*b.v[StatePlayerColor]) ||b.selected[0] == index+(b.v[StatePlayerDice2]*b.v[StatePlayerColor])) && b.selected[1] > 0
|
|
|
|
|
if b.selected[1] > 0 && highlightSpace && index != 25 && index != 0 { |
|
|
|
|
//+(b.v[StatePlayerDice1]*b.v[StatePlayerColor]) ||b.selectedSpace == index+(b.v[StatePlayerDice2]*b.v[StatePlayerColor])) && b.selectedNum > 0
|
|
|
|
|
if b.selectedNum > 0 && highlightSpace && index != 25 && index != 0 { |
|
|
|
|
foregroundColor = "black" |
|
|
|
|
backgroundColor = "yellow" |
|
|
|
|
} |
|
|
|
@ -384,7 +361,7 @@ func (b *Board) renderSpace(index int, spaceValue int) []byte {
@@ -384,7 +361,7 @@ func (b *Board) renderSpace(index int, spaceValue int) []byte {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rightArrowFrom := (b.v[StateDirection] == b.movesColor) == (index > 12) |
|
|
|
|
if b.selected[0] == index && b.selected[1] > 0 && spaceValue <= abs && spaceValue > abs-b.selected[1] { |
|
|
|
|
if b.selectedSpace == index && b.selectedNum > 0 && spaceValue <= abs && spaceValue > abs-b.selectedNum { |
|
|
|
|
r = []byte("*") |
|
|
|
|
} else if b.Premovefrom[index] > 0 && spaceValue > (abs+b.Premoveto[index])-b.Premovefrom[index] && spaceValue <= abs+b.Premoveto[index] { |
|
|
|
|
if index == 25-b.PlayerBarSpace() { |
|
|
|
@ -425,7 +402,7 @@ func (b *Board) renderSpace(index int, spaceValue int) []byte {
@@ -425,7 +402,7 @@ func (b *Board) renderSpace(index int, spaceValue int) []byte {
|
|
|
|
|
func (b *Board) ResetMoves() { |
|
|
|
|
b.moves = nil |
|
|
|
|
b.movesColor = 0 |
|
|
|
|
b.validMoves = make(map[int][]int) |
|
|
|
|
b.validMoves = make(map[int][][]int) |
|
|
|
|
b.from = make(map[int]int) |
|
|
|
|
b.to = make(map[int]int) |
|
|
|
|
} |
|
|
|
@ -453,9 +430,15 @@ func (b *Board) allPlayerPiecesInHomeBoard() bool {
@@ -453,9 +430,15 @@ func (b *Board) allPlayerPiecesInHomeBoard() bool {
|
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
value := b.v[StateBoardSpace0+index] |
|
|
|
|
|
|
|
|
|
// Include pre-moves
|
|
|
|
|
mod := b.v[StatePlayerColor] |
|
|
|
|
value -= b.client.Board.Premovefrom[index] * mod |
|
|
|
|
return value != 0 |
|
|
|
|
|
|
|
|
|
if b.v[StatePlayerColor] == -1 { |
|
|
|
|
return value < 0 |
|
|
|
|
} |
|
|
|
|
return value > 0 |
|
|
|
|
} |
|
|
|
|
for i := 1; i < 24; i++ { |
|
|
|
|
if i >= homeBoardStart && i <= homeBoardEnd { |
|
|
|
@ -479,12 +462,12 @@ func (b *Board) spaceAvailable(index int) bool {
@@ -479,12 +462,12 @@ func (b *Board) spaceAvailable(index int) bool {
|
|
|
|
|
(b.v[StatePlayerColor] == -1 && b.v[StateBoardSpace0+index] <= 1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) GetValidMoves(from int) []int { |
|
|
|
|
func (b *Board) GetValidMoves(from int) [][]int { |
|
|
|
|
if validMoves, ok := b.validMoves[from]; ok { |
|
|
|
|
return validMoves |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var validMoves []int |
|
|
|
|
var validMoves [][]int |
|
|
|
|
defer func() { |
|
|
|
|
b.validMoves[from] = validMoves |
|
|
|
|
}() |
|
|
|
@ -493,7 +476,6 @@ func (b *Board) GetValidMoves(from int) []int {
@@ -493,7 +476,6 @@ func (b *Board) GetValidMoves(from int) []int {
|
|
|
|
|
return validMoves |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO consider opponent blocking midway In full move
|
|
|
|
|
trySpaces := [][]int{ |
|
|
|
|
{b.v[StatePlayerDice1]}, |
|
|
|
|
{b.v[StatePlayerDice2]}, |
|
|
|
@ -529,12 +511,10 @@ CHECKSPACES:
@@ -529,12 +511,10 @@ CHECKSPACES:
|
|
|
|
|
space := from + (checkSpace * b.v[StateDirection]) |
|
|
|
|
if _, value := foundMoves[space]; !value { |
|
|
|
|
foundMoves[space] = true |
|
|
|
|
validMoves = append(validMoves, space) |
|
|
|
|
validMoves = append(validMoves, trySpaces[i]) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sort.Ints(validMoves) |
|
|
|
|
|
|
|
|
|
return validMoves |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -560,8 +540,16 @@ func (b *Board) ValidMove(f int, t int) bool {
@@ -560,8 +540,16 @@ func (b *Board) ValidMove(f int, t int) bool {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
validMoves := b.GetValidMoves(f) |
|
|
|
|
CHECKVALID: |
|
|
|
|
for i := range validMoves { |
|
|
|
|
if validMoves[i] == t { |
|
|
|
|
checkSpace := 0 |
|
|
|
|
for _, space := range validMoves[i] { |
|
|
|
|
checkSpace += space |
|
|
|
|
if !b.spaceAvailable(f + (checkSpace * b.v[StateDirection])) { |
|
|
|
|
continue CHECKVALID |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if f+(checkSpace*b.v[StateDirection]) == t { |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -603,7 +591,7 @@ func (b *Board) Move(player int, f string, t string) {
@@ -603,7 +591,7 @@ func (b *Board) Move(player int, f string, t string) {
|
|
|
|
|
|
|
|
|
|
b.v[StateTurn] = player * -1 |
|
|
|
|
|
|
|
|
|
b.validMoves = make(map[int][]int) |
|
|
|
|
b.validMoves = make(map[int][][]int) |
|
|
|
|
b.ResetPreMoves() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -627,18 +615,77 @@ func (b *Board) SimplifyMoves() {
@@ -627,18 +615,77 @@ func (b *Board) SimplifyMoves() {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) AddPreMove(from int, to int) bool { |
|
|
|
|
func (b *Board) GetSelection() (num int, space int) { |
|
|
|
|
return b.selectedNum, b.selectedSpace |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) SetSelection(num int, space int) { |
|
|
|
|
b.selectedNum, b.selectedSpace = num, space |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) ResetSelection() { |
|
|
|
|
b.selectedNum, b.selectedSpace = 0, 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) addPreMove(from int, to int, num int) bool { |
|
|
|
|
// Allow bearing off when the player moves their own pieces on to the bar
|
|
|
|
|
if to == 0 || to == 25 { |
|
|
|
|
to = b.PlayerHomeSpace() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Expand combined move
|
|
|
|
|
moves := b.client.Board.GetValidMoves(from) |
|
|
|
|
|
|
|
|
|
CHECKPREMOVES: |
|
|
|
|
for i := range moves { |
|
|
|
|
checkSpace := 0 |
|
|
|
|
for _, space := range moves[i] { |
|
|
|
|
checkSpace += space |
|
|
|
|
lf("CHECK %d %d", checkSpace, from+(checkSpace*b.v[StateDirection])) |
|
|
|
|
if !b.spaceAvailable(from + (checkSpace * b.v[StateDirection])) { |
|
|
|
|
continue CHECKPREMOVES |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
lf("SECOND PHASE %+v %d", moves[i], num) |
|
|
|
|
if (from+(checkSpace*b.v[StateDirection]) == to) && len(moves[i]) > 1 { |
|
|
|
|
lf("SECOND.5 PHASE %+v %d", moves[i], num) |
|
|
|
|
for j := 0; j < num; j++ { |
|
|
|
|
checkSpace = 0 |
|
|
|
|
lastSpace := 0 |
|
|
|
|
for _, space := range moves[i] { |
|
|
|
|
checkSpace += space |
|
|
|
|
lf("THIRD PHASE %d %d", from+(lastSpace*b.v[StateDirection]), from+(checkSpace*b.v[StateDirection])) |
|
|
|
|
|
|
|
|
|
if !b.addPreMove(from+(lastSpace*b.v[StateDirection]), from+(checkSpace*b.v[StateDirection]), 1) { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
lastSpace = checkSpace |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !b.ValidMove(from, to) { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
b.premove = append(b.premove, [2]int{from, to}) |
|
|
|
|
b.Premovefrom[from]++ |
|
|
|
|
b.Premoveto[to]++ |
|
|
|
|
|
|
|
|
|
for i := 0; i < num; i++ { |
|
|
|
|
b.premove = append(b.premove, [2]int{from, to}) |
|
|
|
|
b.Premovefrom[from]++ |
|
|
|
|
b.Premoveto[to]++ |
|
|
|
|
} |
|
|
|
|
lf("ADD %+v", b.premove) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *Board) AddPreMove(from int, to int) bool { |
|
|
|
|
if !b.addPreMove(from, to, b.selectedNum) { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
lf("FINAL %+v", b.premove) |
|
|
|
|
|
|
|
|
|
b.resetSelection() |
|
|
|
|
b.autoSendMoves() |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|