deck.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. package main
  2. import (
  3. "math/rand"
  4. "red-green/door"
  5. "strings"
  6. )
  7. type Deck struct {
  8. Cards []door.Panel
  9. Backs []door.Panel
  10. Mark []door.Panel
  11. }
  12. func (d *Deck) SetBackColor(color string) {
  13. for x := 0; x < 5; x++ {
  14. for idx := range d.Backs[x].Lines {
  15. d.Backs[x].Lines[idx].DefaultColor = color
  16. }
  17. }
  18. }
  19. func (d *Deck) Init() {
  20. d.Cards = make([]door.Panel, 52)
  21. for x := 0; x < 52; x++ {
  22. d.Cards[x] = CardOf(x)
  23. }
  24. d.Backs = make([]door.Panel, 5)
  25. for x := 0; x < 5; x++ {
  26. d.Backs[x] = BackOf(x)
  27. }
  28. d.Mark = make([]door.Panel, 2)
  29. d.Mark[0] = MarkOf(0)
  30. d.Mark[1] = MarkOf(1)
  31. }
  32. func CardOf(c int) door.Panel {
  33. suit := GetSuit(c)
  34. rank := GetRank(c)
  35. var is_red bool = suit < 2
  36. var color string
  37. if is_red {
  38. color = door.ColorText("RED ON WHITE")
  39. } else {
  40. color = door.ColorText("BLACK ON WHITE")
  41. }
  42. p := door.Panel{
  43. X: 0,
  44. Y: 0,
  45. Width: 5}
  46. r := RankSymbol(rank)
  47. s := SuitSymbol(suit)
  48. p.Lines = append(p.Lines,
  49. door.Line{Text: r + s + " ",
  50. DefaultColor: color})
  51. p.Lines = append(p.Lines,
  52. door.Line{Text: " " + s + " ",
  53. DefaultColor: color})
  54. p.Lines = append(p.Lines,
  55. door.Line{Text: " " + s + r,
  56. DefaultColor: color})
  57. return p
  58. }
  59. func BackOf(level int) door.Panel {
  60. p := door.Panel{
  61. X: 0,
  62. Y: 0,
  63. Width: 5,
  64. }
  65. var back string = strings.Repeat(BackSymbol(level), 5)
  66. for x := 0; x < 3; x++ {
  67. p.Lines = append(p.Lines,
  68. door.Line{Text: back})
  69. }
  70. return p
  71. }
  72. func MarkOf(c int) door.Panel {
  73. p := door.Panel{Width: 1}
  74. color := door.ColorText("BLUE ON WHITE")
  75. // var m rune
  76. if c == 0 {
  77. p.Lines = append(p.Lines,
  78. door.Line{Text: " ",
  79. DefaultColor: color,
  80. })
  81. } else {
  82. if door.Unicode {
  83. p.Lines = append(p.Lines,
  84. door.Line{Text: "\u25a0",
  85. DefaultColor: color,
  86. })
  87. // m = '\u25a0'
  88. } else {
  89. // Safely convert from byte to string
  90. var b [1]byte
  91. b[0] = 0xfe
  92. p.Lines = append(p.Lines,
  93. door.Line{Text: string(b[:]),
  94. DefaultColor: color})
  95. }
  96. }
  97. return p
  98. }
  99. func RankSymbol(c int) string {
  100. const symbols = "A23456789TJQK"
  101. return symbols[c : c+1]
  102. }
  103. func SuitSymbol(c int) string {
  104. if door.Unicode {
  105. switch c {
  106. case 0:
  107. return "\u2665"
  108. case 1:
  109. return "\u2666"
  110. case 2:
  111. return "\u2663"
  112. case 3:
  113. return "\u2660"
  114. }
  115. } else {
  116. if door.Full_CP437 {
  117. switch c {
  118. case 0:
  119. return "\x03"
  120. case 1:
  121. return "\x04"
  122. case 2:
  123. return "\x05"
  124. case 3:
  125. return "\x06"
  126. }
  127. } else {
  128. switch c {
  129. case 0:
  130. return "*"
  131. case 1:
  132. return "^"
  133. case 2:
  134. return "%"
  135. case 3:
  136. return "$"
  137. }
  138. }
  139. }
  140. return "?"
  141. }
  142. func BackSymbol(level int) string {
  143. if level == 0 {
  144. return " "
  145. }
  146. if door.Unicode {
  147. switch level {
  148. case 1:
  149. return "\u2591"
  150. case 2:
  151. return "\u2592"
  152. case 3:
  153. return "\u2593"
  154. case 4:
  155. return "\u2588"
  156. }
  157. } else {
  158. switch level {
  159. case 1:
  160. return "\xb0"
  161. case 2:
  162. return "\xb1"
  163. case 3:
  164. return "\xb2"
  165. case 4:
  166. return "\xdb"
  167. }
  168. }
  169. return "?"
  170. }
  171. func GetRank(c int) int {
  172. return (c % 52) % 13
  173. }
  174. func GetSuit(c int) int {
  175. return (c % 52) / 13
  176. }
  177. func GetDeck(c int) int {
  178. return c / 52
  179. }
  180. type Pos struct {
  181. X int
  182. Y int
  183. Level int
  184. }
  185. func CalcCardPos(pos int) Pos {
  186. var result Pos
  187. const space = 3
  188. const height = 3
  189. if pos == 28 {
  190. result = CalcCardPos(23)
  191. result.Y += height + 1
  192. result.Level--
  193. return result
  194. } else {
  195. if pos == 29 {
  196. result = CalcCardPos(22)
  197. result.Y += height + 1
  198. result.Level--
  199. return result
  200. }
  201. }
  202. const CARD_WIDTH = 5
  203. var HALF_WIDTH int = 3
  204. HALF_WIDTH += space / 2
  205. const between = CARD_WIDTH + space
  206. if pos < 3 {
  207. result.Level = 1
  208. result.Y = (result.Level-1)*(height-1) + 1
  209. result.X = pos*(between*3) + between + HALF_WIDTH + space
  210. return result
  211. } else {
  212. pos -= 3
  213. }
  214. if pos < 6 {
  215. result.Level = 2
  216. result.Y = (result.Level-1)*(height-1) + 1
  217. group := pos / 2
  218. result.X = pos*between + (group * between) + CARD_WIDTH + space*2
  219. return result
  220. } else {
  221. pos -= 6
  222. }
  223. if pos < 9 {
  224. result.Level = 3
  225. result.Y = (result.Level-1)*(height-1) + 1
  226. result.X = pos*between + HALF_WIDTH + space
  227. return result
  228. } else {
  229. pos -= 9
  230. }
  231. if pos < 10 {
  232. result.Level = 4
  233. result.Y = (result.Level-1)*(height-1) + 1
  234. result.X = pos*between + space
  235. return result
  236. }
  237. // failure
  238. result.Level = -1
  239. result.X = -1
  240. result.Y = -1
  241. return result
  242. }
  243. // 0-29
  244. var CardPos []Pos
  245. // What cards block which card?
  246. var Blocks [][]int
  247. /*
  248. 00 01 02
  249. 03 04 05 06 07 08
  250. 09 10 11 12 13 14 15 16 17
  251. 18 19 20 21 22 23 24 25 26 27
  252. */
  253. // Pre-calculate the card positions
  254. func init() {
  255. CardPos = make([]Pos, 30)
  256. for x := 0; x < 30; x++ {
  257. CardPos[x] = CalcCardPos(x)
  258. }
  259. Blocks = [][]int{
  260. {3, 4},
  261. {5, 6},
  262. {7, 8}, // end row 1
  263. {9, 10},
  264. {10, 11},
  265. {12, 13},
  266. {13, 14},
  267. {15, 16},
  268. {16, 17}, // end row 2
  269. {18, 19},
  270. {19, 20},
  271. {20, 21},
  272. {21, 22},
  273. {22, 23},
  274. {23, 24},
  275. {24, 25},
  276. {25, 26},
  277. {26, 27},
  278. }
  279. }
  280. // Which card(s) are unblocked by this card?
  281. func Unblocks(card int) []int {
  282. var result []int
  283. for idx := range Blocks {
  284. if Blocks[idx][0] == card || Blocks[idx][1] == card {
  285. result = append(result, idx)
  286. }
  287. }
  288. return result
  289. }
  290. func CanPlay(card1 DeckType, card2 DeckType) bool {
  291. rank1 := GetRank(int(card1))
  292. rank2 := GetRank(int(card2))
  293. if (rank1+1)%13 == rank2 {
  294. return true
  295. }
  296. if rank1 == 0 {
  297. rank1 += 13
  298. }
  299. if rank1-1 == rank2 {
  300. return true
  301. }
  302. return false
  303. }
  304. // Set the size used to represent cards in the deck.
  305. // 1 deck = 52, 2 decks = 104, 4 decks = 208
  306. // If we need more then 4 decks, we'll need a bigger
  307. // type here.
  308. type DeckType int8
  309. /*
  310. This shuffles the deck(s) of cards.
  311. The RNG must be seeded before calling.
  312. */
  313. func ShuffleCards(RNG *rand.Rand, decks int) []DeckType {
  314. var size int = decks * 52
  315. var result []DeckType = make([]DeckType, size)
  316. for x := 0; x < size; x++ {
  317. result[x] = DeckType(x)
  318. }
  319. RNG.Shuffle(size, func(i, j int) {
  320. result[i], result[j] = result[j], result[i]
  321. })
  322. return result
  323. }
  324. // Create an array to hold the deck state.
  325. // Has it played? Has it been unblocked/face up?
  326. func MakeCardStates(decks int) []DeckType {
  327. var size int = decks * 52
  328. var result []DeckType = make([]DeckType, size)
  329. // defaults to 0
  330. return result
  331. }
  332. func RemoveCard(c int, back_color string, off_x int, off_y int, left bool, right bool) string {
  333. var result string
  334. // We are modifying this -- make copy
  335. Pos := CardPos[c]
  336. if Pos.Level > 1 {
  337. Pos.Level--
  338. }
  339. cstr := BackSymbol(Pos.Level)
  340. result = door.Goto(Pos.X+off_x, Pos.Y+off_y) + back_color
  341. if left {
  342. result += cstr
  343. } else {
  344. result += " "
  345. }
  346. result += " "
  347. if right {
  348. result += cstr
  349. } else {
  350. result += " "
  351. }
  352. result += door.Goto(Pos.X+off_x, Pos.Y+off_y+1) + " "
  353. result += door.Goto(Pos.X+off_x, Pos.Y+off_y+2) + " "
  354. return result
  355. }
  356. func FindNextActiveCard(left bool, state *[]DeckType, current int) int {
  357. Pos := &CardPos[current]
  358. var current_x int = Pos.X
  359. var pos int = -1
  360. var pos_x int
  361. var max_pos int = -1
  362. var max_x int = -1
  363. var min_pos int = -1
  364. var min_x int = 100
  365. if left {
  366. pos_x = 0
  367. } else {
  368. pos_x = 100
  369. }
  370. for x := 0; x < 28; x++ {
  371. if (*state)[x] == 1 {
  372. // Possible location
  373. if x == current {
  374. continue
  375. }
  376. Pos = &CardPos[x]
  377. // find max and min while we're iterating here
  378. if Pos.X < min_x {
  379. min_pos = x
  380. min_x = Pos.X
  381. }
  382. if Pos.X > max_x {
  383. max_pos = x
  384. max_x = Pos.X
  385. }
  386. if left {
  387. if Pos.X < current_x && Pos.X > pos_x {
  388. pos_x = Pos.X
  389. pos = x
  390. }
  391. } else {
  392. if Pos.X > current_x && Pos.X < pos_x {
  393. pos_x = Pos.X
  394. pos = x
  395. }
  396. }
  397. }
  398. }
  399. if pos == -1 {
  400. // we couldn't find one
  401. if left {
  402. // use max -- roll around to the right
  403. pos = max_pos
  404. } else {
  405. // use min -- roll around to the left
  406. pos = min_pos
  407. }
  408. }
  409. return pos
  410. }
  411. func FindClosestActiveCard(state *[]DeckType, current int) int {
  412. Pos := &CardPos[current]
  413. var current_x int = Pos.X
  414. var pos int = -1
  415. var pos_x int = -1
  416. for x := 0; x < 28; x++ {
  417. if (*state)[x] == 1 {
  418. // Possible location
  419. if x == current {
  420. continue
  421. }
  422. xPos := &CardPos[x]
  423. if pos == -1 {
  424. pos = x
  425. pos_x = xPos.X
  426. } else {
  427. if Abs(current_x-xPos.X) < Abs(current_x-pos_x) {
  428. pos = x
  429. pos_x = xPos.X
  430. }
  431. }
  432. }
  433. }
  434. return pos
  435. }