@ -1,761 +1,52 @@
@@ -1,761 +1,52 @@
package main
import (
"bytes"
"fmt"
"log"
"sort"
"strconv"
"strings"
"code.rocketnine.space/tslocum/cview"
"code.rocketnine.space/tslocum/fibs"
"github.com/gdamore/tcell/v2"
)
// TODO Add PlayerName, etc
const SpaceUnknown = - 1
const (
StateLength = iota
StatePlayerScore
StateOpponentScore
StateBoardSpace0
)
const (
StateTurn = 29 + iota
StatePlayerDice1
StatePlayerDice2
StateOpponentDice1
StateOpponentDice2
StateDoublingValue
StatePlayerMayDouble
StateOpponentMayDouble
StateWasDoubled
StatePlayerColor
StateDirection
StateObsoleteHome
StateObsoleteBar
StatePlayerHome
StateOpponentHome
StatePlayerBar
StateOpponentBar
StateMovablePieces
StateObsoletePlayerForced
StateObsoleteOpponentForced
StateRedoubles
)
const (
SpaceUnknown = - 1
)
var boardTopWhite = [ ] byte ( "+13-14-15-16-17-18-+---+19-20-21-22-23-24-+" )
var boardBottomWhite = [ ] byte ( "+12-11-10--9--8--7-+---+-6--5--4--3--2--1-+" )
var boardTopBlack = [ ] byte ( "+-1--2--3--4--5--6-+---+-7--8--9-10-11-12-+" )
var boardBottomBlack = [ ] byte ( "+24-23-22-21-20-19-+---+18-17-16-15-14-13-+" )
type Board struct {
type GameBoard struct {
Board * fibs . Board
* cview . TextView
client * Client
state string
s [ ] string
v [ ] int
moves [ ] [ 2 ] int
movesColor int
validMoves map [ int ] [ ] int
from map [ int ] int
to map [ int ] int
playerDice [ 2 ] int
opponentDice [ 2 ] int
selected [ 2 ] int
premove [ ] [ 2 ] int
premovefrom map [ int ] int
premoveto map [ int ] int
dragFromX int
dragFromY int
dragFromX , dragFromY int
}
func NewBoard ( client * Client ) * Board {
b := & Board {
func NewGameBoard ( client * fibs . Client ) * GameBoard {
b := & GameBoard {
Board : client . Board ,
TextView : cview . NewTextView ( ) ,
client : client ,
}
tv := b . TextView
tv . SetRegions ( true )
tv . SetDynamicColors ( true )
tv . SetToggleHighlights ( true )
tv . SetHighlightedFunc ( b . handleHighlight )
b . ResetMoves ( )
b . ResetPreMoves ( )
b . SetState ( initialState )
// TODO
/ *
b . v [ StatePlayerColor ] = - 1
b . v [ StateBoardSpace0 + 11 ] = 12
b . v [ StateBoardSpace0 + 9 ] = 7
b . v [ StateBoardSpace0 + 13 ] = - 13
b . v [ StateBoardSpace0 + 24 ] = - 3
b . v [ StatePlayerBar ] = 3
b . Update ( )
* /
return b
}
func ( b * Board ) resetSelection ( ) {
b . selected [ 0 ] = 0
b . selected [ 1 ] = 0
}
func ( b * Board ) autoSendMoves ( ) {
movable := 2
if b . playerDice [ 0 ] > 0 && b . playerDice [ 0 ] == b . playerDice [ 1 ] {
movable = 4
}
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 . playerDice [ 0 ] == b . playerDice [ 1 ] {
for expandDoubles := 4 ; expandDoubles >= 2 ; expandDoubles -- {
if abs != b . playerDice [ 0 ] * 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 . playerDice [ 0 ] * i - 1 ) * direction ) , from + ( ( b . playerDice [ 0 ] * i ) * direction ) } )
}
break
}
}
}
if len ( b . premove ) < movable {
return
}
moveCommand := [ ] byte ( "move" )
for j := 0 ; j < 2 ; j ++ {
for i := range b . premove {
var from string
if b . premove [ i ] [ 0 ] == 0 || b . premove [ i ] [ 0 ] == 25 {
from = "bar"
} else {
from = strconv . Itoa ( b . premove [ i ] [ 0 ] )
}
if ( j == 0 ) != ( from == "bar" ) {
continue // Always send bar moves first
}
var to string
if b . premove [ i ] [ 1 ] == b . playerHomeSpace ( ) {
to = "off"
} else {
to = strconv . Itoa ( b . premove [ i ] [ 1 ] )
}
moveCommand = append ( moveCommand , [ ] byte ( " " + from + "-" + to ) ... )
}
}
b . ResetPreMoves ( )
b . client . out <- moveCommand
}
func ( b * Board ) GetState ( ) string {
var s = strings . Join ( b . s , ":" )
for i := range b . v {
s += ":" + strconv . Itoa ( b . v [ i ] )
}
return s
}
func ( b * Board ) SetState ( state string ) {
b . Lock ( )
b . TextView . SetRegions ( true )
b . TextView . SetDynamicColors ( true )
b . TextView . SetToggleHighlights ( true )
b . TextView . SetHighlightedFunc ( b . handleHighlight )
lastTurn := 0
if len ( b . v ) > 0 {
lastTurn = b . v [ StateTurn ]
}
b . s = strings . Split ( state , ":" )
b . v = make ( [ ] int , len ( b . s ) - 2 )
var err error
for i := 0 ; i < 46 ; i ++ {
b . v [ i ] , err = strconv . Atoi ( b . s [ i + 2 ] )
if err != nil {
log . Fatal ( err )
}
}
if b . v [ StateTurn ] != lastTurn {
if lastTurn == b . v [ StatePlayerColor ] {
b . playerDice = [ 2 ] int { 0 , 0 }
} else {
b . opponentDice = [ 2 ] int { 0 , 0 }
}
}
if b . v [ StatePlayerDice1 ] > 0 {
b . playerDice = [ 2 ] int { b . v [ StatePlayerDice1 ] , b . v [ StatePlayerDice2 ] }
}
if b . v [ StateOpponentDice1 ] > 0 {
b . opponentDice = [ 2 ] int { b . v [ StateOpponentDice1 ] , b . v [ StateOpponentDice2 ] }
}
b . Unlock ( )
b . Update ( )
return b
}
func ( b * Board ) renderSpace ( index int , spaceValue int ) [ ] byte {
var playerColor = "x"
var opponentColor = "o"
if b . v [ StatePlayerColor ] == 1 {
playerColor = "o"
opponentColor = "x"
}
var pieceColor string
value := b . v [ StateBoardSpace0 + index ]
if index == b . playerBarSpace ( ) {
value = b . v [ StatePlayerBar ]
pieceColor = playerColor
} else if index == 25 - b . playerBarSpace ( ) {
value = b . v [ StateOpponentBar ]
pieceColor = opponentColor
} else {
if value < 0 {
pieceColor = "x"
} else if value > 0 {
pieceColor = "o"
} else {
pieceColor = playerColor
}
}
abs := value
if value < 0 {
abs = value * - 1
}
top := index <= 12
if b . v [ StatePlayerColor ] == 1 {
top = ! top
}
firstDigit := 4
secondDigit := 5
if ! top {
firstDigit = 5
secondDigit = 4
}
var firstNumeral string
var secondNumeral string
if abs > 5 {
if abs > 9 {
firstNumeral = "1"
} else {
firstNumeral = strconv . Itoa ( abs )
}
if abs > 9 {
secondNumeral = strconv . Itoa ( abs - 10 )
}
if spaceValue == firstDigit && ( ! top || abs > 9 ) {
pieceColor = firstNumeral
} else if spaceValue == secondDigit && abs > 9 {
pieceColor = secondNumeral
} else if top && spaceValue == secondDigit {
pieceColor = firstNumeral
}
}
// TODO
if abs > 5 {
abs = 5
}
var r [ ] byte
foregroundColor := "#FFFFFF"
backgroundColor := "#000000"
if index != 0 && index != 25 {
if true { // default theme
if index % 2 == 0 {
backgroundColor = "#303030"
} else {
backgroundColor = "#101010"
}
} else { // rainbow
foregroundColor = "#000000"
switch index % 6 {
case 1 :
backgroundColor = "#FF0000"
case 2 :
backgroundColor = "#FFA500"
case 3 :
backgroundColor = "#FFFF00"
case 4 :
backgroundColor = "#008000"
case 5 :
backgroundColor = "#0000FF"
case 0 :
backgroundColor = "#4B0082"
}
}
}
// Highlight legal moves
highlightSpace := b . validMove ( b . selected [ 0 ] , index )
highlightSpace = false // TODO Make configurable, disable by default
//+(b.playerDice[0]*b.v[StatePlayerColor]) ||b.selected[0] == index+(b.playerDice[1]*b.v[StatePlayerColor])) && b.selected[1] > 0
if b . selected [ 1 ] > 0 && highlightSpace && index != 25 && index != 0 {
foregroundColor = "black"
backgroundColor = "yellow"
}
if abs > 0 && spaceValue <= abs {
r = [ ] byte ( pieceColor )
} else {
r = [ ] 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 ] {
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 ( ) {
r = [ ] byte ( "โพ" )
} else if index == b . playerBarSpace ( ) {
r = [ ] byte ( "โด" )
} else if rightArrowFrom {
r = [ ] byte ( "โธ" )
} else {
r = [ ] byte ( "โ" )
}
foregroundColor = "yellow"
} else if b . premoveto [ index ] > 0 && spaceValue > abs && spaceValue <= abs + ( b . premoveto [ index ] ) {
r = [ ] byte ( playerColor )
foregroundColor = "yellow"
} else if b . from [ index ] > 0 && spaceValue > abs && spaceValue <= abs + b . from [ index ] {
if rightArrowFrom {
r = [ ] byte ( "โธ" )
} else {
r = [ ] byte ( "โ" )
}
if b . movesColor == b . v [ StatePlayerColor ] {
foregroundColor = "yellow"
} else {
foregroundColor = "green"
}
} else if b . to [ index ] > 0 && spaceValue > abs - ( b . to [ index ] + b . from [ index ] ) {
if b . movesColor == b . v [ StatePlayerColor ] {
foregroundColor = "yellow"
} else {
foregroundColor = "green"
}
}
return append ( append ( [ ] byte ( fmt . Sprintf ( "[\"space-%d\"][%s:%s:b] " , index , foregroundColor , backgroundColor ) ) , r ... ) , [ ] byte ( " [-:-:-][\"\"]" ) ... )
}
func ( b * Board ) Update ( ) {
b . Lock ( )
if app != nil {
defer app . Draw ( b )
}
var white bool
if b . v [ StatePlayerColor ] == 1 {
white = true
}
var opponentName = b . s [ 1 ]
var playerName = b . s [ 0 ]
var playerColor = "x"
var opponentColor = "o"
if white {
playerColor = "o"
opponentColor = "x"
}
var t bytes . Buffer
t . WriteString ( "[\"space-off\"] [\"\"]\n" )
t . WriteString ( "[\"space-off\"] [\"\"]\n" )
t . WriteString ( "[\"space-off\"] " )
if white {
t . Write ( boardTopWhite )
} else {
t . Write ( boardTopBlack )
}
t . WriteString ( "[\"\"] " )
t . WriteByte ( '\n' )
space := func ( i int , j int ) [ ] byte {
spaceValue := i + 1
if i > 5 {
spaceValue = 5 - ( i - 6 )
}
if j == - 1 {
if i <= 4 {
return b . renderSpace ( 25 - b . playerBarSpace ( ) , spaceValue )
}
return b . renderSpace ( b . playerBarSpace ( ) , spaceValue )
}
var index int
if ! white {
if i < 6 {
j = 12 - j
} else {
j = 11 - j
}
index = 12 + j
if i > 5 {
index = 12 - j
}
} else {
index = 12 + j
if i > 5 {
index = 11 - j
}
}
if ! white {
index = 24 - index
}
index ++ // increment to get actual space number (0 is bar)
if i == 5 {
return [ ] byte ( "[-:#000000] [-:-]" )
}
return b . renderSpace ( index , spaceValue )
}
for i := 0 ; i < 11 ; i ++ {
t . Write ( [ ] byte ( "[\"space-off\"]" ) )
if i == 5 && b . v [ StateDoublingValue ] > 1 {
t . WriteString ( fmt . Sprintf ( "%2d " , b . v [ StateDoublingValue ] ) )
if b . v [ StatePlayerMayDouble ] == 1 {
t . WriteByte ( 'v' )
} else {
t . WriteByte ( '^' )
}
} else {
t . WriteByte ( ' ' )
t . WriteByte ( ' ' )
t . WriteByte ( ' ' )
t . WriteByte ( ' ' )
}
t . WriteRune ( cview . BoxDrawingsLightVertical )
t . Write ( [ ] byte ( "[\"\"]" ) )
for j := 0 ; j < 12 ; j ++ {
t . Write ( space ( i , j ) )
if j == 5 {
t . WriteRune ( cview . BoxDrawingsLightVertical )
t . Write ( space ( i , - 1 ) )
t . WriteRune ( cview . BoxDrawingsLightVertical )
}
}
t . Write ( [ ] byte ( "[\"space-off\"]" + string ( cview . BoxDrawingsLightVertical ) + " " ) )
playerRollColor := "yellow"
playerBold := "b"
opponentRollColor := "white"
opponentBold := ""
if b . v [ StateTurn ] != b . v [ StatePlayerColor ] {
playerRollColor = "white"
opponentRollColor = "green"
playerBold = ""
opponentBold = "b"
}
if i == 0 {
t . Write ( [ ] byte ( "[" + opponentRollColor + "::" + opponentBold + "]" + opponentColor + " " + opponentName + " (" + b . s [ 4 ] + ")" ) )
if b . v [ StateOpponentHome ] > 0 {
t . Write ( [ ] byte ( fmt . Sprintf ( " %d off" , b . v [ StateOpponentHome ] ) ) )
}
t . Write ( [ ] byte ( "[-::-]" ) )
} else if i == 2 {
if b . opponentDice [ 0 ] > 0 {
t . Write ( [ ] byte ( fmt . Sprintf ( " [%s::%s]%d %d[-::-] " , opponentRollColor , opponentBold , b . opponentDice [ 0 ] , b . opponentDice [ 1 ] ) ) )
} else {
t . Write ( [ ] byte ( fmt . Sprintf ( " [%s]- -[-] " , opponentRollColor ) ) )
}
} else if i == 8 {
if b . playerDice [ 0 ] > 0 {
t . Write ( [ ] byte ( fmt . Sprintf ( " [%s::%s]%d %d[-::-] " , playerRollColor , playerBold , b . playerDice [ 0 ] , b . playerDice [ 1 ] ) ) )
} else {
t . Write ( [ ] byte ( fmt . Sprintf ( " [%s]- -[-] " , playerRollColor ) ) )
}
} else if i == 10 {
t . Write ( [ ] byte ( "[" + playerRollColor + "::" + playerBold + "]" + playerColor + " " + playerName + " (" + b . s [ 3 ] + ")" ) )
if b . v [ StatePlayerHome ] > 0 {
t . Write ( [ ] byte ( fmt . Sprintf ( " %d off" , b . v [ StatePlayerHome ] ) ) )
}
t . Write ( [ ] byte ( "[-::-]" ) )
}
t . Write ( [ ] byte ( "[\"\"] " ) )
t . WriteByte ( '\n' )
}
t . WriteString ( "[\"space-off\"] " )
if white {
t . Write ( boardBottomWhite )
} else {
t . Write ( boardBottomBlack )
}
t . WriteString ( " [\"\"]\n" )
t . WriteString ( "[\"space-off\"] [\"\"]" )
b . Unlock ( )
b . TextView . SetBytes ( t . Bytes ( ) )
}
func ( b * Board ) ResetMoves ( ) {
b . moves = nil
b . movesColor = 0
b . validMoves = make ( map [ int ] [ ] int )
b . from = make ( map [ int ] int )
b . to = make ( map [ int ] int )
}
func ( b * Board ) ResetPreMoves ( ) {
b . premove = nil
b . premovefrom = make ( map [ int ] int )
b . premoveto = make ( map [ int ] int )
}
func ( b * Board ) allPlayerPiecesInHomeBoard ( ) bool {
homeBoardStart := 1
homeBoardEnd := 6
if b . v [ StateDirection ] == - 1 {
homeBoardStart = 19
homeBoardEnd = 24
}
hasPlayerPiece := func ( index int ) bool {
if index < 0 || index > 25 {
return false
}
return ( b . v [ StatePlayerColor ] == 1 && b . v [ StateBoardSpace0 + index ] > 0 ) ||
( b . v [ StatePlayerColor ] == - 1 && b . v [ StateBoardSpace0 + index ] < 0 )
}
for i := 1 ; i < 24 ; i ++ {
if i >= homeBoardStart && i <= homeBoardEnd {
continue
}
if hasPlayerPiece ( i ) {
return false
}
}
return true
}
func ( b * Board ) spaceAvailable ( index int ) bool {
if index < 0 || index > 25 {
return false
}
if index == 0 || index == 25 {
return b . allPlayerPiecesInHomeBoard ( )
}
return ( b . v [ StatePlayerColor ] == 1 && b . v [ StateBoardSpace0 + index ] >= - 1 ) ||
( b . v [ StatePlayerColor ] == - 1 && b . v [ StateBoardSpace0 + index ] <= 1 )
}
func ( b * Board ) GetValidMoves ( from int ) [ ] int {
if validMoves , ok := b . validMoves [ from ] ; ok {
return validMoves
}
var validMoves [ ] int
defer func ( ) {
b . validMoves [ from ] = validMoves
} ( )
if b . v [ StateTurn ] != b . v [ StatePlayerColor ] || b . playerDice [ 0 ] == 0 || b . playerDice [ 1 ] == 0 {
return validMoves
}
// TODO consider opponent blocking midway in full move
trySpaces := [ ] [ ] int {
{ b . playerDice [ 0 ] } ,
{ b . playerDice [ 1 ] } ,
{ b . playerDice [ 0 ] , b . playerDice [ 1 ] } ,
{ b . playerDice [ 1 ] , b . playerDice [ 0 ] } ,
}
if b . playerDice [ 0 ] == b . playerDice [ 1 ] {
trySpaces = append ( trySpaces ,
[ ] int { b . playerDice [ 0 ] , b . playerDice [ 0 ] , b . playerDice [ 0 ] } ,
[ ] int { b . playerDice [ 0 ] , b . playerDice [ 0 ] , b . playerDice [ 0 ] , b . playerDice [ 0 ] } )
}
if b . allPlayerPiecesInHomeBoard ( ) {
homeSpace := b . playerHomeSpace ( )
spacesHome := from - homeSpace
if spacesHome < 0 {
spacesHome *= - 1
}
if spacesHome <= b . playerDice [ 0 ] || spacesHome <= b . playerDice [ 1 ] {
trySpaces = append ( trySpaces , [ ] int { spacesHome } )
}
}
foundMoves := make ( map [ int ] bool )
CHECKSPACES :
for i := range trySpaces {
checkSpace := 0
for _ , space := range trySpaces [ i ] {
checkSpace += space
if ! b . spaceAvailable ( from + ( checkSpace * b . v [ StateDirection ] ) ) {
continue CHECKSPACES
}
}
space := from + ( checkSpace * b . v [ StateDirection ] )
if _ , value := foundMoves [ space ] ; ! value {
foundMoves [ space ] = true
validMoves = append ( validMoves , space )
}
}
sort . Ints ( validMoves )
return validMoves
}
func ( b * Board ) playerBarSpace ( ) int {
return 25 - b . playerHomeSpace ( )
}
func ( b * Board ) playerHomeSpace ( ) int {
if b . v [ StateDirection ] == - 1 {
return 0
}
return 25
}
func ( b * Board ) validMove ( f int , t int ) bool {
if b . v [ StateTurn ] != b . v [ StatePlayerColor ] || b . playerDice [ 0 ] == 0 || b . playerDice [ 1 ] == 0 {
return false
}
if t == b . playerHomeSpace ( ) {
// TODO bear off logic, only allow high roll
return b . allPlayerPiecesInHomeBoard ( )
}
validMoves := b . GetValidMoves ( f )
for i := range validMoves {
if validMoves [ i ] == t {
return true
}
}
return false
}
func ( b * Board ) Move ( player int , f string , t string ) {
from , err := strconv . Atoi ( f )
if err != nil {
from = SpaceUnknown
if f == "bar" {
barSpace := b . playerBarSpace ( )
if b . v [ StatePlayerColor ] == player {
from = barSpace
} else {
from = 25 - barSpace
}
}
}
to , err := strconv . Atoi ( t )
if err != nil {
to = SpaceUnknown
if t == "off" {
to = b . playerHomeSpace ( )
}
}
if from == SpaceUnknown || to == SpaceUnknown {
lf ( "error: failed to parse move: player %d, from %s, to %s" , player , f , t )
return
}
b . moves = append ( b . moves , [ 2 ] int { from , to } )
b . movesColor = player
b . from [ from ] ++
b . to [ to ] ++
b . v [ StateTurn ] = player * - 1
b . validMoves = make ( map [ int ] [ ] int )
b . ResetPreMoves ( )
}
func ( b * Board ) SimplifyMoves ( ) {
for i := range b . moves {
for j := range b . moves {
if b . moves [ i ] [ 1 ] == b . moves [ j ] [ 0 ] {
// Same to space as from space
b . moves [ j ] [ 0 ] = b . moves [ i ] [ 0 ] // Set from space to earlier from space
b . moves = append ( b . moves [ : i ] , b . moves [ i + 1 : ] ... )
b . SimplifyMoves ( )
return
} else if b . moves [ i ] [ 0 ] == b . moves [ j ] [ 1 ] {
// Same to space as from space
b . moves [ j ] [ 1 ] = b . moves [ i ] [ 1 ] // Set to space to earlier to space
b . moves = append ( b . moves [ : i ] , b . moves [ i + 1 : ] ... )
b . SimplifyMoves ( )
return
}
}
}
func ( b * GameBoard ) Update ( ) {
b . TextView . SetBytes ( b . Board . Render ( ) )
}
func ( b * Board ) addPreMove ( from int , to int ) bool {
if ! b . validMove ( from , to ) {
return false
}
b . premove = append ( b . premove , [ 2 ] int { from , to } )
b . premovefrom [ from ] ++
b . premoveto [ to ] ++
return true
func ( b * GameBoard ) resetSelection ( ) {
b . selected [ 0 ] = 0
b . selected [ 1 ] = 0
}
func ( b * Board ) handleHighlight ( added , removed , remaining [ ] string ) {
func ( b * GameBoard ) handleHighlight ( added , removed , remaining [ ] string ) {
defer b . Update ( )
v := b . Board . GetIntState ( )
if len ( added ) > 0 && len ( remaining ) > 0 {
if added [ 0 ] == "space-0" || added [ 0 ] == "space-25" {
// Deselect
@ -780,7 +71,7 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -780,7 +71,7 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
to , err := strconv . Atoi ( added [ 0 ] [ 6 : ] )
if err != nil {
if added [ 0 ] == "space-off" {
to = b . p layerHomeSpace( )
to = b . Board . P layerHomeSpace( )
} else {
return
}
@ -796,17 +87,20 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -796,17 +87,20 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
}
}
var mid = SpaceUnknown
if ( b . playerDice [ 0 ] != b . playerDice [ 1 ] && spaces * b . selected [ 1 ] == b . playerDice [ 0 ] + b . playerDice [ 1 ] ) ||
( b . playerDice [ 0 ] == b . playerDice [ 1 ] && spaces * b . selected [ 1 ] == ( b . playerDice [ 0 ] + b . playerDice [ 1 ] ) * 2 ) {
if ( v [ fibs . StatePlayerDice1 ] != v [ fibs . StatePlayerDice2 ] && spaces * b . selected [ 1 ] == v [ fibs . StatePlayerDice1 ] + v [ fibs . StatePlayerDice2 ] ) ||
( v [ fibs . StatePlayerDice1 ] == v [ fibs . StatePlayerDice2 ] && spaces * b . selected [ 1 ] == ( v [ fibs . StatePlayerDice1 ] + v [ fibs . StatePlayerDice2 ] ) * 2 ) {
// Prefer any move that will bar opponent
for i := 0 ; i < 2 ; i ++ {
dice := b . playerDice [ i ]
index := calcFrom + ( dice * b . v [ StateDirection ] )
dice := v [ fibs . StatePlayerDice1 ]
if i == 2 {
dice = v [ fibs . StatePlayerDice2 ]
}
index := calcFrom + ( dice * v [ fibs . StateDirection ] )
if index == to {
continue
}
if ( b . v [ StateBoardSpace0 + index ] == - 1 && b . v [ StatePlayerColor ] > 0 ) ||
( b . v [ StateBoardSpace0 + index ] == 1 && b . v [ StatePlayerColor ] < 0 ) {
if ( v [ fibs . StateBoardSpace0 + index ] == - 1 && v [ fibs . StatePlayerColor ] > 0 ) ||
( v [ fibs . StateBoardSpace0 + index ] == 1 && v [ fibs . StatePlayerColor ] < 0 ) {
mid = index
break
}
@ -814,13 +108,16 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -814,13 +108,16 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
if mid == SpaceUnknown {
// Send any valid move
for i := 0 ; i < 2 ; i ++ {
dice := b . playerDice [ i ]
index := calcFrom + ( dice * b . v [ StateDirection ] )
dice := v [ fibs . StatePlayerDice1 ]
if i == 2 {
dice = v [ fibs . StatePlayerDice2 ]
}
index := calcFrom + ( dice * v [ fibs . StateDirection ] )
if index == to {
continue
}
if ( b . v [ StateBoardSpace0 + index ] >= 0 && b . v [ StatePlayerColor ] > 0 ) ||
( b . v [ StateBoardSpace0 + index ] <= 0 && b . v [ StatePlayerColor ] < 0 ) {
if ( v [ fibs . StateBoardSpace0 + index ] >= 0 && v [ fibs . StatePlayerColor ] > 0 ) ||
( v [ fibs . StateBoardSpace0 + index ] <= 0 && v [ fibs . StatePlayerColor ] < 0 ) {
mid = index
break
}
@ -830,10 +127,10 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -830,10 +127,10 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
for i := 0 ; i < b . selected [ 1 ] ; i ++ {
if mid < 0 {
b . a ddPreMove( from , to )
b . Board . A ddPreMove( from , to )
} else {
b . a ddPreMove( from , mid )
b . a ddPreMove( mid , to )
b . Board . A ddPreMove( from , mid )
b . Board . A ddPreMove( mid , to )
}
}
@ -843,8 +140,6 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -843,8 +140,6 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
b . TextView . SetHighlightedFunc ( b . handleHighlight )
b . resetSelection ( )
b . autoSendMoves ( )
} else if len ( added ) > 0 {
if added [ 0 ] == "space-off" {
b . TextView . SetHighlightedFunc ( nil )
@ -853,7 +148,7 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -853,7 +148,7 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
b . resetSelection ( )
return
} else if ( added [ 0 ] == "space-0" || added [ 0 ] == "space-25" ) && b . v [ StatePlayerBar ] == 0 {
} else if ( added [ 0 ] == "space-0" || added [ 0 ] == "space-25" ) && v [ fibs . StatePlayerBar ] == 0 {
b . TextView . SetHighlightedFunc ( nil )
b . TextView . Highlight ( added [ 0 ] )
b . TextView . SetHighlightedFunc ( b . handleHighlight )
@ -864,12 +159,12 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -864,12 +159,12 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
index , err := strconv . Atoi ( added [ 0 ] [ 6 : ] )
if err == nil {
abs := b . v [ StateBoardSpace0 + index ]
abs := v [ fibs . StateBoardSpace0 + index ]
if abs < 0 {
abs *= - 1
}
if added [ 0 ] == "space-0" || added [ 0 ] == "space-25" {
abs = b . v [ StatePlayerBar ]
abs = v [ fibs . StatePlayerBar ]
}
if b . selected [ 1 ] >= abs && false { // TODO or has premove piece in space
@ -885,12 +180,12 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -885,12 +180,12 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
} else if len ( removed ) > 0 {
index , err := strconv . Atoi ( removed [ 0 ] [ 6 : ] )
if err == nil {
abs := b . v [ StateBoardSpace0 + index ]
abs := v [ fibs . StateBoardSpace0 + index ]
if abs < 0 {
abs *= - 1
}
if removed [ 0 ] == "space-0" || removed [ 0 ] == "space-25" {
abs = b . v [ StatePlayerBar ]
abs = v [ fibs . StatePlayerBar ]
}
if b . selected [ 1 ] < abs {
@ -906,7 +201,7 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
@@ -906,7 +201,7 @@ func (b *Board) handleHighlight(added, removed, remaining []string) {
}
// MouseHandler returns the mouse handler for this primitive.
func ( b * Board ) MouseHandler ( ) func ( action cview . MouseAction , event * tcell . EventMouse , setFocus func ( p cview . Primitive ) ) ( consumed bool , capture cview . Primitive ) {
func ( b * Game Board) MouseHandler ( ) func ( action cview . MouseAction , event * tcell . EventMouse , setFocus func ( p cview . Primitive ) ) ( consumed bool , capture cview . Primitive ) {
return b . WrapMouseHandler ( func ( action cview . MouseAction , event * tcell . EventMouse , setFocus func ( p cview . Primitive ) ) ( consumed bool , capture cview . Primitive ) {
x , y := event . Position ( )
if ! b . InRect ( x , y ) {