123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254 |
- package main
- import (
- "crypto/sha1"
- "encoding/binary"
- "fmt"
- "log"
- "math/rand"
- "red-green/door"
- "strconv"
- "strings"
- "time"
- )
- func StringToANSIColor(colorCode string) string {
- colors := []string{
- "BLUE",
- "BROWN",
- "RED",
- "CYAN",
- "GREEN",
- "MAGENTA",
- "WHITE",
- }
- code := strings.ToUpper(colorCode)
- for _, c := range colors {
- if c == code {
- return door.ColorText(code)
- }
- }
- if code == "ALL" {
- rand.Seed(time.Now().UnixNano())
- pos := rand.Intn(len(colors))
- return door.ColorText(colors[pos])
- }
- return door.ColorText("WHITE")
- }
- type PlayCards struct {
- Door *door.Door
- DB *DBData
- Config *map[string]string
- RNG *rand.Rand
- Seeds []int32
- Total_hands int
- Play_card int
- Current_streak int
- Best_streak int
- Hand_streak int
- Month_streak int
- Select_card int
- Score int
- Play_day YMD
- Days_played int
- Hand int
- SpaceAceTriPeaks door.Panel
- ScorePanel door.Panel
- StreakPanel door.Panel
- LeftPanel door.Panel
- CmdPanel door.Panel
- NextQuitPanel door.Panel
- DeckPanel Deck
- Deck []DeckType // [51]DeckType t
- State []DeckType // [51]DeckType
- Off_X int
- Off_Y int
- Calendar door.Screen
- Calendar_panel_days [42]int // Where is each day positioned on the Calendar? 42 = 7 day * 6 lines
- Calendar_day_status [31]int
- }
- // Calendar_day [31]DBDate // deprecate
- // Possibly change Deck to [51]DeckType. This game always only has 1 deck.
- // Possibly change State [51]DeckType to [51]int8.
- // There are few states to track.
- func cmdLineRender(bracket string, inner string, outer string) func(string) string {
- return func(input string) string {
- var r door.Render = door.Render{Line: input}
- inOuter := true
- for _, c := range input {
- if c == '[' {
- inOuter = false
- r.Append(bracket, 1)
- continue
- }
- if c == ']' {
- inOuter = true
- r.Append(bracket, 1)
- continue
- }
- if inOuter {
- r.Append(outer, 1)
- } else {
- r.Append(inner, 1)
- }
- }
- return r.Result
- }
- }
- func (pc *PlayCards) InitValues() {
- hands := pc.DB.GetSetting("hands_per_day", "3")
- pc.Total_hands, _ = strconv.Atoi(hands)
- pc.Play_card = 28
- pc.Current_streak = 0
- pc.Best_streak = 0
- best := pc.DB.GetSetting("best_streak", "0")
- pc.Best_streak, _ = strconv.Atoi(best)
- pc.Month_streak = 0
- // Init the best streak for this month
- // TODO: Pull from DB.
- pc.Hand_streak = 0
- // Best for this hand
- pc.Select_card = 23
- pc.Score = 0
- }
- func (pc *PlayCards) Init() {
- // init_values()
- pc.InitValues()
- // PlayCards::PlayCards()
- pc.Play_day = NewYMDFromTime(time.Now())
- // NormalizeDate(&pc.Play_day)
- //pc.Play_day_t = pc.Play_day.Unix()
- pc.DeckPanel.Init()
- var last_played YMD
- last := pc.DB.GetSetting("last_played", "0")
- temp, _ := strconv.ParseInt(last, 10, 64)
- last_played = YMD(temp)
- days := pc.DB.GetSetting("days_played", "0")
- pc.Days_played, _ = strconv.Atoi(days)
- if last_played != pc.Play_day {
- pc.DB.SetSetting("last_played", strconv.FormatInt(int64(pc.Play_day), 10))
- pc.DB.SetSetting("days_played", "0")
- pc.Days_played = 0
- }
- pc.Seeds = make([]int32, 0)
- // config _seed
- parts := strings.Split((*pc.Config)["_seed"], ",")
- for _, seed := range parts {
- i, _ := strconv.ParseInt(seed, 10, 32)
- pc.Seeds = append(pc.Seeds, int32(i))
- }
- pc.Hand = 0
- // spaceAceTriPeaks = make_tripeaks();
- {
- tripeakstext := " " + SPACEACE + " - Tri-Peaks Solitaire v" + SPACEACE_VERSION + " "
- pc.SpaceAceTriPeaks = door.Panel{Width: len(tripeakstext),
- Style: door.SINGLE,
- BorderColor: door.ColorText("CYAN ON BLACK"),
- }
- pc.SpaceAceTriPeaks.Lines = append(pc.SpaceAceTriPeaks.Lines,
- door.Line{Text: tripeakstext})
- }
- svRender := RenderStatusValue(door.ColorText("BOLD WHITE ON BLUE"),
- door.ColorText("BOLD YELLOW ON BLUE"))
- // score_panel = make_score_panel();
- {
- W := 25
- pc.ScorePanel = door.Panel{Width: W}
- text := "Name: " + pc.Door.Config.Real_name
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: fmt.Sprintf("%*s", -W, text), RenderF: svRender})
- scoreUpdate := func() string {
- txt := fmt.Sprintf("Score: %d", pc.Score)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: scoreUpdate(),
- UpdateF: scoreUpdate,
- RenderF: svRender,
- })
- timeUpdate := func() string {
- var left int = int(pc.Door.TimeLeft().Minutes())
- var used int = int(pc.Door.TimeUsed().Minutes())
- txt := fmt.Sprintf("Time used: %3d / %3d", used, left)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: timeUpdate(),
- UpdateF: timeUpdate,
- RenderF: svRender,
- })
- handUpdate := func() string {
- txt := fmt.Sprintf("Playing Hand %d of %d", pc.Hand, pc.Total_hands)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: handUpdate(),
- UpdateF: handUpdate,
- RenderF: svRender,
- })
- }
- // streak_panel = make_streak_panel();
- {
- W := 20
- pc.StreakPanel = door.Panel{Width: W}
- dateUpdate := func() string {
- format, ok := (*pc.Config)["date_format"]
- if !ok {
- format = "January 2"
- }
- txt := fmt.Sprintf("Playing: %s", ToTime(pc.Play_day).Format(format))
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.StreakPanel.Lines = append(pc.StreakPanel.Lines,
- door.Line{Text: dateUpdate(),
- UpdateF: dateUpdate,
- RenderF: svRender,
- })
- currentUpdate := func() string {
- txt := fmt.Sprintf("Current Streak: %d", pc.Current_streak)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.StreakPanel.Lines = append(pc.StreakPanel.Lines,
- door.Line{Text: currentUpdate(),
- UpdateF: currentUpdate,
- RenderF: svRender,
- })
- handUpdate := func() string {
- txt := fmt.Sprintf("Hand Streak : %d", pc.Hand_streak)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.StreakPanel.Lines = append(pc.StreakPanel.Lines,
- door.Line{Text: handUpdate(),
- UpdateF: handUpdate,
- RenderF: svRender,
- })
- longestUpdate := func() string {
- txt := fmt.Sprintf("Longest Streak: %d", pc.Best_streak)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- // TODO:
- // Add: This Month and This Hand values
- // pc.Month_streak, pc.Hand_streak
- pc.StreakPanel.Lines = append(pc.StreakPanel.Lines,
- door.Line{Text: longestUpdate(),
- UpdateF: longestUpdate,
- RenderF: svRender,
- })
- }
- // left_panel = make_left_panel();
- {
- W := 13
- pc.LeftPanel = door.Panel{Width: W}
- leftUpdate := func() string {
- txt := fmt.Sprintf("Cards left:%d", 51-pc.Play_card)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.LeftPanel.Lines = append(pc.LeftPanel.Lines,
- door.Line{Text: leftUpdate(),
- UpdateF: leftUpdate,
- RenderF: svRender,
- })
- }
- // cmd_panel = make_command_panel();
- {
- W := 76
- pc.CmdPanel = door.Panel{Width: W}
- var commands string
- if door.Unicode {
- commands = "[4/\u25c4] Left [6/\u25ba] Right [Space] Play Card [Enter] Draw [Q]uit [R]edraw [H]elp"
- commands += strings.Repeat(" ", W-len([]rune(commands)))
- } else {
- commands = "[4/\x11] Left [6/\x10] Right [Space] Play Card [Enter] Draw [Q]uit [R]edraw [H]elp"
- commands += strings.Repeat(" ", W-len(commands))
- }
- cmdRender := cmdLineRender(door.ColorText("BOLD YELLOW ON BLUE"),
- door.ColorText("BOLD CYAN ON BLUE"),
- door.ColorText("BOLD GREEN ON BLUE"))
- pc.CmdPanel.Lines = append(pc.CmdPanel.Lines,
- door.Line{Text: commands,
- RenderF: cmdRender})
- }
- // next_quit_panel = make_next_panel();
- {
- W := 50
- pc.NextQuitPanel = door.Panel{Width: W,
- Style: door.DOUBLE,
- BorderColor: door.ColorText("BOLD YELLOW ON BLUE"),
- }
- nextUpdate := func() string {
- var text string
- if pc.Select_card != -1 {
- text = "[C]ontinue this hand"
- }
- if pc.Hand < pc.Total_hands {
- text += " [N]ext Hand [Q]uit"
- } else {
- text += " [D]one [Q]uit"
- }
- text = " " + text + " "
- text += strings.Repeat(" ", W-len(text))
- return text
- }
- pc.NextQuitPanel.Lines = append(pc.NextQuitPanel.Lines,
- door.Line{Text: nextUpdate(),
- UpdateF: nextUpdate,
- RenderF: cmdLineRender(door.ColorText("BOLD YEL ON BLU"),
- door.ColorText("BOLD CYAN ON BLU"),
- door.ColorText("BOLD GREE ON BLUE"))})
- }
- // calendar = make_calendar();
- {
- pc.Calendar = door.Screen{}
- var month YMD = NewYMDFromTime(time.Now())
- month.First()
- var today_day int = month.Day()
- // FirstOfMonthDate(&month)
- var month_end YMD = month
- month_end.Last()
- // clear out
- /*
- for x := range pc.Calendar_day {
- pc.Calendar_day[x] = 0
- }
- // pc.Calendar_day_t = make([]int64, 31)
- pc.Calendar_day[0] = month // .Unix()
- */
- var First_Weekday int = int(ToTime(month).Weekday())
- var month_last_day = month_end.Day()
- /*
- var calendarDay DBDate = month
- for x := 1; x <= month_last_day; x++ {
- calendarDay.SetDay(x) // = DBDate((int(calendarDay) % 100) + x)
- pc.Calendar_day[x-1] = calendarDay
- }
- */
- // var month_end time.Time = month
- /*
- for {
- month_end = month_end.AddDate(0, 0, 1)
- NormalizeDate(&month_end)
- if month_end.Day() == 1 {
- break
- } else {
- pc.Calendar_day_t[month_end.Day()-1] = month_end.Unix()
- month_last_day = month_end.Day()
- }
- }
- */
- // clear out
- for x := range pc.Calendar_panel_days {
- pc.Calendar_panel_days[x] = 0
- }
- // pc.Calendar_panel_days = make([]int, 6*7)
- var row int = 0
- for x := 0; x < month_last_day; x++ {
- var dow int = (x + First_Weekday) % 7
- if x != 0 && dow == 0 {
- row++
- }
- pc.Calendar_panel_days[row*7+dow] = x + 1
- }
- // clear out
- for x := range pc.Calendar_day_status {
- pc.Calendar_day_status[x] = 0
- }
- // pc.Calendar_day_status = make([]int, 31)
- last_played := pc.DB.WhenPlayed()
- for played, hands := range last_played {
- if played >= month {
- // Ok, it is within the range
- var played_day int = played.Day()
- if hands < pc.Total_hands {
- pc.Calendar_day_status[played_day-1] = 1
- } else {
- pc.Calendar_day_status[played_day-1] = 2
- }
- }
- }
- // Get play_days_ahead from config
- var play_days_ahead int = 0
- if playdays, has := (*pc.Config)["play_days_ahead"]; has {
- play_days_ahead, _ = strconv.Atoi(playdays)
- }
- // Mark all days ahead as NNY.
- for d := 0; d < 31; d++ {
- if today_day+play_days_ahead-1 < d {
- pc.Calendar_day_status[d] = 3
- }
- }
- // Get current month as string
- var current string = strings.ToUpper(CurrentMonth(ToTime(month)))
- if len(current) < 6 {
- current = " " + current + " "
- }
- // FUTURE: Replace this with TDF rendering of Month.
- // make_month
- var MonthPanel door.Panel = door.Panel{X: 3,
- Y: 3,
- Width: 3,
- Style: door.DOUBLE,
- BorderColor: door.ColorText("BOLD YELLOW ON BLACK"),
- }
- for _, c := range current {
- MonthPanel.Lines = append(MonthPanel.Lines,
- door.Line{Text: fmt.Sprintf(" %c ", c)})
- }
- pc.Calendar.AddPanel(MonthPanel)
- // make_weekday
- var WeekdayPanel door.Panel = door.Panel{X: 8,
- Y: 3,
- Width: 41,
- Style: door.DOUBLE,
- BorderColor: door.ColorText("BOLD CYAN ON BLACK"),
- }
- WeekdayPanel.Lines = append(WeekdayPanel.Lines,
- door.Line{Text: " SUN MON TUE WED THU FRI SAT "})
- pc.Calendar.AddPanel(WeekdayPanel)
- // make_calendar_panel
- var CalendarPanel door.Panel
- {
- W := 41
- CalendarPanel = door.Panel{Width: W,
- Style: door.DOUBLE,
- BorderColor: door.ColorText("CYAN ON BLACK")}
- calendarRender := func(text string) string {
- // var result string
- // var lastColor string
- result := door.Render{Line: text}
- digits := door.ColorText("CYAN ON BLACK")
- digits_play := door.ColorText("BOLD CYAN ON BLACK")
- spaces := door.ColorText("WHITE ON BLACK")
- open := door.ColorText("BOLD GREEN ON BLACK")
- hands := door.ColorText("BOLD YELLOW ON BLACK")
- full := door.ColorText("RED ON BLACK")
- nny := door.ColorText("BOLD BLACK ON BLACK")
- for days := 0; days < 7; days++ {
- var dayText string
- if days == 0 {
- result.Append(spaces, 1)
- }
- dayText = text[1+days*6 : (1+days*6)+3]
- // if dayText[1] == ' ' {
- if dayText[0] == ' ' {
- result.Append(spaces, 3)
- } else {
- // Something is here
- cday := dayText[2]
- if cday == 'o' || cday == 'h' {
- result.Append(digits_play, 2)
- } else {
- result.Append(digits, 2)
- }
- switch cday {
- case 'o':
- result.Append(open, 1)
- case 'h':
- result.Append(hands, 1)
- case 'x':
- result.Append(full, 1)
- case 'u':
- result.Append(nny, 1)
- }
- }
- if days == 6 {
- result.Append(spaces, 1)
- } else {
- result.Append(spaces, 3)
- }
- }
- return result.Result
- }
- for row := 0; row < 6; row++ {
- // Do this, or it doesn't get captured correctly.
- _row := row
- // _pc := pc
- calendarUpdate := func() string {
- var text string
- for d := 0; d < 7; d++ {
- text += " "
- v := pc.Calendar_panel_days[(_row*7)+d]
- if v == 0 {
- text += " "
- } else {
- text += fmt.Sprintf("%-2d", v)
- status := pc.Calendar_day_status[v-1]
- switch status {
- case 0:
- text += "o"
- case 1:
- text += "h"
- case 2:
- text += "x"
- case 3:
- text += "u"
- }
- }
- if d == 6 {
- text += " "
- } else {
- text += " "
- }
- }
- return text
- }
- log.Printf("line %d: [%s]\n", row, calendarUpdate())
- CalendarPanel.Lines = append(CalendarPanel.Lines,
- door.Line{Text: calendarUpdate(),
- UpdateF: calendarUpdate,
- RenderF: calendarRender})
- }
- }
- CalendarPanel.X = 8
- CalendarPanel.Y = 6
- pc.Calendar.AddPanel(CalendarPanel)
- }
- // end make_calendar
- }
- func (pc *PlayCards) Play() rune {
- // this defaults (for now) to playing today (if unplayed).
- // Otherwise display calendar.
- pc.Play_day = NewYMDFromTime(time.Now())
- // NormalizeDate(&pc.Play_day)
- // pc.Play_day_t = pc.Play_day.Unix()
- played := pc.DB.HandsPlayedOnDay(pc.Play_day)
- log.Printf("HandsPlayedOnDay(%d), %d", pc.Play_day, played)
- var r rune
- if played == 0 {
- pc.Door.Write(door.CRNL + door.Reset + "Let's play today..." + door.CRNL)
- time.Sleep(time.Second * time.Duration(2))
- pc.Hand = 1
- r = pc.PlayCards()
- if r != 'D' {
- return r
- }
- } else {
- if played < pc.Total_hands {
- // let's finish today...
- pc.Door.Write(door.CRNL + door.Reset + "Let's finish today..." + door.CRNL)
- time.Sleep(time.Second * time.Duration(2))
- pc.Hand = played + 1
- r = pc.PlayCards()
- if r != 'D' {
- return r
- }
- }
- }
- CALENDAR_UPDATE:
- // pc.UpdateCalendarDays()
- month_t := pc.Play_day // pc.Calendar_day[0]
- month_t.SetDay(1)
- last_played := pc.DB.WhenPlayed()
- for played, hands := range last_played {
- if played >= month_t {
- // Ok, it is within the range
- var played_day int = played.Day()
- log.Printf("update: month_unix %d, played %d, hands %d (total %d)\n",
- month_t, played_day, hands, pc.Total_hands)
- if hands < pc.Total_hands {
- pc.Calendar_day_status[played_day-1] = 1
- } else {
- pc.Calendar_day_status[played_day-1] = 2
- }
- }
- }
- // log.Printf("%#v\n", pc.Calendar)
- log.Println("Calendar.Update()")
- pc.Calendar.Update()
- log.Println("Calendar.Output()")
- pc.Door.Write(pc.Calendar.Output())
- var has_playable_day bool = false
- for x := 0; x < 31; x++ {
- status := pc.Calendar_day_status[x]
- if status == 0 || status == 1 {
- has_playable_day = true
- break
- }
- }
- if !has_playable_day {
- pc.Door.Write(door.CRNL + "Sorry, there are no days available to play." + door.CRNL)
- r = press_a_key(pc.Door)
- if r < 0 {
- return r
- } else {
- return 'Q'
- }
- }
- log.Println("Choose Day")
- pc.Door.Write(door.CRNL + "Please choose a day : " + door.SavePos)
- AGAIN:
- log.Println("Input")
- var toplay string = pc.Door.Input(3)
- log.Printf("Input was: %s\n", toplay)
- pc.Door.Write(door.RestorePos)
- var number int
- var err error
- number, err = strconv.Atoi(toplay)
- if err != nil {
- number = 0
- }
- if number == 0 {
- return ' '
- }
- var status int
- if number <= 31 {
- status = pc.Calendar_day_status[number-1]
- if status == 0 {
- // play full day
- pc.Hand = 1
- pc.Play_day.SetDay(number) // = pc.Calendar_day[number-1]
- // pc.Play_day = time.Unix(pc.Play_day_t, 0)
- r = pc.PlayCards()
- if r == 'D' {
- goto CALENDAR_UPDATE
- }
- return r
- }
- if status == 1 {
- // Play half day
- pc.Play_day.SetDay(number) // = pc.Calendar_day[number-1]
- // pc.Play_day = time.Unix(pc.Play_day_t, 0)
- played := pc.DB.HandsPlayedOnDay(pc.Play_day)
- if played < pc.Total_hands {
- pc.Hand = played + 1
- r = pc.PlayCards()
- if r == 'D' {
- goto CALENDAR_UPDATE
- }
- return r
- }
- }
- goto AGAIN
- }
- return ' '
- }
- func (pc *PlayCards) PlayCards() rune {
- pc.InitValues()
- var game_width int
- var game_height int = 20
- // pos := &CardPos[27]
- game_width = CardPos[27].X + 5
- MX := door.Width
- MY := door.Height
- pc.Off_X = (MX - game_width) / 2
- pc.Off_Y = (MY - game_height) / 2
- // _ = off_x
- // We can now position things properly centered
- pc.SpaceAceTriPeaks.X = (MX - pc.SpaceAceTriPeaks.Width) / 2
- pc.SpaceAceTriPeaks.Y = pc.Off_Y
- pc.Off_Y += 3
- currentDefault := pc.DB.GetSetting("DeckColor", "ALL")
- Next_Hand:
- deck_color := StringToANSIColor(currentDefault)
- pc.DeckPanel.SetBackColor(deck_color)
- pc.Play_card = 28
- pc.Select_card = 23
- pc.Score = 0
- pc.Current_streak = 0
- pc.Hand_streak = 0
- // Don't touch Month_streak.
- // Use play day to seed RNG
- {
- // Secret Squirrel method of seeding the RNG
- seed_seq := make([]byte, 0)
- for _, seed := range pc.Seeds {
- ba := Int32toByteArray(seed)
- seed_seq = append(seed_seq, ba[:]...)
- // sha1.Sum(ba[:])
- }
- pd := Int64toByteArray(int64(pc.Play_day))
- seed_seq = append(seed_seq, pd[:]...)
- // We also need the hand # that we're playing.
- seed_seq = append(seed_seq, byte(pc.Hand))
- result := sha1.Sum(seed_seq)
- var seed int64 = int64(binary.BigEndian.Uint64(result[0:8]))
- pc.RNG.Seed(seed)
- // I'm seeing changes in the seed_seq bytes, but the seed is the same number.
- // log.Printf("%#v\nSeed %d\nLen %d\nresult %#v\n", seed_seq, seed, len(seed_seq), result)
- pc.Deck = ShuffleCards(pc.RNG, 1)
- pc.State = MakeCardStates(1)
- }
- // Position the panels
- {
- off_yp := pc.Off_Y + 11
- left_panel_x := CardPos[18].X
- right_panel_x := CardPos[15].X
- pc.ScorePanel.X = left_panel_x + pc.Off_X
- pc.ScorePanel.Y = off_yp
- pc.StreakPanel.X = right_panel_x + pc.Off_X
- pc.StreakPanel.Y = off_yp
- pc.CmdPanel.X = left_panel_x + pc.Off_X
- pc.CmdPanel.Y = off_yp + 5
- next_off_x := (MX - pc.NextQuitPanel.Width) / 2
- pc.NextQuitPanel.X = next_off_x
- pc.NextQuitPanel.Y = CardPos[10].Y + pc.Off_Y
- }
- var Dealing bool = true
- var r rune
- var ex door.Extended
- var err error
- pc.Redraw(Dealing)
- Dealing = false
- pc.LeftPanel.Update()
- pc.Door.Write(door.Reset)
- var c *door.Panel
- var in_game bool = true
- var save_streak bool = false
- var waiting int = 0
- for in_game {
- var output string
- output = pc.ScorePanel.Update()
- if output != "" {
- pc.Door.Write(output)
- {
- // Redisplay Mark / Selected Card
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output())
- }
- }
- if save_streak {
- save_streak = false
- pc.DB.SetSetting("best_streak", strconv.Itoa(pc.Best_streak))
- }
- waiting = 0
- for waiting < int(door.Inactivity) {
- r, ex, err = pc.Door.WaitKey(time.Second)
- if err == door.ErrTimeout {
- // TIMEOUT is expected here
- waiting++
- output = pc.ScorePanel.Update()
- if output != "" {
- pc.Door.Write(output)
- {
- // Redisplay Mark / Selected Card
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output())
- }
- }
- } else {
- break
- }
- }
- if err == nil {
- // Not a timeout
- /*
- if r < 0x1000 {
- // not a function key
- r = int(unicode.ToUpper(rune(r)))
- }
- */
- switch ex {
- case door.LEFT_ARROW:
- r = '4'
- case door.RIGHT_ARROW:
- r = '6'
- }
- switch r {
- case '\x0d':
- // Next Card
- var updateStreakPanel bool = false
- if pc.Current_streak > pc.Hand_streak {
- pc.Hand_streak = pc.Current_streak
- updateStreakPanel = true
- }
- if pc.Current_streak > pc.Month_streak {
- pc.Month_streak = pc.Current_streak
- updateStreakPanel = true
- }
- if pc.Current_streak > pc.Best_streak {
- pc.Best_streak = pc.Current_streak
- save_streak = true
- updateStreakPanel = true
- // pc.Door.Write(pc.StreakPanel.Update())
- }
- if updateStreakPanel {
- pc.Door.Write(pc.StreakPanel.Update())
- }
- if pc.Play_card < 51 {
- pc.Play_card++
- pc.Current_streak = 0
- pc.Door.Write(pc.StreakPanel.Update())
- pc.Door.Write(pc.LeftPanel.Update())
- // Deal the next card
- if pc.Play_card == 51 {
- // out of cards
- cpos := &CardPos[29]
- c = &pc.DeckPanel.Backs[0]
- c.X = cpos.X + pc.Off_X
- c.Y = cpos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- cpos := &CardPos[28]
- c = &pc.DeckPanel.Cards[pc.Deck[pc.Play_card]]
- c.X = cpos.X + pc.Off_X
- c.Y = cpos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- case 'R', 'r':
- pc.Redraw(false)
- case 'Q', 'q':
- // Possibly prompt here for [N]ext hand or [Q]uit
- // Odd: It seems like streaks should be tracked in
- // one place -- when we play a card...
- if pc.Current_streak > pc.Best_streak {
- pc.Best_streak = pc.Current_streak
- pc.Door.Write(pc.StreakPanel.Update())
- }
- pc.NextQuitPanel.Update()
- pc.Door.Write(pc.NextQuitPanel.Output())
- if pc.State[26] == 2 {
- pc.Door.Write(door.ColorText("BLACK"))
- } else {
- pc.Door.Write(door.Reset)
- }
- if pc.Hand < pc.Total_hands {
- r = pc.Door.GetOneOf("CNQ")
- } else {
- r = pc.Door.GetOneOf("CDQ")
- }
- if r == 'C' {
- // Continue
- pc.Redraw(false)
- } else {
- if r == 'D' || r == 'Q' {
- if pc.Score >= 50 {
- pc.DB.SaveScore(NewYMDFromTime(time.Now()), pc.Play_day, pc.Hand, 0, pc.Hand_streak, pc.Score)
- }
- in_game = false
- } else {
- if r == 'N' {
- pc.DB.SaveScore(NewYMDFromTime(time.Now()), pc.Play_day, pc.Hand, 0, pc.Hand_streak, pc.Score)
- pc.Hand++
- goto Next_Hand
- }
- }
- }
- case ' ', '5':
- if CanPlay(pc.Deck[pc.Select_card],
- pc.Deck[pc.Play_card]) {
- pc.Current_streak++
- pc.Door.Write(pc.StreakPanel.Update())
- pc.Score += 10
- if pc.Current_streak > 1 {
- pc.Score += pc.Current_streak * 5
- }
- pc.Door.Write(pc.ScorePanel.Update())
- // Play card
- pc.State[pc.Select_card] = 2
- {
- // Swap out the select card with the play card
- temp := pc.Deck[pc.Select_card]
- pc.Deck[pc.Select_card] = pc.Deck[pc.Play_card]
- pc.Deck[pc.Play_card] = temp
- // Select card is invalidated here. Find new card.
- check := Unblocks(pc.Select_card)
- var left bool = false
- var right bool = false
- for _, chk := range check {
- blk := Blocks[chk]
- if blk[0] == pc.Select_card {
- right = true
- }
- if blk[1] == pc.Select_card {
- left = true
- }
- }
- cardback_color := pc.DeckPanel.Backs[1].Lines[0].DefaultColor
- pc.Door.Write(RemoveCard(pc.Select_card, cardback_color, pc.Off_X, pc.Off_Y, left, right))
- // Redraw play card #28 ("old" select_card)
- cpos := &CardPos[28]
- c = &pc.DeckPanel.Cards[pc.Deck[pc.Play_card]]
- c.X = cpos.X + pc.Off_X
- c.Y = cpos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- // Did we unhide a card?
- var new_card_shown int = -1
- if len(check) > 0 {
- for _, chk := range check {
- blk := Blocks[chk]
- if pc.State[blk[0]] == 2 &&
- pc.State[blk[1]] == 2 {
- pc.State[chk] = 1
- cpos := &CardPos[chk]
- c = &pc.DeckPanel.Cards[pc.Deck[chk]]
- c.X = cpos.X + pc.Off_X
- c.Y = cpos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- new_card_shown = chk
- }
- }
- } else {
- // top card cleared
- cpos := &CardPos[pc.Select_card]
- pc.Door.Write(door.Goto(cpos.X+pc.Off_X, cpos.Y+pc.Off_Y) + Bonus())
- pc.Score += 100
- pc.State[pc.Select_card] = 3 // Handle in "redraw"
- pc.Door.Write(pc.ScorePanel.Update())
- }
- // Find new number for select_card.
- if new_card_shown != -1 {
- pc.Select_card = new_card_shown
- } else {
- new_select := FindClosestActiveCard(&pc.State, pc.Select_card)
- if new_select != -1 {
- pc.Select_card = new_select
- } else {
- log.Println("Winner")
- pc.Select_card = -1
- pc.Score += 15 * (51 - pc.Play_card)
- pc.Door.Write(pc.ScorePanel.Update())
- // Save Score
- pc.DB.SaveScore(NewYMDFromTime(time.Now()), pc.Play_day, pc.Hand, 1, pc.Hand_streak, pc.Score)
- pc.NextQuitPanel.Update()
- pc.Door.Write(pc.NextQuitPanel.Output())
- if pc.State[26] == 2 {
- pc.Door.Write(door.ColorText("BLACK"))
- } else {
- pc.Door.Write(door.Reset)
- }
- if pc.Hand < pc.Total_hands {
- r = pc.Door.GetOneOf("NQ")
- } else {
- r = pc.Door.GetOneOf("DQ")
- }
- if r == 'N' {
- pc.Hand++
- goto Next_Hand
- }
- in_game = false
- // if r == 'D' ?
- if r == 'Q' {
- // this seemed odd. We quit the game ?
- r = 'Q'
- }
- break
- }
- }
- // Update the select_card marker
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output() + door.Reset)
- }
- }
- case '4':
- var new_select int = FindNextActiveCard(true, &pc.State, pc.Select_card)
- if new_select >= 0 {
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[0]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output())
- pc.Select_card = new_select
- Pos = &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output() + door.Reset)
- }
- case '6':
- var new_select int = FindNextActiveCard(false, &pc.State, pc.Select_card)
- if new_select >= 0 {
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[0]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output())
- pc.Select_card = new_select
- Pos = &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output() + door.Reset)
- }
- }
- } else {
- in_game = false
- }
- }
- return r
- }
- func (pc *PlayCards) Redraw(Dealing bool) {
- // stars.display()
- pc.Door.Write(door.Clrscr + door.Reset)
- pc.Door.Write(pc.SpaceAceTriPeaks.Output())
- var c *door.Panel
- {
- // Step 1: Draw the deck "source"
- pos := &CardPos[29]
- if pc.Play_card == 51 {
- // out of cards
- pos.Level = 0
- }
- c = &pc.DeckPanel.Backs[pos.Level]
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.LeftPanel.X = pos.X + pc.Off_X
- pc.LeftPanel.Y = pos.Y + pc.Off_Y + 3 // const height see deck
- pc.ScorePanel.Update()
- pc.LeftPanel.Update()
- pc.StreakPanel.Update()
- pc.CmdPanel.Update()
- pc.Door.Write(pc.ScorePanel.Output())
- pc.Door.Write(pc.LeftPanel.Output())
- pc.Door.Write(pc.StreakPanel.Output())
- pc.Door.Write(pc.CmdPanel.Output())
- pc.Door.Write(c.Output())
- if Dealing {
- time.Sleep(time.Second)
- }
- }
- var x_max int = 29
- if Dealing {
- x_max = 28
- }
- for x := 0; x < x_max; x++ {
- pos := &CardPos[x]
- if Dealing {
- time.Sleep(time.Duration(75) * time.Millisecond)
- }
- // log.Printf("Redraw(%d, %d)", x, pos.Level)
- if Dealing {
- c = &pc.DeckPanel.Backs[pos.Level]
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- } else {
- switch pc.State[x] {
- case 0:
- c = &pc.DeckPanel.Backs[pos.Level]
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- case 1:
- if x == 28 {
- c = &pc.DeckPanel.Cards[pc.Deck[pc.Play_card]]
- } else {
- c = &pc.DeckPanel.Cards[pc.Deck[x]]
- }
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- case 2:
- // no card to draw.
- case 3:
- // peak cleared, draw bonus
- var output string = door.Goto(pos.X+pc.Off_X, pos.Y+pc.Off_Y)
- output += Bonus()
- pc.Door.Write(output)
- }
- }
- }
- if Dealing {
- for x := 18; x < 29; x++ {
- pc.State[x] = 1
- // CardPos[x] X Y Level
- Pos := &CardPos[x]
- time.Sleep(time.Duration(200) * time.Millisecond)
- c = &pc.DeckPanel.Cards[pc.Deck[x]]
- c.X = Pos.X + pc.Off_X
- c.Y = Pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- }
- {
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X + 2
- c.Y = Pos.Y + pc.Off_Y + 2
- pc.Door.Write(c.Output())
- }
- }
- func Bonus() string {
- return door.ColorText("BOLD YELLOW") + "BONUS"
- }
- func (pc *PlayCards) UpdateCalendarDays() {
- }
|