package door import ( "bytes" ) type SpinRite struct { Width uint8 // Width of the animation (must be odd) Length uint8 // Width of the worm (must be odd) Color []byte // Color (default CYAN ON BLUE) OutputB []byte // Output CP437/bytes (Width) OutputR []rune // Output Unicode (Width) Buffer []uint8 // Output calculate buffer (Width) Runes []rune // blank, center, top, bottom, both Bytes []byte // blank, center, top, bottom, both CenterPos uint8 // Center Position (Width - 1) / 2 StartPos uint8 // Starting Position (Length -1) / 2 Index uint8 // Index of current iteration output *bytes.Buffer // Buffer for output } /* Other center character options: · ∞ We default to ∞ [ █████ ] [ ▄▄███▀▀ ] [ ▄▄▄▄█▀▀▀▀ ] [ ▄▄▄▄▄•▀▀▀▀▀ ] [▄▄▄▄▄ • ▀▀▀▀▀] [█▄▄▄ • ▀▀▀█] [██▄ • ▀██] [██▀ • ▄██] [█▀▀▀ • ▄▄▄█] [█▀▀▀▀ • ▄▄▄▄█] [ ▀▀▀▀▀•▄▄▄▄▄ ] [ ▀▀▀▀█▄▄▄▄ ] [ ▀▀███▄▄ ] */ /* 0 = Blank 1 = Center Character 2 = Top 3 = Bottom 4 = Full Block */ func SpinRiteInit(width uint8, length uint8, color []byte) SpinRite { if len(color) == 0 { color = ColorText("CYAN ON BLUE") } var center uint8 = ((width - 1) / 2) var start uint8 = ((length - 1) / 2) var result SpinRite = SpinRite{Width: width, Length: length, Color: color, CenterPos: center, StartPos: start, Buffer: make([]uint8, width), Index: 0, output: &bytes.Buffer{}} if Unicode { result.OutputR = make([]rune, width) result.Runes = []rune{' ', '\u221e', '\u2580', '\u2584', '\u2588'} } else { result.OutputB = make([]byte, width) result.Bytes = []byte{' ', 0xec, 0xdf, 0xdc, 0xdb} } return result } func (sr *SpinRite) PosToIndex(pos int8, top bool) (index uint8, level bool) { if top { if pos >= int8(sr.Width) { // wrap around level = !top idx := int8(sr.Width) + (int8(sr.Width) - (pos + 1)) index = uint8(idx) } else { level = top index = uint8(pos) } } else { // bottom if pos < 0 { level = !top pos++ index = uint8(-pos) } else { level = top index = uint8(pos) } } return } func (sr *SpinRite) Calculate() { for i := range sr.Buffer { sr.Buffer[i] = 0 } sr.Buffer[sr.CenterPos] = 1 // [ S C s ] var top int8 = int8(sr.CenterPos) - int8(sr.StartPos) + int8(sr.Index) var bottom int8 = int8(sr.CenterPos) + int8(sr.StartPos) - int8(sr.Index) var l int8 for l = 0; l < int8(sr.Length); l++ { var index uint8 var level bool index, level = sr.PosToIndex(top+l, true) // log.Println("TOP", l, top+l, index, level) if level { sr.Buffer[index] |= 0x02 } else { sr.Buffer[index] |= 0x04 } index, level = sr.PosToIndex(bottom-l, false) // log.Println("BOT", l, bottom-l, index, level) if level { sr.Buffer[index] |= 0x02 } else { sr.Buffer[index] |= 0x04 } } // log.Println("Index", sr.Index, "Buffer", sr.Buffer) var reset bool = true // Convert from buffer to output if Unicode { for l = 0; l < int8(sr.Width); l++ { switch sr.Buffer[l] { case 0: sr.OutputR[l] = sr.Runes[0] case 1: sr.OutputR[l] = sr.Runes[1] reset = false case 2, 3: sr.OutputR[l] = sr.Runes[2] reset = false case 4, 5: sr.OutputR[l] = sr.Runes[3] reset = false case 6, 7: sr.OutputR[l] = sr.Runes[4] } } } else { for l = 0; l < int8(sr.Width); l++ { switch sr.Buffer[l] { case 0: sr.OutputB[l] = sr.Bytes[0] case 1: sr.OutputB[l] = sr.Bytes[1] reset = false case 2, 3: sr.OutputB[l] = sr.Bytes[2] reset = false case 4, 5: sr.OutputB[l] = sr.Bytes[3] reset = false case 6, 7: sr.OutputB[l] = sr.Bytes[4] } } } if reset { // log.Println("RESET") sr.Index = 0 } } func (sr *SpinRite) Output() []byte { // var result string sr.output.Reset() // sr.Result.Reset() sr.output.Write(sr.Color) sr.Calculate() if Unicode { // result = string(sr.OutputR) for _, r := range sr.OutputR { sr.output.WriteRune(r) } // Use the above, benchmark. // sr.output.WriteString(string(sr.OutputR)) } else { //result = string(sr.OutputB) sr.output.Write(sr.OutputB) } sr.Index++ // return sr.Color + result return sr.output.Bytes() } type SpinRiteMsg struct { SpinRite Messages []string MsgIndex int Next bool } func SpinRiteMsgInit(width uint8, length uint8, color []byte, messages []string) SpinRiteMsg { var result SpinRiteMsg = SpinRiteMsg{SpinRite: SpinRiteInit(width, length, color)} if Unicode { result.Runes[1] = result.Runes[0] } else { result.SpinRite.Bytes[1] = result.SpinRite.Bytes[0] } result.Messages = messages result.MsgIndex = 0 result.Next = false return result } func (sr *SpinRiteMsg) Output() []byte { sr.output.Reset() sr.Calculate() if sr.Next && sr.Index == 0 { sr.MsgIndex++ if sr.MsgIndex == len(sr.Messages) { sr.MsgIndex = 0 } } if sr.Index != 0 { sr.Next = true } // Place message var message string = sr.Messages[sr.MsgIndex] var msg []rune = []rune(message) var pos int = int(sr.CenterPos) // Bug: If we're changing to next message (sr.Next == True) ... but the // message is > SpinRite.Length, it shows the text beyond what it should. var texthalf int = StringLen([]byte(message)) / 2 // Place text center, outwards. Stopping if there's no space. for i := 0; i < texthalf+1; i++ { if Unicode { if sr.OutputR[pos+i] == ' ' { if texthalf+i < StringLen([]byte(message)) { sr.OutputR[pos+i] = []rune(msg)[texthalf+i] } } else { break } if i != 0 { if sr.OutputR[pos-i] == ' ' { sr.OutputR[pos-i] = []rune(msg)[texthalf-i] } else { break } } } else { if sr.OutputB[pos+i] == ' ' { if texthalf+i < StringLen([]byte(message)) { sr.OutputB[pos+i] = byte(msg[texthalf+i]) } } else { break } if i != 0 { if sr.OutputB[pos-i] == ' ' { sr.OutputB[pos-i] = byte(msg[texthalf-i]) } else { break } } } } /* for i := 0; i < len(msg); i++ { if Unicode { if sr.OutputR[pos+i] == ' ' { sr.OutputR[pos+i] = []rune(msg)[i] } } else { if sr.OutputB[pos+i] == ' ' { sr.OutputB[pos+i] = byte(msg[i]) } } } */ sr.output.Write(sr.Color) if Unicode { for _, r := range sr.OutputR { sr.output.WriteRune(r) } // result = string(sr.OutputR) } else { sr.output.Write(sr.OutputB) // result = string(sr.OutputB) } sr.Index++ // return sr.Color + result return sr.output.Bytes() }