diff --git a/game/pieces.go b/game/pieces.go index 2f122c5..ffce58e 100644 --- a/game/pieces.go +++ b/game/pieces.go @@ -6,7 +6,7 @@ import ( "math" ) -const SIZE_CELL float32 = 75.0 //length of single square cell +const SIZE_CELL = 75.0 // length of single square cell type Vec2 struct { X float32 // x position @@ -24,15 +24,15 @@ type Piece struct { Id int32 // unique piece id IsKing bool // whether this piece is King Pos Vec2 // current piece position - PieceColor PieceType // either red or black + PieceColor PieceType // either RED or BLACK } -// MoveSimple actually moves this piece diagonally to given `destPos` by 1 cell. Returns TRUE if successful -func (p *Piece) MoveSimple(destPos *Vec2) bool { - var deltaX = float64(destPos.X - p.Pos.X) - var deltaY = float64(destPos.Y - p.Pos.Y) +// MoveSimple actually moves this piece diagonally to given destination by 1 cell. Returns TRUE if successful +func (p *Piece) MoveSimple(dest *Vec2) bool { + var deltaX = float64(dest.X - p.Pos.X) + var deltaY = float64(dest.Y - p.Pos.Y) - if math.Abs(deltaX) != float64(SIZE_CELL) || math.Abs(deltaY) != float64(SIZE_CELL) { + if math.Abs(deltaX) != SIZE_CELL || math.Abs(deltaY) != SIZE_CELL { return false } if p.PieceColor == Piece_Red && deltaY > 0 && !p.IsKing { @@ -42,21 +42,21 @@ func (p *Piece) MoveSimple(destPos *Vec2) bool { return false } - p.Pos.X = destPos.X - p.Pos.Y = destPos.Y - if (p.PieceColor == Piece_Red && destPos.Y == 0) || - (p.PieceColor == Piece_Black && destPos.Y == 7*SIZE_CELL) { + p.Pos.X = dest.X + p.Pos.Y = dest.Y + if (p.PieceColor == Piece_Red && dest.Y == 0) || + (p.PieceColor == Piece_Black && dest.Y == 7*SIZE_CELL) { p.IsKing = true } return true } -// MoveCapture actually moves this piece by 2 cells diagonally to the given `destPos`. Returns TRUE if success -func (p *Piece) MoveCapture(destPos *Vec2) bool { - var deltaX = float64(destPos.X - p.Pos.X) - var deltaY = float64(destPos.Y - p.Pos.Y) +// MoveCapture (when attacking) moves this piece by 2 cells diagonally to the given `destination`. Returns TRUE if success +func (p *Piece) MoveCapture(dest *Vec2) bool { + var deltaX = float64(dest.X - p.Pos.X) + var deltaY = float64(dest.Y - p.Pos.Y) - if math.Abs(deltaX) != float64(2*SIZE_CELL) || math.Abs(deltaY) != float64(2*SIZE_CELL) { + if math.Abs(deltaX) != 2*SIZE_CELL || math.Abs(deltaY) != 2*SIZE_CELL { return false } if p.PieceColor == Piece_Red && deltaY > 0 && !p.IsKing { @@ -66,16 +66,16 @@ func (p *Piece) MoveCapture(destPos *Vec2) bool { return false } - p.Pos.X = destPos.X - p.Pos.Y = destPos.Y - if (p.PieceColor == Piece_Red && destPos.Y == 0) || - (p.PieceColor == Piece_Black && destPos.Y == 7*SIZE_CELL) { + p.Pos.X = dest.X + p.Pos.Y = dest.Y + if (p.PieceColor == Piece_Red && dest.Y == 0) || + (p.PieceColor == Piece_Black && dest.Y == 7*SIZE_CELL) { p.IsKing = true } return true } -// IsEvenCellRow determines whether given `cellIdx` is on even Row on the board +// IsEvenCellRow determines whether the CELL with given Index is on EVEN Row on the board func IsEvenCellRow(cellIdx int32) bool { rowNumber := 9 - (cellIdx-1)/4 return rowNumber%2 == 0 @@ -86,10 +86,10 @@ func IsAwayFromEdge(pos *Vec2) bool { return pos.X > 0 && pos.X < 7*SIZE_CELL && pos.Y > 0 && pos.Y < 7*SIZE_CELL } -// HasWinner determines if `p` has won the match against `opponent`, then notifies both players if TRUE. +// HasWinner returns TRUE if `p` has won the match against `opponent`, then notifies both players. func HasWinner(p *player.Player, opponent *player.Player) bool { if len(opponent.Pieces) == 0 { - //`opponent` has lost, `p` has won! game over + // Meaning `opponent` has lost, `p` has won! Game over p.SendMessage(&BasePayload{ Notice: "Congrats! You won! GAME OVER", Inner: &BasePayload_WinlosePayload{ diff --git a/main.go b/main.go index 5001e55..e5882d6 100644 --- a/main.go +++ b/main.go @@ -16,11 +16,11 @@ import ( "golang.org/x/net/websocket" ) -const SERVER_VERSION = "1.0.8" -const maxRequestSize int = 1 << 10 //1KB +const SERVER_VERSION = "1.0.9" +const maxRequestSize int = 1 << 10 // 1KB var numPlayers atomic.Uint32 // total number of LIVE players -var lobby = make(chan *player.Player, 2) // waiting room for players +var lobby = make(chan *player.Player, 1) // waiting room for players func main() { portNum, err := strconv.Atoi(os.Getenv("PORT")) @@ -30,13 +30,13 @@ func main() { port := strconv.Itoa(portNum) http.HandleFunc("/", func(writer http.ResponseWriter, r *http.Request) { - fmt.Fprintf(writer, `

