deck.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package cards
  2. import (
  3. cryptoRand "crypto/rand"
  4. "fmt"
  5. "math/big"
  6. )
  7. // новая колода из 36 карт. jokers - количество джокеров в колоде
  8. func NewDeck36(jokers int) *Deck {
  9. deck, _ := NewDeckOffset(Number(6), jokers)
  10. return deck
  11. }
  12. // новая колода из 54 карт. jokers - количество джокеров в колоде
  13. func NewDeck54(jokers int) *Deck {
  14. deck, _ := NewDeckOffset(Number(2), jokers)
  15. return deck
  16. }
  17. // новая колода. 4 масти, порядок начинается с offset (минимальный)
  18. func NewDeckOffset(offset Number, jockers int) (*Deck, error) {
  19. if !offset.IsValid() {
  20. return nil, fmt.Errorf("invalid offset: %d", offset)
  21. }
  22. cards := make([]*Card, 0, 52+jockers)
  23. for i := Hearts; i <= Spades; i++ {
  24. for j := Number(2); j <= Ace; j++ {
  25. cards = append(
  26. cards,
  27. &Card{
  28. N: j,
  29. S: i,
  30. },
  31. )
  32. }
  33. }
  34. for i := 0; i < jockers; i++ {
  35. cards = append(
  36. cards,
  37. &Card{
  38. N: Joker,
  39. S: Undefined,
  40. })
  41. }
  42. deck := &Deck{
  43. countJokers: jockers,
  44. cards: cards,
  45. }
  46. return deck, nil
  47. }
  48. // колода
  49. type Deck struct {
  50. countJokers int
  51. cards []*Card
  52. offsetLeft int
  53. offsetRight int
  54. }
  55. // количество джокеров в колоде
  56. func (s *Deck) CountJokers() int {
  57. return s.countJokers
  58. }
  59. // собираем колоду в исходное состояние (возвращаем вышедшие карты)
  60. func (s *Deck) ResetOffset() {
  61. s.offsetLeft = 0
  62. s.offsetRight = 0
  63. }
  64. // количество карт в колоде
  65. func (s *Deck) Count() int {
  66. return len(s.cards)
  67. }
  68. // количество карт без джокеров
  69. func (s *Deck) CountWithoutJokers() int {
  70. return len(s.cards) - s.countJokers
  71. }
  72. // количество оставшихся карт в колоде
  73. func (s *Deck) CountLeft() int {
  74. return len(s.cards) - s.offsetLeft - s.offsetRight
  75. }
  76. // переместить карту с позиции pos на позицию newPos
  77. // если pos или newPos выходят за рамки массива колоды, результат будет false
  78. func (s *Deck) MoveCard(pos, newPos int) bool {
  79. if (pos < 0 || pos >= len(s.cards)) || (newPos < 0 || newPos >= len(s.cards)) {
  80. return false
  81. }
  82. s.cards[pos], s.cards[newPos] = s.cards[newPos], s.cards[pos]
  83. return true
  84. }
  85. // перемешать колоду (стандартныйметод с использованием криптографически стойкого генератора)
  86. func (s *Deck) Shuffle() {
  87. n := len(s.cards)
  88. for i := range s.cards {
  89. // генерация случайного индекса с использованием криптографически стойкого генератора
  90. jBig, _ := cryptoRand.Int(cryptoRand.Reader, big.NewInt(int64(n-i)))
  91. j := int(jBig.Int64()) + i
  92. // меняем позицию
  93. s.cards[i], s.cards[j] = s.cards[j], s.cards[i]
  94. }
  95. }
  96. // взять карту снизу
  97. func (s *Deck) PopLeft() (*Card, bool) {
  98. if s.CountLeft() == 0 {
  99. return nil, false
  100. }
  101. card := s.cards[s.offsetLeft]
  102. s.offsetLeft += 1
  103. return card, true
  104. }
  105. // взять карту сверху
  106. func (s *Deck) PopRight() (*Card, bool) {
  107. if s.CountLeft() == 0 {
  108. return nil, false
  109. }
  110. card := s.cards[len(s.cards)-s.offsetRight-1]
  111. s.offsetRight += 1
  112. return card, true
  113. }
  114. // строка полной колоды (включая вышедшие карты)
  115. func (s *Deck) StringAll() string {
  116. return showCardSlice(s.cards)
  117. }
  118. // строка только оставшихся карт
  119. func (s *Deck) StringLeft() (res string) {
  120. left := s.cards[s.offsetLeft : len(s.cards)-s.offsetRight]
  121. return showCardSlice(left)
  122. }
  123. // строка только вышедших карт
  124. func (s *Deck) String() string {
  125. return "[ " + s.StringLeft() + " ]"
  126. }