blob: 027caa8a8f2d6cb5ce976c8b1f058078895bd20f [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package table
import (
"hearts/logic/card"
"hearts/logic/player"
"math/rand"
)
func NewTable(p []*player.Player) *Table {
return &Table{
players: p,
trick: make([]*card.Card, len(p)),
firstPlayed: -1,
allCards: nil,
heartsBroken: false,
firstTrick: true,
winCondition: 100,
}
}
type Table struct {
// players contains all players in the game, indexed by playerIndex
players []*player.Player
// trick contains all cards in the current trick, indexed by the playerIndex of the player who played them
trick []*card.Card
// firstPlayed is the index in trick of the card played first
firstPlayed int
// allCards contains all 52 cards in the deck. GenerateCards() populates this
allCards []*card.Card
// heartsBroken returns true if a heart has been played yet in the round, otherwise false
heartsBroken bool
// firstTrick returns true if the current trick is the first in the round, otherwise false
firstTrick bool
// winCondition is the number of points needed to win the game
// traditionally 100, could set higher or lower for longer or shorter game
winCondition int
}
func (t *Table) GetPlayers() []*player.Player {
return t.players
}
func (t *Table) SetFirstPlayed(index int) {
t.firstPlayed = index
}
// This function generates a traditional deck of 52 cards, with 13 in each of the four suits
// Each card has a suit (Club, Diamond, Spade, or Heart)
// Each card also has a number from 2-14, where 11 through 14 represent Jack, Queen, King and Ace, respectively
func (t *Table) GenerateCards() {
cardsPerSuit := 13
t.allCards = make([]*card.Card, 0)
cardFaces := []card.Face{card.Two, card.Three, card.Four, card.Five, card.Six, card.Seven, card.Eight, card.Nine,
card.Ten, card.Jack, card.Queen, card.King, card.Ace}
for i := 0; i < cardsPerSuit; i++ {
t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Club))
t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Diamond))
t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Spade))
t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Heart))
}
}
func (t *Table) PlayCard(c *card.Card, playerIndex int) {
t.trick[playerIndex] = c
if c.GetSuit() == card.Heart && !t.heartsBroken {
t.heartsBroken = true
}
}
func (t *Table) ValidPlay(c *card.Card, playerIndex int) bool {
player := t.players[playerIndex]
if t.firstPlayed == playerIndex {
if !t.firstTrick {
if c.GetSuit() != card.Heart || t.heartsBroken {
return true
} else {
if player.HasOnlyHearts() {
return true
}
}
} else if c.GetSuit() == card.Club && c.GetFace() == card.Two {
return true
}
} else {
firstPlayedSuit := t.trick[t.firstPlayed].GetSuit()
if c.GetSuit() == firstPlayedSuit || !player.HasSuit(firstPlayedSuit) {
if !t.firstTrick {
return true
} else if !c.WorthPoints() {
return true
} else if player.HasAllPoints() {
return true
}
}
}
return false
}
func (t *Table) SendTrick() {
trickSuit := t.trick[t.firstPlayed].GetSuit()
highestCardFace := card.Two
highestIndex := -1
for i := 0; i < len(t.trick); i++ {
curCard := t.trick[i]
if curCard.GetSuit() == trickSuit && curCard.GetFace() >= highestCardFace {
highestCardFace = curCard.GetFace()
highestIndex = i
}
}
// clear trick
t.players[highestIndex].TakeTrick(t.trick)
t.trick = make([]*card.Card, len(t.players))
if t.firstTrick {
t.firstTrick = false
}
}
func (t *Table) ScoreRound() {
allPoints := 26
roundScores := make([]int, len(t.players))
shotMoon := false
shooter := -1
for i := 0; i < len(t.players); i++ {
roundScores[i] = t.players[i].CalculateScore()
if roundScores[i] == allPoints {
shotMoon = true
shooter = i
}
}
if shotMoon {
for i := 0; i < len(t.players); i++ {
if i == shooter {
roundScores[i] = 0
} else {
roundScores[i] = allPoints
}
}
}
// sending scores to players
for i := 0; i < len(t.players); i++ {
t.players[i].UpdateScore(roundScores[i])
}
}
func (t *Table) Deal() {
numPlayers := len(t.players)
if t.allCards == nil {
t.GenerateCards()
}
shuffle := rand.Perm(len(t.allCards))
for i := 0; i < len(t.allCards); i++ {
t.players[i%numPlayers].AddToHand(t.allCards[shuffle[i]])
}
}
// returns -1 if the game hasn't been won, playerIndex of the winner if it has
// to-do: return a list of players in the event of a tie
func (t *Table) EndRound() int {
t.ScoreRound()
lowestScore := -1
winningPlayer := -1
winTriggered := false
for _, p := range t.players {
p.ResetTricks()
if p.GetScore() >= t.winCondition {
winTriggered = true
}
if p.GetScore() < lowestScore || lowestScore == -1 {
lowestScore = p.GetScore()
winningPlayer = p.GetPlayerIndex()
}
}
if winTriggered {
return winningPlayer
}
return -1
}
func (t *Table) NewRound() {
t.heartsBroken = false
t.firstTrick = true
t.Deal()
}