This is a socket server. Dial ws://%s:%s/game

`, r.URL.Host, port) + fmt.Fprintf(writer, `

This is a websocket server. Dial ws://%s:%s/game

`, r.RemoteAddr, port) }) http.Handle("/game", websocket.Handler(wsHandler)) go listenForJoins() - log.Println("Server listening at http://localhost:" + port) + log.Println("Server listening at http://127.0.0.1:" + port) log.Fatal(http.ListenAndServe(":"+port, nil)) } diff --git a/player/member.go b/player/member.go index 806570e..2ff0e22 100644 --- a/player/member.go +++ b/player/member.go @@ -14,11 +14,11 @@ type Player struct { Conn *websocket.Conn // client's WS connection Name string // Name can only be RED or BLACK Pieces []int32 // pieces IDs owned by this player. Max size 12 - Dead chan<- bool // to signal this player was kicked out or left AFTER match starts - Quit <-chan bool // to detect player has quit BEFORE match starts + Dead chan<- bool // to SEND signal this player left AFTER match starts + Quit <-chan bool // to RECEIVE signal this player has quit BEFORE match starts } -// pingCodec is used to send Ping msg to client +// pingCodec is used to send PING to client var pingCodec = websocket.Codec{Marshal: func(v interface{}) (data []byte, payloadType byte, err error) { return nil, websocket.PingFrame, nil }} diff --git a/room/capture_validator.go b/room/capture_validator.go index 938b883..278bfbe 100644 --- a/room/capture_validator.go +++ b/room/capture_validator.go @@ -58,7 +58,7 @@ func validateCapture(captureReq *game.CapturePayload, gameMap map[int32]*game.Pi return false } - //check if destCell already has a Piece or not + // check whether destCell already has a Piece destCell := captureReq.GetDestination() _, hasValue := gameMap[destCell.GetCellIndex()] if hasValue { diff --git a/room/enemy_detect.go b/room/enemy_detect.go index 1d19517..4fc584f 100644 --- a/room/enemy_detect.go +++ b/room/enemy_detect.go @@ -6,7 +6,7 @@ import ( ) // hasExtraTargets returns TRUE if hunter's single Piece at `currCell` has EXTRA nearby targets to capture. -// This should be called only AFTER `handleCapture` by player `hunter` was successful +// This should be called only AFTER `handleCapture` by player `hunter` is TRUE func hasExtraTargets(hunter *player.Player, currCell int32, gameMap map[int32]*game.Piece) bool { piecePtr, exists := gameMap[currCell] if !exists || !hunter.HasThisPiece(piecePtr.Id) { @@ -25,7 +25,7 @@ func hasExtraTargets(hunter *player.Player, currCell int32, gameMap map[int32]*g return false } -// collectFrontLHS returns true ONLY IF there is an enemy on NorthWest of player `p` at currCell +// collectFrontLHS returns true ONLY IF there is an enemy on NorthWest of player `p` at `cellIdx` func collectFrontLHS(p *player.Player, cellIdx int32, gameMap map[int32]*game.Piece) bool { piecePtr := gameMap[cellIdx] //check LHS (north west) @@ -39,14 +39,15 @@ func collectFrontLHS(p *player.Player, cellIdx int32, gameMap map[int32]*game.Pi var deltaBehindEnemy int32 = 4 var hasEnemyAhead = false - var enemyOpenBehind = false // does enemy piece have EMPTY cell behind it? + var enemyOpenBehind = false // have EMPTY cell behind enemy? if game.IsEvenCellRow(cellIdx) { + // do swap deltaForward, deltaBehindEnemy = deltaBehindEnemy, deltaForward } var mSign int32 = +1 // direction. up +1, down -1 - // if player piece is Black (PLAYER 2) + // if player piece is Black (PLAYER 2), swap values if p.Name == game.TeamColor_TEAM_BLACK.String() { mSign = -1 deltaBehindEnemy, deltaForward = deltaForward, deltaBehindEnemy @@ -56,13 +57,13 @@ func collectFrontLHS(p *player.Player, cellIdx int32, gameMap map[int32]*game.Pi return false } - pieceAhead, existFront := gameMap[cellAheadIdx] // north west (of hunter) + pieceAhead, existFront := gameMap[cellAheadIdx] // north-west (of hunter) hasEnemyAhead = existFront && !p.HasThisPiece(pieceAhead.Id) if existFront && !game.IsAwayFromEdge(&pieceAhead.Pos) { return false } - cellBehindEnemy := cellIdx + (deltaBehindEnemy * mSign) + (deltaForward * mSign) // south east (of enemy) + cellBehindEnemy := cellIdx + (deltaBehindEnemy * mSign) + (deltaForward * mSign) // south-east (of enemy) if cellBehindEnemy > 32 || cellBehindEnemy < 1 { return false } @@ -72,7 +73,7 @@ func collectFrontLHS(p *player.Player, cellIdx int32, gameMap map[int32]*game.Pi return hasEnemyAhead && enemyOpenBehind } -// collectFrontRHS returns true ONLY IF there is an enemy on NorthEast of this player `p` at currCell +// collectFrontRHS returns true ONLY IF there is an enemy on NorthEast of this player `p` at `cellIdx` func collectFrontRHS(p *player.Player, cellIdx int32, gameMap map[int32]*game.Piece) bool { piecePtr := gameMap[cellIdx] if p.Name == game.TeamColor_TEAM_RED.String() && piecePtr.Pos.X >= 7*game.SIZE_CELL { @@ -85,14 +86,15 @@ func collectFrontRHS(p *player.Player, cellIdx int32, gameMap map[int32]*game.Pi var deltaBehindEnemy int32 = 3 var hasEnemyAhead = false - var enemyOpenBehind = false //is there an EMPTY cell behind enemy? + var enemyOpenBehind = false // is there an EMPTY cell behind enemy? if game.IsEvenCellRow(cellIdx) { + //do swap deltaBehindEnemy, deltaForward = deltaForward, deltaBehindEnemy } var mSign int32 = +1 // direction. up +1, down -1 - // if piece is Black (PLAYER 2) + // if piece is Black (PLAYER 2), swap values if p.Name == game.TeamColor_TEAM_BLACK.String() { mSign = -1 deltaBehindEnemy, deltaForward = deltaForward, deltaBehindEnemy @@ -102,13 +104,13 @@ func collectFrontRHS(p *player.Player, cellIdx int32, gameMap map[int32]*game.Pi return false } - pieceAhead, existFront := gameMap[cellAheadIdx] // north east + pieceAhead, existFront := gameMap[cellAheadIdx] // north-east hasEnemyAhead = existFront && !p.HasThisPiece(pieceAhead.Id) if existFront && !game.IsAwayFromEdge(&pieceAhead.Pos) { return false } - cellBehindEnemy := cellIdx + (deltaBehindEnemy * mSign) + (deltaForward * mSign) // south west (of enemy) + cellBehindEnemy := cellIdx + (deltaBehindEnemy * mSign) + (deltaForward * mSign) // south-west (of enemy) if cellBehindEnemy > 32 || cellBehindEnemy < 1 { return false } @@ -138,7 +140,7 @@ func collectBehindRHS(king *player.Player, cellIdx int32, gameMap map[int32]*gam } var mSign int32 = +1 // direction - // if player piece is Black (PLAYER 2) + // if player piece is Black (PLAYER 2), swap values if king.Name == game.TeamColor_TEAM_BLACK.String() { mSign = -1 deltaForward, deltaBehindEnemy = deltaBehindEnemy, deltaForward @@ -148,13 +150,13 @@ func collectBehindRHS(king *player.Player, cellIdx int32, gameMap map[int32]*gam return false } - pieceAhead, existFront := gameMap[cellAheadIdx] // north west (opposite direction) + pieceAhead, existFront := gameMap[cellAheadIdx] // north-west (from behind) hasEnemyAhead = existFront && !king.HasThisPiece(pieceAhead.Id) if existFront && !game.IsAwayFromEdge(&pieceAhead.Pos) { return false } - cellBehindEnemy := cellIdx - (deltaBehindEnemy * mSign) - (deltaForward * mSign) // south east (of enemy) + cellBehindEnemy := cellIdx - (deltaBehindEnemy * mSign) - (deltaForward * mSign) // south-east (of enemy) if cellBehindEnemy > 32 || cellBehindEnemy < 1 { return false } @@ -177,14 +179,14 @@ func collectBehindLHS(king *player.Player, cellIdx int32, gameMap map[int32]*gam var deltaBehindEnemy int32 = 4 var hasEnemyAhead = false - var enemyOpenBehind = false //is there an EMPTY cell behind enemy? + var enemyOpenBehind = false // have EMPTY cell behind enemy? if game.IsEvenCellRow(cellIdx) { deltaForward, deltaBehindEnemy = deltaBehindEnemy, deltaForward } - var mSign int32 = +1 // direction + var mSign int32 = +1 // direction. +1 forward, -1 back - // if player piece is Black (PLAYER 2) + // if player piece is Black (PLAYER 2), do swap if king.Name == game.TeamColor_TEAM_BLACK.String() { mSign = -1 deltaForward, deltaBehindEnemy = deltaBehindEnemy, deltaForward @@ -194,13 +196,13 @@ func collectBehindLHS(king *player.Player, cellIdx int32, gameMap map[int32]*gam return false } - pieceAhead, existFront := gameMap[cellAheadIdx] // north east (opposite direction) + pieceAhead, existFront := gameMap[cellAheadIdx] // north-east (from behind) hasEnemyAhead = existFront && !king.HasThisPiece(pieceAhead.Id) if existFront && !game.IsAwayFromEdge(&pieceAhead.Pos) { return false } - cellBehindEnemy := cellIdx - (deltaBehindEnemy * mSign) - (deltaForward * mSign) // south west of enemy + cellBehindEnemy := cellIdx - (deltaBehindEnemy * mSign) - (deltaForward * mSign) // south-west of enemy if cellBehindEnemy > 32 || cellBehindEnemy < 1 { return false } diff --git a/room/generator.go b/room/generator.go index 27e944f..d08d8c0 100644 --- a/room/generator.go +++ b/room/generator.go @@ -21,7 +21,7 @@ func generateGameMap(p1 *player.Player, p2 *player.Player) map[int32]*game.Piece var iterRed = 0 //red pieces iterator var iterBlack = 0 //black pieces iterator - // create pieces, and position them on checkerboard (in reverse) + // create pieces, and position them on checkerboard (from top -> down) for row := 0; row < numRows; row++ { for col := 0; col < numCols; col++ { if (row+col)%2 != 0 { diff --git a/room/move_validator.go b/room/move_validator.go index ffed4ee..e70081e 100644 --- a/room/move_validator.go +++ b/room/move_validator.go @@ -27,7 +27,7 @@ func processMovePiece(payload *game.BasePayload, gameMap map[int32]*game.Piece, }) return false } - //Else, forward the "MOVE" payload to opponent + // All is OK, forward the "MOVE" payload to opponent opponent.SendMessage(payload) return true } @@ -46,7 +46,7 @@ func validateAndUpdateMap(payload *game.MovePayload, gameMap map[int32]*game.Pie return false } - //check if destCell already has a Piece or not + // check whether destCell already has a Piece _, hasValue := gameMap[destination.CellIndex] if hasValue { return false diff --git a/room/room.go b/room/room.go index ce0ec98..7eeb233 100644 --- a/room/room.go +++ b/room/room.go @@ -40,6 +40,11 @@ func RunMatch(p1 *player.Player, p2 *player.Player, gameOver chan<- bool) { var isPlayerRedTurn = true // Who turn is it now? RED always starts. var gameMap = generateGameMap(p1, p2) // map of cell index --> pieces. + // free used memory after match ends + defer func() { + clear(gameMap) + }() + //START GAME MAIN LOOP for { if isPlayerRedTurn { @@ -90,10 +95,10 @@ func RunMatch(p1 *player.Player, p2 *player.Player, gameOver chan<- bool) { gameOver <- true return } - //check for extra opportunities for P1. if NONE, toggle turns isKingNow := getKingStatusAfter(payload.GetCapturePayload(), gameMap) currentCell := payload.GetCapturePayload().Destination.CellIndex var needCheck bool = isKingBefore == isKingNow + // CHECK for extra opportunities for P1. if NONE, toggle turns if needCheck && hasExtraTargets(p1, currentCell, gameMap) { log.Println(p1.Name, " have extra targets!") continue