package door import ( "bytes" "fmt" "strings" "time" ) /* WOPR [ GAME ] [ TIME ELAPSED ] [ XX HRS ] [ XX MIN XX SEC ] [■ ] -> [ GAME ] [ TIME REMAINING ] [ XX HRS ] [ XX MIN XX SEC ] [ ■] <- Border SINGLE Ok, Width = 16 1000 / 16 = 62.5 ms = 62500 us Width 16 (at pos 1, update time/sec increment) Black on Cyan */ type WOPR struct { ElapsedPanel Panel Elapsed time.Time ElapsedD time.Duration RemainingPanel Panel Remaining time.Time RemainingD time.Duration Color string Index int Ticker *time.Ticker StopIt chan bool } func (w *WOPR) Clear() string { return w.ElapsedPanel.Clear() + w.RemainingPanel.Clear() } // Initialize, Set X, Y on Panels, Animate() // Initialize, and create panels func (w *WOPR) Init(elapsed time.Time, remaining time.Time, color string) { if color == "" { color = ColorText("BLACK ON CYAN") } w.Elapsed = elapsed w.Remaining = remaining w.Index = 0 w.ElapsedPanel = Panel{Width: 16, BorderColor: color, Style: SINGLE} w.ElapsedPanel.Lines = append(w.ElapsedPanel.Lines, Line{Text: " GAME "}) w.ElapsedPanel.Lines = append(w.ElapsedPanel.Lines, Line{Text: " TIME ELAPSED "}) var ehour Line = Line{} ehour.UpdateF = func() string { var hours int = int(w.ElapsedD.Hours()) return fmt.Sprintf(" %02d HRS ", hours%100) } ehour.Text = ehour.UpdateF() w.ElapsedPanel.Lines = append(w.ElapsedPanel.Lines, ehour) var eminsec Line = Line{} eminsec.UpdateF = func() string { var mins int = int(w.ElapsedD.Minutes()) % 60 var secs int = int(w.ElapsedD.Seconds()) % 60 return fmt.Sprintf(" %02d MIN %02d SEC ", mins, secs) } eminsec.Text = eminsec.UpdateF() w.ElapsedPanel.Lines = append(w.ElapsedPanel.Lines, eminsec) var eanimate Line = Line{} eanimate.UpdateF = func() string { // Left to Right if Unicode { var buffer []rune = []rune(strings.Repeat(" ", 16)) buffer[w.Index] = '\u25a0' return string(buffer) } else { var buffer []byte = bytes.Repeat([]byte(" "), 16) buffer[w.Index] = '\xfe' return string(buffer) } } eanimate.Text = eanimate.UpdateF() w.ElapsedPanel.Lines = append(w.ElapsedPanel.Lines, eanimate) w.RemainingPanel = Panel{Width: 16, BorderColor: color, Style: SINGLE} w.RemainingPanel.Lines = append(w.RemainingPanel.Lines, Line{Text: " GAME "}) w.RemainingPanel.Lines = append(w.RemainingPanel.Lines, Line{Text: " TIME REMAINING "}) var rhour Line = Line{} rhour.UpdateF = func() string { var hours int = int(w.RemainingD.Hours()) return fmt.Sprintf(" %02d HRS ", hours%100) } rhour.Text = rhour.UpdateF() w.RemainingPanel.Lines = append(w.RemainingPanel.Lines, rhour) var rminsec Line = Line{} rminsec.UpdateF = func() string { var mins int = int(w.RemainingD.Minutes()) % 60 var secs int = int(w.RemainingD.Seconds()) % 60 return fmt.Sprintf(" %02d MIN %02d SEC ", mins, secs) } rminsec.Text = rminsec.UpdateF() w.RemainingPanel.Lines = append(w.RemainingPanel.Lines, rminsec) var ranimate Line = Line{} ranimate.UpdateF = func() string { // Left to Right if Unicode { var buffer []rune = []rune(strings.Repeat(" ", 16)) buffer[15-w.Index] = '\u25a0' return string(buffer) } else { var buffer []byte = bytes.Repeat([]byte(" "), 16) buffer[15-w.Index] = '\xfe' return string(buffer) } } ranimate.Text = ranimate.UpdateF() w.RemainingPanel.Lines = append(w.RemainingPanel.Lines, ranimate) } func (w *WOPR) Inc() { w.Index++ if w.Index == 16 { w.Index = 0 w.ElapsedPanel.Update() w.RemainingPanel.Update() w.RemainingD = time.Duration(w.RemainingD.Seconds()-1) * time.Second w.ElapsedD = time.Duration(w.ElapsedD.Seconds()+1) * time.Second } } func (w *WOPR) Animate(d *Door) { // til := time.Now().UnixNano() % int64(time.Second) // w.Index = int((til / int64(time.Microsecond)) / 62500) // either put the sync sleep in the go routine, or sleep and sync Index. // time.Sleep(time.Duration(int64(time.Second) - til)) // time.Now().UnixMilli()%1000) * time.Millisecond) // time.Second / 16 // w.Ticker = time.NewTicker(time.Microsecond * time.Duration(62500)) // w.Index = 0 // Convert time.Time to time.Duration // This gives us consistency when resuming. w.ElapsedD = time.Since(w.Elapsed) w.RemainingD = time.Until(w.Remaining) w.StopIt = make(chan bool) go func(d *Door) { // til := time.Now().UnixNano() % int64(time.Second) sec16 := int64(time.Second) / 16 // tilms := til % sec16 w.Index = 0 // int(til / sec16) // log.Printf("til: %d, sec: %d, w.Index: %d\n", til, sec16, w.Index) // either put the sync sleep in the go routine, or sleep and sync Index. // time.Sleep(time.Second - time.Duration(til)) // sec16 - (til % sec16))) //int64(time.Second) - til)) // time.Now().UnixMilli()%1000) * time.Millisecond) // time.Second / 16 w.Ticker = time.NewTicker(time.Duration(sec16)) // time.Microsecond * time.Duration(62500)) var output string for { select { case <-w.StopIt: return case <-w.Ticker.C: w.ElapsedPanel.Update() w.RemainingPanel.Update() output = SavePos + w.ElapsedPanel.Output() + w.RemainingPanel.Output() + RestorePos if !d.Disconnect() { d.Write(output) } else { w.Ticker.Stop() return } w.Inc() } } }(d) } func (w *WOPR) Stop() { w.Ticker.Stop() w.StopIt <- true }