Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ sshOurboros -- multiplayer game where snake eats itself and grows
*To play go here `ssh web2u.org -p6996`*

*The Rules:*

1. The goal is to claim the most space
2. Secondary goal is to kill as many other snakes as you can

*The how:*

1. To claim space you need to either eat your own tail or reach tiles you've already claimed,
tiles that are enclosed when you do so become yours!
2. To kill other snakes you hit their tails
3. To speed up press arrow of the same direction you going toward mulitple times
4. To slow down either press "space" or the opposite direction to gradually slow down

*To watchout:*

1. Other players can kill you
2. Other players can take your tiles.

Expand Down
118 changes: 65 additions & 53 deletions internal/game/GameManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,80 +135,92 @@ func (gm *GameManager) processGameTick() {
return true
}

nextTile := player.GetNextTile()
if IsWall(nextTile.Y, nextTile.X) {
player.isDead = true
gm.PlayerManager.SunsetPlayersChannel <- player
return true
}
if player.Speed < 0 {
if player.ticksSkippedCount < player.Speed*-1 {
// we are skipping this tick because we are slow
player.ticksSkippedCount += 1
return true
}

player.isSafe = false
player.ticksSkippedCount = 0
}

if nextTile.OwnerColor != nil && nextTile.OwnerColor != player.Color {
nextTileOwnerAny, _ := gm.Players.Load(*nextTile.OwnerColor)
if nextTileOwnerAny == nil {
nextTiles := player.GetNextTiles()
for _, nextTile := range nextTiles {
if IsWall(nextTile.Y, nextTile.X) {
player.isDead = true
gm.PlayerManager.SunsetPlayersChannel <- player
return true
}

nextTileOwner := nextTileOwnerAny.(*Player)
if nextTileOwner.isDead || nextTileOwner.isSafe {
return true
player.isSafe = false

if nextTile.OwnerColor != nil && nextTile.OwnerColor != player.Color {
nextTileOwnerAny, _ := gm.Players.Load(*nextTile.OwnerColor)
if nextTileOwnerAny == nil {
return true
}

nextTileOwner := nextTileOwnerAny.(*Player)
if nextTileOwner.isDead || nextTileOwner.isSafe {
return true
}

if nextTileOwner.Location == nextTile {
nextTileOwner.isDead = true
player.isDead = true
player.Kills += 1
nextTileOwner.Kills += 1

gm.PlayerManager.SunsetPlayersChannel <- nextTileOwner
gm.PlayerManager.SunsetPlayersChannel <- player
return true
}

if nextTile.IsTail {
nextTileOwner.isDead = true
gm.PlayerManager.SunsetPlayersChannel <- nextTileOwner

player.Kills += 1
nextTile.OwnerColor = player.Color
nextTile.IsTail = true
player.Tail.tailLock.Lock()
player.Tail.tailTiles = append(player.Tail.tailTiles, nextTile)
player.Tail.tailLock.Unlock()

player.Location = nextTile

return true
}

}

if nextTileOwner.Location == nextTile {
nextTileOwner.isDead = true
player.isDead = true
player.Kills += 1
nextTileOwner.Kills += 1
if nextTile.OwnerColor == player.Color && len(player.Tail.tailTiles) > 0 {
select {
case gm.SpaceFillerService.SpaceFillerChan <- player:
// Successfully sent direction
default:
gm.SpaceFillerService = getNewSpaceFiller(gm.GameMap)
log.Printf("space fill channel is full")
}

gm.PlayerManager.SunsetPlayersChannel <- nextTileOwner
gm.PlayerManager.SunsetPlayersChannel <- player
player.Location = nextTile
player.isSafe = true
return true
}

if nextTile.IsTail {
nextTileOwner.isDead = true
gm.PlayerManager.SunsetPlayersChannel <- nextTileOwner

player.Kills += 1
if nextTile.OwnerColor != player.Color {
nextTile.OwnerColor = player.Color
nextTile.IsTail = true
nextTile.Direction = player.CurrentDirection
player.Tail.tailLock.Lock()
player.Tail.tailTiles = append(player.Tail.tailTiles, nextTile)
player.Tail.tailLock.Unlock()

player.Location = nextTile

return true
}

}

if nextTile.OwnerColor == player.Color && len(player.Tail.tailTiles) > 0 {
select {
case gm.SpaceFillerService.SpaceFillerChan <- player:
// Successfully sent direction
default:
gm.SpaceFillerService = getNewSpaceFiller(gm.GameMap)
log.Printf("space fill channel is full")
}

player.Location = nextTile
player.isSafe = true
return true
}

if nextTile.OwnerColor != player.Color {
nextTile.OwnerColor = player.Color
nextTile.IsTail = true
nextTile.Direction = player.CurrentDirection
player.Tail.tailLock.Lock()
player.Tail.tailTiles = append(player.Tail.tailTiles, nextTile)
player.Tail.tailLock.Unlock()
}

player.Location = nextTile

if player.BotStrategy != nil {
gm.BotStrategyWg.Add(1)
go func() {
Expand Down
83 changes: 50 additions & 33 deletions internal/game/Player.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,21 @@ type AllTiles struct {
}

type Player struct {
Name string
SshSession ssh.Session
Color *int
ClaimedEstate int
Location *Tile
CurrentDirection Direction
UpdateChannel chan tea.Msg
BotStrategy Strategy
Kills int
isDead bool
isSafe bool
Tail Tail
AllTiles AllTiles
Name string
SshSession ssh.Session
Color *int
ClaimedEstate int
Location *Tile
CurrentDirection Direction
UpdateChannel chan tea.Msg
BotStrategy Strategy
Kills int
isDead bool
isSafe bool
Speed int
ticksSkippedCount int //this is used if speed is below 0
Tail Tail
AllTiles AllTiles
}

func CreateNewPlayer(sshSession ssh.Session, name string, color int, spawnPoint *Tile) *Player {
Expand All @@ -54,33 +56,44 @@ func CreateNewPlayer(sshSession ssh.Session, name string, color int, spawnPoint
tailTiles: []*Tile{
spawnPoint,
}},
UpdateChannel: make(chan tea.Msg, 256),
Kills: 0,
isDead: false,
isSafe: false,
UpdateChannel: make(chan tea.Msg, 256),
Kills: 0,
isDead: false,
isSafe: false,
Speed: 0,
ticksSkippedCount: 0,
}
}

func (p *Player) GetNextTile() *Tile {
nextX := p.Location.X + p.CurrentDirection.Dx
nextY := p.Location.Y + p.CurrentDirection.Dy
func (p *Player) GetNextTiles() []*Tile {
tilesToGet := max(1, p.Speed)
currLocationX := p.Location.X
currLocationY := p.Location.Y
result := []*Tile{}

if nextX < 0 {
nextX = MapColCount - 1
} else if nextX >= MapColCount {
nextX = 0
}
if nextY < 0 {
nextY = MapRowCount - 1
} else if nextY >= MapRowCount {
nextY = 0
}
for range tilesToGet {
nextX := currLocationX + p.CurrentDirection.Dx
nextY := currLocationY + p.CurrentDirection.Dy

if nextX < 0 {
nextX = MapColCount - 1
} else if nextX >= MapColCount {
nextX = 0
}
if nextY < 0 {
nextY = MapRowCount - 1
} else if nextY >= MapRowCount {
nextY = 0
}

if nextY < MapRowCount && nextX < MapColCount {
return getInitGameMap()[nextY][nextX]
if nextY < MapRowCount && nextX < MapColCount {
result = append(result, getInitGameMap()[nextY][nextX])
currLocationX = nextX
currLocationY = nextY
}
}

return nil
return result
}

func (p *Player) resetTailData() {
Expand Down Expand Up @@ -112,3 +125,7 @@ func (p *Player) GetConsolidateTiles() float64 {
p.AllTiles.AllPlayerTiles = updatedTiles
return claimedLand
}

func (p *Player) ResetSpeed() {
p.Speed = 0
}
18 changes: 14 additions & 4 deletions internal/ui/GameView.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,23 @@ func (m GameViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
engineCommand = game.Direction{Dx: -1, Dy: 0, PlayerColor: *currentPlayer.Color}
case "d", "right":
engineCommand = game.Direction{Dx: 1, Dy: 0, PlayerColor: *currentPlayer.Color}
case " ":
currentPlayer.ResetSpeed()
default:
return m, nil
}

if (engineCommand.Dx == -currentPlayer.CurrentDirection.Dx && engineCommand.Dy == -currentPlayer.CurrentDirection.Dy) || (engineCommand == currentPlayer.CurrentDirection) {
return m, nil
oldSpeed := currentPlayer.Speed
if engineCommand.Dx == -currentPlayer.CurrentDirection.Dx && engineCommand.Dy == -currentPlayer.CurrentDirection.Dy {
currentPlayer.Speed -= 1
}

if engineCommand == currentPlayer.CurrentDirection {
currentPlayer.Speed += 1
}

if (engineCommand == game.Direction{}) {
//speed was altered no need to bather with direction switch
if oldSpeed != currentPlayer.Speed {
return m, nil
}

Expand Down Expand Up @@ -379,9 +387,11 @@ func (m GameViewModel) renderStatusPanel(currentPlayer *game.Player, width int,
// (This section remains unchanged from your original code)
statusContent.WriteString(lipgloss.NewStyle().Bold(true).Render("--- Player Stats ---\n"))
claimedLand := currentPlayer.GetConsolidateTiles()
statusContent.WriteString(fmt.Sprintf("Direction: %c\n", headRunes[game.Direction{Dx: currentPlayer.CurrentDirection.Dx, Dy: currentPlayer.CurrentDirection.Dy}]))
statusContent.WriteString(fmt.Sprintf("Speed: %d \n", currentPlayer.Speed))

statusContent.WriteString(fmt.Sprintf("Kills: %d\n", currentPlayer.Kills))
statusContent.WriteString(fmt.Sprintf("Claimed: %.2f %% of land\n", claimedLand*100/float64(game.MapColCount*game.MapColCount)))
statusContent.WriteString(fmt.Sprintf("Direction: %c\n", headRunes[game.Direction{Dx: currentPlayer.CurrentDirection.Dx, Dy: currentPlayer.CurrentDirection.Dy}]))
statusContent.WriteString("\n")

botCount := 0
Expand Down