123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- package main
- import (
- "math/rand"
- "red-green/door"
- "strings"
- )
- type Deck struct {
- Cards []door.Panel
- Backs []door.Panel
- Mark []door.Panel
- }
- func (d *Deck) SetBackColor(color string) {
- for x := 0; x < 5; x++ {
- for idx := range d.Backs[x].Lines {
- d.Backs[x].Lines[idx].DefaultColor = color
- }
- }
- }
- func (d *Deck) Init() {
- d.Cards = make([]door.Panel, 52)
- for x := 0; x < 52; x++ {
- d.Cards[x] = CardOf(x)
- }
- d.Backs = make([]door.Panel, 5)
- for x := 0; x < 5; x++ {
- d.Backs[x] = BackOf(x)
- }
- d.Mark = make([]door.Panel, 2)
- d.Mark[0] = MarkOf(0)
- d.Mark[1] = MarkOf(1)
- }
- func CardOf(c int) door.Panel {
- suit := GetSuit(c)
- rank := GetRank(c)
- var is_red bool = suit < 2
- var color string
- if is_red {
- color = door.ColorText("RED ON WHITE")
- } else {
- color = door.ColorText("BLACK ON WHITE")
- }
- p := door.Panel{
- X: 0,
- Y: 0,
- Width: 5}
- r := RankSymbol(rank)
- s := SuitSymbol(suit)
- p.Lines = append(p.Lines,
- door.Line{Text: r + s + " ",
- DefaultColor: color})
- p.Lines = append(p.Lines,
- door.Line{Text: " " + s + " ",
- DefaultColor: color})
- p.Lines = append(p.Lines,
- door.Line{Text: " " + s + r,
- DefaultColor: color})
- return p
- }
- func BackOf(level int) door.Panel {
- p := door.Panel{
- X: 0,
- Y: 0,
- Width: 5,
- }
- var back string = strings.Repeat(BackSymbol(level), 5)
- for x := 0; x < 3; x++ {
- p.Lines = append(p.Lines,
- door.Line{Text: back})
- }
- return p
- }
- func MarkOf(c int) door.Panel {
- p := door.Panel{Width: 1}
- color := door.ColorText("BLUE ON WHITE")
- // var m rune
- if c == 0 {
- p.Lines = append(p.Lines,
- door.Line{Text: " ",
- DefaultColor: color,
- })
- } else {
- if door.Unicode {
- p.Lines = append(p.Lines,
- door.Line{Text: "\u25a0",
- DefaultColor: color,
- })
- // m = '\u25a0'
- } else {
- // Safely convert from byte to string
- var b [1]byte
- b[0] = 0xfe
- p.Lines = append(p.Lines,
- door.Line{Text: string(b[:]),
- DefaultColor: color})
- }
- }
- return p
- }
- func RankSymbol(c int) string {
- const symbols = "A23456789TJQK"
- return symbols[c : c+1]
- }
- func SuitSymbol(c int) string {
- if door.Unicode {
- switch c {
- case 0:
- return "\u2665"
- case 1:
- return "\u2666"
- case 2:
- return "\u2663"
- case 3:
- return "\u2660"
- }
- } else {
- if door.Full_CP437 {
- switch c {
- case 0:
- return "\x03"
- case 1:
- return "\x04"
- case 2:
- return "\x05"
- case 3:
- return "\x06"
- }
- } else {
- switch c {
- case 0:
- return "*"
- case 1:
- return "^"
- case 2:
- return "%"
- case 3:
- return "$"
- }
- }
- }
- return "?"
- }
- func BackSymbol(level int) string {
- if level == 0 {
- return " "
- }
- if door.Unicode {
- switch level {
- case 1:
- return "\u2591"
- case 2:
- return "\u2592"
- case 3:
- return "\u2593"
- case 4:
- return "\u2588"
- }
- } else {
- switch level {
- case 1:
- return "\xb0"
- case 2:
- return "\xb1"
- case 3:
- return "\xb2"
- case 4:
- return "\xdb"
- }
- }
- return "?"
- }
- func GetRank(c int) int {
- return (c % 52) % 13
- }
- func GetSuit(c int) int {
- return (c % 52) / 13
- }
- func GetDeck(c int) int {
- return c / 52
- }
- type Pos struct {
- X int
- Y int
- Level int
- }
- func CalcCardPos(pos int) Pos {
- var result Pos
- const space = 3
- const height = 3
- if pos == 28 {
- result = CalcCardPos(23)
- result.Y += height + 1
- result.Level--
- return result
- } else {
- if pos == 29 {
- result = CalcCardPos(22)
- result.Y += height + 1
- result.Level--
- return result
- }
- }
- const CARD_WIDTH = 5
- var HALF_WIDTH int = 3
- HALF_WIDTH += space / 2
- const between = CARD_WIDTH + space
- if pos < 3 {
- result.Level = 1
- result.Y = (result.Level-1)*(height-1) + 1
- result.X = pos*(between*3) + between + HALF_WIDTH + space
- return result
- } else {
- pos -= 3
- }
- if pos < 6 {
- result.Level = 2
- result.Y = (result.Level-1)*(height-1) + 1
- group := pos / 2
- result.X = pos*between + (group * between) + CARD_WIDTH + space*2
- return result
- } else {
- pos -= 6
- }
- if pos < 9 {
- result.Level = 3
- result.Y = (result.Level-1)*(height-1) + 1
- result.X = pos*between + HALF_WIDTH + space
- return result
- } else {
- pos -= 9
- }
- if pos < 10 {
- result.Level = 4
- result.Y = (result.Level-1)*(height-1) + 1
- result.X = pos*between + space
- return result
- }
- // failure
- result.Level = -1
- result.X = -1
- result.Y = -1
- return result
- }
- // 0-29
- var CardPos []Pos
- // What cards block which card?
- var Blocks [][]int
- /*
- 00 01 02
- 03 04 05 06 07 08
- 09 10 11 12 13 14 15 16 17
- 18 19 20 21 22 23 24 25 26 27
- */
- // Pre-calculate the card positions
- func init() {
- CardPos = make([]Pos, 30)
- for x := 0; x < 30; x++ {
- CardPos[x] = CalcCardPos(x)
- }
- Blocks = [][]int{
- {3, 4},
- {5, 6},
- {7, 8}, // end row 1
- {9, 10},
- {10, 11},
- {12, 13},
- {13, 14},
- {15, 16},
- {16, 17}, // end row 2
- {18, 19},
- {19, 20},
- {20, 21},
- {21, 22},
- {22, 23},
- {23, 24},
- {24, 25},
- {25, 26},
- {26, 27},
- }
- }
- // Which card(s) are unblocked by this card?
- func Unblocks(card int) []int {
- var result []int
- for idx := range Blocks {
- if Blocks[idx][0] == card || Blocks[idx][1] == card {
- result = append(result, idx)
- }
- }
- return result
- }
- func CanPlay(card1 DeckType, card2 DeckType) bool {
- rank1 := GetRank(int(card1))
- rank2 := GetRank(int(card2))
- if (rank1+1)%13 == rank2 {
- return true
- }
- if rank1 == 0 {
- rank1 += 13
- }
- if rank1-1 == rank2 {
- return true
- }
- return false
- }
- // Set the size used to represent cards in the deck.
- // 1 deck = 52, 2 decks = 104, 4 decks = 208
- // If we need more then 4 decks, we'll need a bigger
- // type here.
- type DeckType int8
- /*
- This shuffles the deck(s) of cards.
- The RNG must be seeded before calling.
- */
- func ShuffleCards(RNG *rand.Rand, decks int) []DeckType {
- var size int = decks * 52
- var result []DeckType = make([]DeckType, size)
- for x := 0; x < size; x++ {
- result[x] = DeckType(x)
- }
- RNG.Shuffle(size, func(i, j int) {
- result[i], result[j] = result[j], result[i]
- })
- return result
- }
- // Create an array to hold the deck state.
- // Has it played? Has it been unblocked/face up?
- func MakeCardStates(decks int) []DeckType {
- var size int = decks * 52
- var result []DeckType = make([]DeckType, size)
- // defaults to 0
- return result
- }
- func RemoveCard(c int, back_color string, off_x int, off_y int, left bool, right bool) string {
- var result string
- // We are modifying this -- make copy
- Pos := CardPos[c]
- if Pos.Level > 1 {
- Pos.Level--
- }
- cstr := BackSymbol(Pos.Level)
- result = door.Goto(Pos.X+off_x, Pos.Y+off_y) + back_color
- if left {
- result += cstr
- } else {
- result += " "
- }
- result += " "
- if right {
- result += cstr
- } else {
- result += " "
- }
- result += door.Goto(Pos.X+off_x, Pos.Y+off_y+1) + " "
- result += door.Goto(Pos.X+off_x, Pos.Y+off_y+2) + " "
- return result
- }
- func FindNextActiveCard(left bool, state *[]DeckType, current int) int {
- Pos := &CardPos[current]
- var current_x int = Pos.X
- var pos int = -1
- var pos_x int
- var max_pos int = -1
- var max_x int = -1
- var min_pos int = -1
- var min_x int = 100
- if left {
- pos_x = 0
- } else {
- pos_x = 100
- }
- for x := 0; x < 28; x++ {
- if (*state)[x] == 1 {
- // Possible location
- if x == current {
- continue
- }
- Pos = &CardPos[x]
- // find max and min while we're iterating here
- if Pos.X < min_x {
- min_pos = x
- min_x = Pos.X
- }
- if Pos.X > max_x {
- max_pos = x
- max_x = Pos.X
- }
- if left {
- if Pos.X < current_x && Pos.X > pos_x {
- pos_x = Pos.X
- pos = x
- }
- } else {
- if Pos.X > current_x && Pos.X < pos_x {
- pos_x = Pos.X
- pos = x
- }
- }
- }
- }
- if pos == -1 {
- // we couldn't find one
- if left {
- // use max -- roll around to the right
- pos = max_pos
- } else {
- // use min -- roll around to the left
- pos = min_pos
- }
- }
- return pos
- }
- func FindClosestActiveCard(state *[]DeckType, current int) int {
- Pos := &CardPos[current]
- var current_x int = Pos.X
- var pos int = -1
- var pos_x int = -1
- for x := 0; x < 28; x++ {
- if (*state)[x] == 1 {
- // Possible location
- if x == current {
- continue
- }
- xPos := &CardPos[x]
- if pos == -1 {
- pos = x
- pos_x = xPos.X
- } else {
- if Abs(current_x-xPos.X) < Abs(current_x-pos_x) {
- pos = x
- pos_x = xPos.X
- }
- }
- }
- }
- return pos
- }
|