Suport undoing moves
This commit is contained in:
parent
0df16bc71a
commit
45b2d00e09
2 changed files with 125 additions and 39 deletions
|
@ -462,10 +462,6 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
gameCopy := bgammon.Game{}
|
||||
gameCopy = *clientGame.Game
|
||||
copy(gameCopy.Moves, clientGame.Moves)
|
||||
|
||||
var moves [][]int
|
||||
for i := range params {
|
||||
split := bytes.Split(params[i], []byte("/"))
|
||||
|
@ -488,31 +484,10 @@ COMMANDS:
|
|||
from, to = bgammon.FlipSpace(from, cmd.client.playerNumber), bgammon.FlipSpace(to, cmd.client.playerNumber)
|
||||
log.Printf("translated player %d %d-%d as %d-%d", cmd.client.playerNumber, originalFrom, originalTo, from, to)
|
||||
|
||||
legalMoves := gameCopy.LegalMoves()
|
||||
var found bool
|
||||
for j := range legalMoves {
|
||||
if legalMoves[j][0] == from && legalMoves[j][1] == to {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Printf("available legal moves: %s", bgammon.FormatMoves(legalMoves, cmd.client.playerNumber))
|
||||
cmd.client.sendEvent(&bgammon.EventFailedMove{
|
||||
From: originalFrom,
|
||||
To: originalTo,
|
||||
Reason: "Illegal move.",
|
||||
})
|
||||
continue COMMANDS
|
||||
}
|
||||
|
||||
move := []int{from, to}
|
||||
moves = append(moves, move)
|
||||
gameCopy.Moves = append(gameCopy.Moves, move)
|
||||
moves = append(moves, []int{from, to})
|
||||
}
|
||||
|
||||
if !clientGame.AddMoves(moves) {
|
||||
log.Panicf("FAILED TO ADD MOVES")
|
||||
cmd.client.sendEvent(&bgammon.EventFailedMove{
|
||||
From: 0,
|
||||
To: 0,
|
||||
|
@ -526,6 +501,36 @@ COMMANDS:
|
|||
})
|
||||
clientGame.sendBoard(client)
|
||||
})
|
||||
case bgammon.CommandReset:
|
||||
if clientGame == nil {
|
||||
cmd.client.sendNotice("You are not currently in a game.")
|
||||
continue
|
||||
}
|
||||
|
||||
if clientGame.Turn != cmd.client.playerNumber {
|
||||
cmd.client.sendNotice("It is not your turn.")
|
||||
continue
|
||||
}
|
||||
|
||||
if len(clientGame.Moves) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
l := len(clientGame.Moves)
|
||||
undoMoves := make([][]int, l)
|
||||
for i, move := range clientGame.Moves {
|
||||
undoMoves[l-1-i] = []int{move[1], move[0]}
|
||||
}
|
||||
if !clientGame.AddMoves(undoMoves) {
|
||||
cmd.client.sendNotice("Failed to undo move: invalid move.")
|
||||
} else {
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
client.sendEvent(&bgammon.EventMoved{
|
||||
Moves: bgammon.FlipMoves(undoMoves, client.playerNumber),
|
||||
})
|
||||
clientGame.sendBoard(client)
|
||||
})
|
||||
}
|
||||
case bgammon.CommandOk, "k":
|
||||
if clientGame == nil {
|
||||
cmd.client.sendNotice("You are not currently in a game.")
|
||||
|
|
107
game.go
107
game.go
|
@ -21,6 +21,8 @@ type Game struct {
|
|||
Roll1 int
|
||||
Roll2 int
|
||||
Moves [][]int // Pending moves.
|
||||
|
||||
boardStates [][]int // One board state for each move to allow undoing a move.
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
|
@ -83,33 +85,112 @@ func (g *Game) iterateSpaces(from int, to int, f func(space int, spaceCount int)
|
|||
}
|
||||
}
|
||||
|
||||
// AddMoves adds moves to the game state. Adding a backwards move will remove the equivalent existing move.
|
||||
func (g *Game) AddMoves(moves [][]int) bool {
|
||||
original := make([]int, len(g.Board))
|
||||
copy(original, g.Board)
|
||||
ADDMOVES:
|
||||
log.Printf("ADD MOVES - %+v", moves)
|
||||
|
||||
delta := 1
|
||||
if g.Turn == 2 {
|
||||
delta = -1
|
||||
}
|
||||
|
||||
var addMoves [][]int
|
||||
var undoMoves [][]int
|
||||
|
||||
newBoard := make([]int, len(g.Board))
|
||||
var boardStates [][]int
|
||||
copy(newBoard, g.Board)
|
||||
validateOffset := 0
|
||||
VALIDATEMOVES:
|
||||
for _, move := range moves {
|
||||
l := g.LegalMoves()
|
||||
for _, lm := range l {
|
||||
if lm[0] == move[0] && lm[1] == move[1] {
|
||||
addMoves = append(addMoves, []int{move[0], move[1]})
|
||||
continue VALIDATEMOVES
|
||||
}
|
||||
}
|
||||
if len(g.Moves) > 0 {
|
||||
i := len(g.Moves) - 1 - validateOffset
|
||||
if i < 0 {
|
||||
log.Printf("FAILED MOVE %d/%d", move[0], move[1])
|
||||
return false
|
||||
}
|
||||
gameMove := g.Moves[i]
|
||||
if move[0] == gameMove[1] && move[1] == gameMove[0] {
|
||||
undoMoves = append(undoMoves, []int{gameMove[1], gameMove[0]})
|
||||
validateOffset++
|
||||
continue VALIDATEMOVES
|
||||
}
|
||||
}
|
||||
log.Printf("FAILED MOVE %d/%d", move[0], move[1])
|
||||
return false
|
||||
}
|
||||
|
||||
if len(addMoves) != 0 && len(undoMoves) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
ADDMOVES:
|
||||
for _, move := range addMoves {
|
||||
l := g.LegalMoves()
|
||||
for _, lm := range l {
|
||||
if lm[0] == move[0] && lm[1] == move[1] {
|
||||
log.Printf("ADD MOV %d/%d", lm[0], lm[1])
|
||||
delta := 1
|
||||
if g.Turn == 2 {
|
||||
delta = -1
|
||||
}
|
||||
g.Board[lm[0]] -= delta
|
||||
opponentCheckers := OpponentCheckers(g.Board[lm[1]], g.Turn)
|
||||
|
||||
boardState := make([]int, len(newBoard))
|
||||
copy(boardState, newBoard)
|
||||
boardStates = append(boardStates, boardState)
|
||||
|
||||
newBoard[move[0]] -= delta
|
||||
opponentCheckers := OpponentCheckers(newBoard[lm[1]], g.Turn)
|
||||
if opponentCheckers == 1 {
|
||||
g.Board[lm[1]] = delta
|
||||
newBoard[move[1]] = delta
|
||||
} else {
|
||||
g.Board[lm[1]] += delta
|
||||
newBoard[move[1]] += delta
|
||||
}
|
||||
continue ADDMOVES
|
||||
}
|
||||
}
|
||||
g.Board = original
|
||||
}
|
||||
if len(addMoves) != 0 {
|
||||
g.Moves = append(g.Moves, moves...)
|
||||
g.boardStates = append(g.boardStates, boardStates...)
|
||||
}
|
||||
|
||||
newMoves := make([][]int, len(g.Moves))
|
||||
copy(newMoves, g.Moves)
|
||||
newBoardStates := make([][]int, len(g.boardStates))
|
||||
copy(newBoardStates, g.boardStates)
|
||||
for _, move := range undoMoves {
|
||||
log.Printf("TRY UNDO MOV %d/%d %+v", move[0], move[1], newMoves)
|
||||
if len(g.Moves) > 0 {
|
||||
i := len(newMoves) - 1
|
||||
if i < 0 {
|
||||
log.Printf("FAILED UNDO MOVE %d/%d", move[0], move[1])
|
||||
return false
|
||||
}
|
||||
gameMove := newMoves[i]
|
||||
if move[0] == gameMove[1] && move[1] == gameMove[0] {
|
||||
log.Printf("UNDO MOV %d/%d", gameMove[0], gameMove[1])
|
||||
|
||||
copy(newBoard, g.boardStates[i])
|
||||
newMoves = g.Moves[:i]
|
||||
newBoardStates = g.boardStates[:i]
|
||||
log.Printf("NEW MOVES %+v", newMoves)
|
||||
continue
|
||||
}
|
||||
log.Printf("COMPARE MOV %d/%d %d/%d", gameMove[0], gameMove[1], move[0], move[1])
|
||||
}
|
||||
log.Printf("FAILED UNDO MOVE %d/%d", move[0], move[1])
|
||||
return false
|
||||
}
|
||||
g.Moves = append(g.Moves, moves...)
|
||||
if len(undoMoves) != 0 {
|
||||
g.Moves = newMoves
|
||||
g.boardStates = newBoardStates
|
||||
}
|
||||
|
||||
g.Board = newBoard
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue