Flip spaces for player 2
This commit is contained in:
parent
2408478221
commit
138a91e57d
5 changed files with 184 additions and 45 deletions
|
@ -143,6 +143,12 @@ type Game struct {
|
|||
}
|
||||
```
|
||||
|
||||
### `failedok <reason:line>`
|
||||
|
||||
Sent after sending `ok` when there are one or more legal moves still available to the player.
|
||||
|
||||
Players must make moves using all available dice rolls before ending their turn.
|
||||
|
||||
### `say <player:text> <message:line>`
|
||||
|
||||
Chat message from another player.
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"code.rocket9labs.com/tslocum/bgammon"
|
||||
|
@ -58,10 +59,26 @@ func (g *serverGame) roll(player int) bool {
|
|||
}
|
||||
|
||||
func (g *serverGame) sendBoard(client *serverClient) {
|
||||
playerNumber := 1
|
||||
if g.client2 == client {
|
||||
playerNumber = 2
|
||||
}
|
||||
|
||||
if client.json {
|
||||
gameState := bgammon.GameState{
|
||||
Game: g.Game,
|
||||
Available: g.LegalMoves(),
|
||||
gameState := ServerGameState{
|
||||
GameState: bgammon.GameState{
|
||||
Game: g.Game,
|
||||
Available: g.LegalMoves(),
|
||||
},
|
||||
Board: g.Game.Board,
|
||||
}
|
||||
if playerNumber == 2 {
|
||||
log.Println(gameState.Board)
|
||||
log.Println(g.Game.Board)
|
||||
slices.Reverse(gameState.Board)
|
||||
|
||||
log.Println(gameState.Board)
|
||||
log.Println(g.Game.Board)
|
||||
}
|
||||
buf, err := json.Marshal(gameState)
|
||||
if err != nil {
|
||||
|
@ -71,10 +88,6 @@ func (g *serverGame) sendBoard(client *serverClient) {
|
|||
return
|
||||
}
|
||||
|
||||
playerNumber := 1
|
||||
if g.client2 == client {
|
||||
playerNumber = 2
|
||||
}
|
||||
scanner := bufio.NewScanner(bytes.NewReader(g.BoardState(playerNumber)))
|
||||
for scanner.Scan() {
|
||||
client.events <- append([]byte("notice "), scanner.Bytes()...)
|
||||
|
@ -98,9 +111,11 @@ func (g *serverGame) addClient(client *serverClient) bool {
|
|||
}
|
||||
joinMessage := []byte(fmt.Sprintf("joined %d %s %s", g.id, client.name, g.name))
|
||||
client.events <- joinMessage
|
||||
g.sendBoard(client)
|
||||
opponent := g.opponent(client)
|
||||
if opponent != nil {
|
||||
opponent.events <- joinMessage
|
||||
g.sendBoard(opponent)
|
||||
}
|
||||
}()
|
||||
switch {
|
||||
|
@ -108,16 +123,20 @@ func (g *serverGame) addClient(client *serverClient) bool {
|
|||
ok = false
|
||||
case g.client1 != nil:
|
||||
g.client2 = client
|
||||
g.Player2.Name = string(client.name)
|
||||
ok = true
|
||||
case g.client2 != nil:
|
||||
g.client1 = client
|
||||
g.Player1.Name = string(client.name)
|
||||
ok = true
|
||||
default:
|
||||
i := rand.Intn(2)
|
||||
if i == 0 {
|
||||
g.client1 = client
|
||||
g.Player1.Name = string(client.name)
|
||||
} else {
|
||||
g.client2 = client
|
||||
g.Player2.Name = string(client.name)
|
||||
}
|
||||
ok = true
|
||||
}
|
||||
|
@ -125,17 +144,34 @@ func (g *serverGame) addClient(client *serverClient) bool {
|
|||
}
|
||||
|
||||
func (g *serverGame) removeClient(client *serverClient) {
|
||||
// TODO game is considered paused when only one player is present
|
||||
// once started, only the same player may join and continue the game
|
||||
log.Println("remove client", client)
|
||||
ok := true
|
||||
defer func() {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
opponent := g.opponent(client)
|
||||
if opponent == nil {
|
||||
return
|
||||
}
|
||||
opponent.events <- []byte(fmt.Sprintf("left %d %s %s", g.id, client.name, g.name))
|
||||
if !opponent.json {
|
||||
g.sendBoard(opponent)
|
||||
}
|
||||
}()
|
||||
switch {
|
||||
case g.client1 == client:
|
||||
g.client1 = nil
|
||||
g.Player1.Name = ""
|
||||
case g.client2 == client:
|
||||
g.client2 = nil
|
||||
g.Player2.Name = ""
|
||||
default:
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
// TODO game is considered paused when only one player is present
|
||||
// once started, only the same player may join and continue the game
|
||||
log.Println("removed client", client)
|
||||
}
|
||||
|
||||
func (g *serverGame) opponent(client *serverClient) *serverClient {
|
||||
|
@ -146,3 +182,8 @@ func (g *serverGame) opponent(client *serverClient) *serverClient {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServerGameState struct {
|
||||
bgammon.GameState
|
||||
Board []int
|
||||
}
|
||||
|
|
|
@ -19,17 +19,17 @@ func main() {
|
|||
g := newServerGame(1)
|
||||
g.Board[bgammon.SpaceBarPlayer] = 3
|
||||
g.Board[bgammon.SpaceBarOpponent] = -2
|
||||
g.Roll1 = 3
|
||||
g.Roll2 = 2
|
||||
g.Turn = 1
|
||||
g.Roll1 = 1
|
||||
g.Roll2 = 3
|
||||
g.Turn = 2
|
||||
log.Println("initial legal moves")
|
||||
log.Printf("%+v", g.LegalMoves())
|
||||
|
||||
g.Moves = append(g.Moves, []int{6, 4})
|
||||
//g.Moves = append(g.Moves, []int{6, 4})
|
||||
log.Printf("Legal moves after %+v", g.Moves)
|
||||
log.Printf("%+v", g.LegalMoves())
|
||||
|
||||
playerNumber := 1
|
||||
playerNumber := 2
|
||||
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
|
|
@ -299,8 +299,6 @@ COMMANDS:
|
|||
log.Panicf("failed to add client to newly created game %+v %+v", g, cmd.client)
|
||||
}
|
||||
s.games = append(s.games, g) // TODO lock
|
||||
|
||||
g.sendBoard(cmd.client)
|
||||
case bgammon.CommandJoin, "j":
|
||||
if clientGame != nil {
|
||||
cmd.client.events <- []byte("failedjoin Please leave the game you are in before joining another game.")
|
||||
|
@ -330,10 +328,7 @@ COMMANDS:
|
|||
|
||||
if !g.addClient(cmd.client) {
|
||||
cmd.client.events <- []byte("failedjoin Game is full.")
|
||||
continue COMMANDS
|
||||
}
|
||||
|
||||
g.sendBoard(cmd.client)
|
||||
continue COMMANDS
|
||||
}
|
||||
}
|
||||
|
@ -368,19 +363,45 @@ COMMANDS:
|
|||
}
|
||||
if !clientGame.roll(playerNumber) {
|
||||
cmd.client.events <- []byte("notice It is not your turn to roll.")
|
||||
} else {
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
client.events <- []byte(fmt.Sprintf("rolled %d %d", clientGame.Roll1, clientGame.Roll2))
|
||||
})
|
||||
continue
|
||||
}
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
roll1 := 0
|
||||
roll2 := 0
|
||||
if playerNumber == 1 {
|
||||
roll1 = clientGame.Roll1
|
||||
} else {
|
||||
roll2 = clientGame.Roll2
|
||||
}
|
||||
client.events <- []byte(fmt.Sprintf("rolled %s %d %d", cmd.client.name, roll1, roll2))
|
||||
})
|
||||
if clientGame.Turn == 0 && clientGame.Roll1 != 0 && clientGame.Roll2 != 0 {
|
||||
if clientGame.Roll1 > clientGame.Roll2 {
|
||||
clientGame.Turn = 1
|
||||
} else if clientGame.Roll2 > clientGame.Roll1 {
|
||||
clientGame.Turn = 2
|
||||
} else {
|
||||
clientGame.Roll1 = 0
|
||||
clientGame.Roll2 = 0
|
||||
}
|
||||
}
|
||||
case bgammon.CommandMove, "m", "mv":
|
||||
if clientGame == nil {
|
||||
cmd.client.events <- []byte("notice You are not currently in a game.")
|
||||
cmd.client.events <- []byte("failedmove You are not currently in a game.")
|
||||
continue
|
||||
}
|
||||
|
||||
playerNumber := 1
|
||||
if clientGame.client2 == cmd.client {
|
||||
playerNumber = 2
|
||||
}
|
||||
if clientGame.Turn != playerNumber {
|
||||
cmd.client.events <- []byte("failedmove It is not your turn to move.")
|
||||
continue
|
||||
}
|
||||
|
||||
sendUsage := func() {
|
||||
cmd.client.events <- []byte("notice Specify one or more moves in the form FROM/TO. For example: 8/4 6/4")
|
||||
cmd.client.events <- []byte("failedmove Specify one or more moves in the form FROM/TO. For example: 8/4 6/4")
|
||||
}
|
||||
|
||||
if len(params) == 0 {
|
||||
|
@ -390,7 +411,6 @@ COMMANDS:
|
|||
|
||||
gameCopy := bgammon.Game{}
|
||||
gameCopy = *clientGame.Game
|
||||
gameCopy.Moves = [][]int{}
|
||||
copy(gameCopy.Moves, clientGame.Moves)
|
||||
|
||||
var moves [][]int
|
||||
|
@ -411,6 +431,9 @@ COMMANDS:
|
|||
continue COMMANDS
|
||||
}
|
||||
|
||||
originalFrom, originalTo := from, to
|
||||
from, to = bgammon.FlipSpace(from, playerNumber), bgammon.FlipSpace(to, playerNumber)
|
||||
|
||||
legalMoves := gameCopy.LegalMoves()
|
||||
var found bool
|
||||
for j := range legalMoves {
|
||||
|
@ -420,7 +443,8 @@ COMMANDS:
|
|||
}
|
||||
}
|
||||
if !found {
|
||||
cmd.client.events <- []byte(fmt.Sprintf("failedmove %d/%d Illegal move.", from, to))
|
||||
log.Printf("available legal moves: %s", bgammon.FormatMoves(legalMoves, playerNumber))
|
||||
cmd.client.events <- []byte(fmt.Sprintf("failedmove %d/%d Illegal move.", originalFrom, originalTo))
|
||||
continue COMMANDS
|
||||
}
|
||||
|
||||
|
@ -429,25 +453,48 @@ COMMANDS:
|
|||
gameCopy.Moves = append(gameCopy.Moves, move)
|
||||
}
|
||||
|
||||
paramsText := bytes.Join(params, []byte(" "))
|
||||
clientGame.Moves = gameCopy.Moves
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
client.events <- []byte(fmt.Sprintf("move %s %s", cmd.client.name, paramsText))
|
||||
clientGame.sendBoard(client)
|
||||
player := 1
|
||||
if clientGame.client2 == client {
|
||||
player = 2
|
||||
}
|
||||
client.events <- []byte(fmt.Sprintf("move %s %s", cmd.client.name, bgammon.FormatMoves(moves, player)))
|
||||
if !client.json {
|
||||
clientGame.sendBoard(client)
|
||||
}
|
||||
})
|
||||
case bgammon.CommandBoard, "b":
|
||||
case bgammon.CommandOk, "k":
|
||||
if clientGame == nil {
|
||||
cmd.client.events <- []byte("notice You are not currently in a game.")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
legalMoves := clientGame.LegalMoves()
|
||||
if len(legalMoves) != 0 {
|
||||
playerNumber := 1
|
||||
if clientGame.client2 == cmd.client {
|
||||
playerNumber = 2
|
||||
}
|
||||
cmd.client.events <- []byte(fmt.Sprintf("failedok You still have the following legal moves available: %s", bgammon.FormatMoves(legalMoves, playerNumber)))
|
||||
continue
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewReader(clientGame.BoardState(playerNumber)))
|
||||
for scanner.Scan() {
|
||||
cmd.client.events <- append([]byte("notice "), scanner.Bytes()...)
|
||||
}
|
||||
log.Println("legal to pass turn")
|
||||
case bgammon.CommandBoard, "b":
|
||||
if clientGame == nil {
|
||||
cmd.client.events <- []byte("notice You are not currently in a game.")
|
||||
continue
|
||||
}
|
||||
|
||||
playerNumber := 1
|
||||
if clientGame.client2 == cmd.client {
|
||||
playerNumber = 2
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewReader(clientGame.BoardState(playerNumber)))
|
||||
for scanner.Scan() {
|
||||
cmd.client.events <- append([]byte("notice "), scanner.Bytes()...)
|
||||
}
|
||||
case bgammon.CommandDisconnect:
|
||||
if clientGame != nil {
|
||||
|
|
61
game.go
61
game.go
|
@ -284,9 +284,13 @@ func (g *Game) BoardState(player int) []byte {
|
|||
|
||||
var playerColor = "x"
|
||||
var opponentColor = "o"
|
||||
playerRoll := g.Roll1
|
||||
opponentRoll := g.Roll2
|
||||
if white {
|
||||
playerColor = "o"
|
||||
opponentColor = "x"
|
||||
playerRoll = g.Roll2
|
||||
opponentRoll = g.Roll1
|
||||
}
|
||||
|
||||
if white {
|
||||
|
@ -365,16 +369,36 @@ func (g *Game) BoardState(player int) []byte {
|
|||
t.Write([]byte(fmt.Sprintf(" %d off", v)))
|
||||
}
|
||||
} else if i == 2 {
|
||||
if g.Turn != player && g.Roll1 > 0 {
|
||||
t.Write([]byte(fmt.Sprintf(" %d %d ", g.Roll1, g.Roll2)))
|
||||
} else {
|
||||
t.Write([]byte(fmt.Sprintf(" - - ")))
|
||||
if g.Turn == 0 {
|
||||
if g.Player1.Name != "" && g.Player2.Name != "" {
|
||||
if opponentRoll != 0 {
|
||||
t.Write([]byte(fmt.Sprintf(" %d", opponentRoll)))
|
||||
} else {
|
||||
t.Write([]byte(fmt.Sprintf(" -")))
|
||||
}
|
||||
}
|
||||
} else if g.Turn != player {
|
||||
if g.Roll1 > 0 {
|
||||
t.Write([]byte(fmt.Sprintf(" %d %d ", g.Roll1, g.Roll2)))
|
||||
} else if opponentName != "" {
|
||||
t.Write([]byte(fmt.Sprintf(" - - ")))
|
||||
}
|
||||
}
|
||||
} else if i == 8 {
|
||||
if g.Turn == player && g.Roll1 > 0 {
|
||||
t.Write([]byte(fmt.Sprintf(" %d %d ", g.Roll1, g.Roll2)))
|
||||
} else {
|
||||
t.Write([]byte(fmt.Sprintf(" - - ")))
|
||||
if g.Turn == 0 {
|
||||
if g.Player1.Name != "" && g.Player2.Name != "" {
|
||||
if playerRoll != 0 {
|
||||
t.Write([]byte(fmt.Sprintf(" %d", playerRoll)))
|
||||
} else {
|
||||
t.Write([]byte(fmt.Sprintf(" -")))
|
||||
}
|
||||
}
|
||||
} else if g.Turn == player {
|
||||
if g.Roll1 > 0 {
|
||||
t.Write([]byte(fmt.Sprintf(" %d %d ", g.Roll1, g.Roll2)))
|
||||
} else if playerName != "" {
|
||||
t.Write([]byte(fmt.Sprintf(" - - ")))
|
||||
}
|
||||
}
|
||||
} else if i == 10 {
|
||||
t.Write([]byte(playerColor + " " + playerName + " (" + playerRating + ")"))
|
||||
|
@ -437,6 +461,27 @@ func numOpponentCheckers(checkers int, player int) int {
|
|||
}
|
||||
}
|
||||
|
||||
func FlipSpace(space int, player int) int {
|
||||
if player == 1 {
|
||||
return space
|
||||
}
|
||||
if space < 1 || space > 24 {
|
||||
return space // TODO fix
|
||||
}
|
||||
return 24 - space + 1
|
||||
}
|
||||
|
||||
func FormatMoves(moves [][]int, player int) []byte {
|
||||
var out bytes.Buffer
|
||||
for i := range moves {
|
||||
if i != 0 {
|
||||
out.WriteByte(' ')
|
||||
}
|
||||
out.Write([]byte(fmt.Sprintf("%d/%d", FlipSpace(moves[i][0], player), FlipSpace(moves[i][1], player))))
|
||||
}
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
const (
|
||||
VerticalBar rune = '\u2502' // │
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue