mirror of
https://github.com/HexCardGames/HexDeck.git
synced 2025-09-05 03:08:39 +02:00
feat(deck-hexv1): implement experimental HexV1 card deck
This commit is contained in:
@ -13,6 +13,10 @@ func DeckFromInterface(cardDeckId int, cardDeck bson.D) types.CardDeck {
|
|||||||
deck := Classic{}
|
deck := Classic{}
|
||||||
bson.Unmarshal(bsonBytes, &deck)
|
bson.Unmarshal(bsonBytes, &deck)
|
||||||
return &deck
|
return &deck
|
||||||
|
case 1:
|
||||||
|
deck := HexV1{}
|
||||||
|
bson.Unmarshal(bsonBytes, &deck)
|
||||||
|
return &deck
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -26,6 +30,10 @@ func CardFromInterface(cardDeckId int, card bson.D) types.Card {
|
|||||||
deck := ClassicCard{}
|
deck := ClassicCard{}
|
||||||
bson.Unmarshal(bsonBytes, &deck)
|
bson.Unmarshal(bsonBytes, &deck)
|
||||||
return &deck
|
return &deck
|
||||||
|
case 1:
|
||||||
|
deck := HexV1Card{}
|
||||||
|
bson.Unmarshal(bsonBytes, &deck)
|
||||||
|
return &deck
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
205
backend/decks/hexv1.go
Normal file
205
backend/decks/hexv1.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
package decks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand/v2"
|
||||||
|
|
||||||
|
"github.com/HexCardGames/HexDeck/types"
|
||||||
|
"github.com/HexCardGames/HexDeck/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HexV1 struct {
|
||||||
|
room *types.Room
|
||||||
|
CardsPlayed []*HexV1Card
|
||||||
|
PlayerOrder []int
|
||||||
|
ActiveIndex int
|
||||||
|
}
|
||||||
|
|
||||||
|
type HexV1Card struct {
|
||||||
|
Symbol string
|
||||||
|
Color string
|
||||||
|
NumericValue int
|
||||||
|
}
|
||||||
|
|
||||||
|
var HexV1Colors = []string{"blue", "green", "yellow", "purple"}
|
||||||
|
var HexV1ActionCards = []string{"shuffle", "skip", "draw", "swap"}
|
||||||
|
|
||||||
|
func (deck *HexV1) Init(room *types.Room) {
|
||||||
|
deck.room = room
|
||||||
|
deck.PlayerOrder = make([]int, len(room.Players))
|
||||||
|
deck.ActiveIndex = 0
|
||||||
|
|
||||||
|
deck.room.PlayersMutex.Lock()
|
||||||
|
defer deck.room.PlayersMutex.Unlock()
|
||||||
|
for i, player := range deck.room.Players {
|
||||||
|
deck.PlayerOrder[i] = i
|
||||||
|
player.Mutex.Lock()
|
||||||
|
defer player.Mutex.Unlock()
|
||||||
|
deck.drawMany(player, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) SetRoom(room *types.Room) {
|
||||||
|
deck.room = room
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) IsEmpty() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) getTopCard() *HexV1Card {
|
||||||
|
if len(deck.CardsPlayed) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return deck.CardsPlayed[len(deck.CardsPlayed)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) GetTopCard() types.Card {
|
||||||
|
return deck.getTopCard()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) generateCard() *HexV1Card {
|
||||||
|
cardType := rand.IntN(16 + len(HexV1ActionCards))
|
||||||
|
cardColor := HexV1Colors[rand.IntN(len(HexV1Colors))]
|
||||||
|
if cardType < 16 {
|
||||||
|
return &HexV1Card{
|
||||||
|
Symbol: fmt.Sprintf("%x", cardType),
|
||||||
|
Color: cardColor,
|
||||||
|
NumericValue: cardType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cardSymbol := HexV1ActionCards[cardType-16]
|
||||||
|
if rand.IntN(100) <= 10 {
|
||||||
|
cardColor = "rainbow"
|
||||||
|
}
|
||||||
|
return &HexV1Card{
|
||||||
|
Symbol: "action:" + cardSymbol,
|
||||||
|
Color: cardColor,
|
||||||
|
NumericValue: 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) drawCard(player *types.Player) types.Card {
|
||||||
|
card := deck.generateCard()
|
||||||
|
player.Cards = append(player.Cards, card)
|
||||||
|
return card
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) drawMany(player *types.Player, cards int) {
|
||||||
|
for i := 0; i < cards; i++ {
|
||||||
|
deck.drawCard(player)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) DrawCard() types.Card {
|
||||||
|
// Can't draw another card before wildcard color is selected
|
||||||
|
topCard := deck.getTopCard()
|
||||||
|
if topCard != nil && topCard.Color == "rainbow" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
card := deck.drawCard(deck.getPlayer(deck.ActiveIndex))
|
||||||
|
deck.nextPlayer()
|
||||||
|
return card
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) getNextValidIndex(index int) int {
|
||||||
|
if len(deck.room.Players) == 0 || len(deck.PlayerOrder) == 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
checkIndex := utils.Mod(index, len(deck.PlayerOrder))
|
||||||
|
for deck.PlayerOrder[checkIndex] >= len(deck.room.Players) {
|
||||||
|
checkIndex = utils.Mod(checkIndex+1, len(deck.PlayerOrder))
|
||||||
|
}
|
||||||
|
return checkIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) getPlayer(index int) *types.Player {
|
||||||
|
playerIndex := deck.getNextValidIndex(index)
|
||||||
|
if playerIndex == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return deck.room.Players[deck.PlayerOrder[playerIndex]]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) getNextPlayerIndex() int {
|
||||||
|
return deck.getNextValidIndex(deck.ActiveIndex + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) nextPlayer() {
|
||||||
|
deck.ActiveIndex = deck.getNextPlayerIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) IsPlayerActive(target *types.Player) bool {
|
||||||
|
return deck.getPlayer(deck.ActiveIndex) == target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) CanPlay(card types.Card) bool {
|
||||||
|
topCard := deck.getTopCard()
|
||||||
|
checkCard := card.(*HexV1Card)
|
||||||
|
if topCard == nil || checkCard == nil {
|
||||||
|
return topCard == nil
|
||||||
|
}
|
||||||
|
return topCard.Color != "rainbow" && (checkCard.Color == "rainbow" || checkCard.Color == topCard.Color || checkCard.Symbol == topCard.Symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) PlayCard(card types.Card) bool {
|
||||||
|
if !deck.CanPlay(card) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
deckCard := card.(*HexV1Card)
|
||||||
|
targetPlayer := deck.getPlayer(deck.ActiveIndex)
|
||||||
|
nextPlayer := deck.getPlayer(deck.getNextPlayerIndex())
|
||||||
|
|
||||||
|
if deckCard.Symbol == "action:skip" && deckCard.Color != "rainbow" {
|
||||||
|
deck.nextPlayer()
|
||||||
|
} else if deckCard.Symbol == "action:draw" {
|
||||||
|
amount := 3
|
||||||
|
topCard := deck.getTopCard()
|
||||||
|
if topCard != nil {
|
||||||
|
amount = topCard.NumericValue
|
||||||
|
}
|
||||||
|
deck.drawMany(nextPlayer, amount)
|
||||||
|
} else if deckCard.Symbol == "action:shuffle" {
|
||||||
|
utils.ShuffleSlice(&deck.PlayerOrder)
|
||||||
|
} else if deckCard.Symbol == "action:swap" {
|
||||||
|
p1Cards := targetPlayer.Cards
|
||||||
|
p2Cards := nextPlayer.Cards
|
||||||
|
targetPlayer.Cards = p2Cards
|
||||||
|
nextPlayer.Cards = p1Cards
|
||||||
|
}
|
||||||
|
|
||||||
|
if deckCard.Color != "rainbow" {
|
||||||
|
deck.nextPlayer()
|
||||||
|
}
|
||||||
|
|
||||||
|
deck.CardsPlayed = append(deck.CardsPlayed, deckCard)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (deck *HexV1) UpdatePlayedCard(cardData interface{}) types.Card {
|
||||||
|
topCard := deck.getTopCard()
|
||||||
|
if topCard.Color != "rainbow" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
updateData, ok := cardData.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newColor, ok := updateData["Color"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, color := range HexV1Colors {
|
||||||
|
if newColor == color {
|
||||||
|
deck.nextPlayer()
|
||||||
|
if topCard.Symbol == "action:skip" {
|
||||||
|
deck.nextPlayer()
|
||||||
|
}
|
||||||
|
topCard.Color = color
|
||||||
|
return topCard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -39,7 +39,7 @@ func CreateRoom() *types.Room {
|
|||||||
GameState: types.StateLobby,
|
GameState: types.StateLobby,
|
||||||
Players: make([]*types.Player, 0),
|
Players: make([]*types.Player, 0),
|
||||||
PlayersMutex: &sync.Mutex{},
|
PlayersMutex: &sync.Mutex{},
|
||||||
CardDeckId: 0,
|
CardDeckId: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Conn.InsertRoom(newRoom)
|
db.Conn.InsertRoom(newRoom)
|
||||||
|
@ -34,5 +34,8 @@ func ShuffleSlice[T any](slice *([]T)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Mod(a, b int) int {
|
func Mod(a, b int) int {
|
||||||
|
if b == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
return (a%b + b) % b
|
return (a%b + b) % b
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user