Files
games/game/logic.go
Ryan Hamamura afd8a3e9d0
Some checks failed
CI / Deploy / test (pull_request) Successful in 8s
CI / Deploy / lint (pull_request) Failing after 44s
CI / Deploy / deploy (pull_request) Has been skipped
fix: resolve all linting errors and add SSE compression
- Add brotli compression (level 5) to long-lived SSE event streams
  (HandleGameEvents, HandleSnakeEvents) to reduce wire payload
- Fix all errcheck violations with nolint annotations for best-effort calls
- Fix goimports: separate stdlib, third-party, and local import groups
- Fix staticcheck: add package comments, use tagged switch
- Zero lint issues remaining
2026-03-02 12:38:21 -10:00

99 lines
2.2 KiB
Go

// Package game implements Connect 4 game logic, state management, and persistence.
package game
// DropPiece attempts to drop a piece in the given column.
// Returns (row placed, success).
func (g *Game) DropPiece(col, playerColor int) (int, bool) {
if col < 0 || col > 6 {
return -1, false
}
if g.CurrentTurn != playerColor {
return -1, false
}
if g.Status != StatusInProgress {
return -1, false
}
// Find lowest empty row in column
for row := 5; row >= 0; row-- {
if g.Board[row][col] == 0 {
g.Board[row][col] = playerColor
return row, true
}
}
return -1, false // Column full
}
// CheckWin checks if the last move at (row, col) created a win.
func (g *Game) CheckWin(row, col int) bool {
color := g.Board[row][col]
directions := [][2]int{
{0, 1}, // Horizontal
{1, 0}, // Vertical
{1, 1}, // Diagonal down-right
{1, -1}, // Diagonal down-left
}
for _, dir := range directions {
cells := g.countLine(row, col, dir[0], dir[1], color)
if len(cells) >= 4 {
g.Status = StatusWon
g.WinningCells = cells[:4]
return true
}
}
return false
}
func (g *Game) countLine(row, col, dr, dc, color int) [][2]int {
cells := [][2]int{{row, col}}
// Count in positive direction
for r, c := row+dr, col+dc; r >= 0 && r < 6 && c >= 0 && c < 7; r, c = r+dr, c+dc {
if g.Board[r][c] != color {
break
}
cells = append(cells, [2]int{r, c})
}
// Count in negative direction
for r, c := row-dr, col-dc; r >= 0 && r < 6 && c >= 0 && c < 7; r, c = r-dr, c-dc {
if g.Board[r][c] != color {
break
}
cells = append(cells, [2]int{r, c})
}
return cells
}
// CheckDraw checks if board is full with no winner.
func (g *Game) CheckDraw() bool {
for col := 0; col < 7; col++ {
if g.Board[0][col] == 0 {
return false
}
}
g.Status = StatusDraw
return true
}
// SwitchTurn alternates the current turn.
func (g *Game) SwitchTurn() {
if g.CurrentTurn == 1 {
g.CurrentTurn = 2
} else {
g.CurrentTurn = 1
}
}
// IsWinningCell checks if a cell is part of the winning line.
func (g *Game) IsWinningCell(row, col int) bool {
for _, cell := range g.WinningCells {
if cell[0] == row && cell[1] == col {
return true
}
}
return false
}