|
@@ -0,0 +1,143 @@
|
|
|
+package cards
|
|
|
+
|
|
|
+import (
|
|
|
+ cryptoRand "crypto/rand"
|
|
|
+ "fmt"
|
|
|
+ "math/big"
|
|
|
+)
|
|
|
+
|
|
|
+// новая колода из 36 карт. jokers - количество джокеров в колоде
|
|
|
+func NewDeck36(jokers int) *Deck {
|
|
|
+ deck, _ := NewDeckOffset(Number(6), jokers)
|
|
|
+ return deck
|
|
|
+}
|
|
|
+
|
|
|
+// новая колода из 54 карт. jokers - количество джокеров в колоде
|
|
|
+func NewDeck54(jokers int) *Deck {
|
|
|
+ deck, _ := NewDeckOffset(Number(2), jokers)
|
|
|
+ return deck
|
|
|
+}
|
|
|
+
|
|
|
+// новая колода. 4 масти, порядок начинается с offset (минимальный)
|
|
|
+func NewDeckOffset(offset Number, jockers int) (*Deck, error) {
|
|
|
+ if !offset.IsValid() {
|
|
|
+ return nil, fmt.Errorf("invalid offset: %d", offset)
|
|
|
+ }
|
|
|
+ cards := make([]*Card, 0, 52+jockers)
|
|
|
+ for i := Hearts; i <= Spades; i++ {
|
|
|
+ for j := Number(2); j <= Ace; j++ {
|
|
|
+ cards = append(
|
|
|
+ cards,
|
|
|
+ &Card{
|
|
|
+ N: j,
|
|
|
+ S: i,
|
|
|
+ },
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for i := 0; i < jockers; i++ {
|
|
|
+ cards = append(
|
|
|
+ cards,
|
|
|
+ &Card{
|
|
|
+ N: Joker,
|
|
|
+ S: Undefined,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ deck := &Deck{
|
|
|
+ countJokers: jockers,
|
|
|
+ cards: cards,
|
|
|
+ }
|
|
|
+ return deck, nil
|
|
|
+}
|
|
|
+
|
|
|
+// колода
|
|
|
+type Deck struct {
|
|
|
+ countJokers int
|
|
|
+ cards []*Card
|
|
|
+ offsetLeft int
|
|
|
+ offsetRight int
|
|
|
+}
|
|
|
+
|
|
|
+// количество джокеров в колоде
|
|
|
+func (s *Deck) CountJokers() int {
|
|
|
+ return s.countJokers
|
|
|
+}
|
|
|
+
|
|
|
+// собираем колоду в исходное состояние (возвращаем вышедшие карты)
|
|
|
+func (s *Deck) ResetOffset() {
|
|
|
+ s.offsetLeft = 0
|
|
|
+ s.offsetRight = 0
|
|
|
+}
|
|
|
+
|
|
|
+// количество карт в колоде
|
|
|
+func (s *Deck) Count() int {
|
|
|
+ return len(s.cards)
|
|
|
+}
|
|
|
+
|
|
|
+// количество карт без джокеров
|
|
|
+func (s *Deck) CountWithoutJokers() int {
|
|
|
+ return len(s.cards) - s.countJokers
|
|
|
+}
|
|
|
+
|
|
|
+// количество оставшихся карт в колоде
|
|
|
+func (s *Deck) CountLeft() int {
|
|
|
+ return len(s.cards) - s.offsetLeft - s.offsetRight
|
|
|
+}
|
|
|
+
|
|
|
+// переместить карту с позиции pos на позицию newPos
|
|
|
+// если pos или newPos выходят за рамки массива колоды, результат будет false
|
|
|
+func (s *Deck) MoveCard(pos, newPos int) bool {
|
|
|
+ if (pos < 0 || pos >= len(s.cards)) || (newPos < 0 || newPos >= len(s.cards)) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ s.cards[pos], s.cards[newPos] = s.cards[newPos], s.cards[pos]
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+// перемешать колоду (стандартныйметод с использованием криптографически стойкого генератора)
|
|
|
+func (s *Deck) Shuffle() {
|
|
|
+ n := len(s.cards)
|
|
|
+ for i := range s.cards {
|
|
|
+ // генерация случайного индекса с использованием криптографически стойкого генератора
|
|
|
+ jBig, _ := cryptoRand.Int(cryptoRand.Reader, big.NewInt(int64(n-i)))
|
|
|
+ j := int(jBig.Int64()) + i
|
|
|
+ // меняем позицию
|
|
|
+ s.cards[i], s.cards[j] = s.cards[j], s.cards[i]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// взять карту снизу
|
|
|
+func (s *Deck) PopLeft() (*Card, bool) {
|
|
|
+ if s.CountLeft() == 0 {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ card := s.cards[s.offsetLeft]
|
|
|
+ s.offsetLeft += 1
|
|
|
+ return card, true
|
|
|
+}
|
|
|
+
|
|
|
+// взять карту сверху
|
|
|
+func (s *Deck) PopRight() (*Card, bool) {
|
|
|
+ if s.CountLeft() == 0 {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ card := s.cards[len(s.cards)-s.offsetRight-1]
|
|
|
+ s.offsetRight += 1
|
|
|
+ return card, true
|
|
|
+}
|
|
|
+
|
|
|
+// строка полной колоды (включая вышедшие карты)
|
|
|
+func (s *Deck) StringAll() string {
|
|
|
+ return showCardSlice(s.cards)
|
|
|
+}
|
|
|
+
|
|
|
+// строка только оставшихся карт
|
|
|
+func (s *Deck) StringLeft() (res string) {
|
|
|
+ left := s.cards[s.offsetLeft : len(s.cards)-s.offsetRight]
|
|
|
+ return showCardSlice(left)
|
|
|
+}
|
|
|
+
|
|
|
+// строка только вышедших карт
|
|
|
+func (s *Deck) String() string {
|
|
|
+ return "[ " + s.StringLeft() + " ]"
|
|
|
+}
|