spinrite.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. package door
  2. import "strings"
  3. type SpinRite struct {
  4. Width uint8 // Width of the animation (must be odd)
  5. Length uint8 // Width of the worm (must be odd)
  6. Color string // Color (default CYAN ON BLUE)
  7. OutputB []byte // Output CP437/bytes (Width)
  8. OutputR []rune // Output Unicode (Width)
  9. Buffer []uint8 // Output calculate buffer (Width)
  10. Runes []rune // blank, center, top, bottom, both
  11. Bytes []byte // blank, center, top, bottom, both
  12. CenterPos uint8 // Center Position (Width - 1) / 2
  13. StartPos uint8 // Starting Position (Length -1) / 2
  14. Index uint8 // Index of current iteration
  15. }
  16. /*
  17. Other center character options: · ∞
  18. We default to ∞
  19. [ █████ ]
  20. [ ▄▄███▀▀ ]
  21. [ ▄▄▄▄█▀▀▀▀ ]
  22. [ ▄▄▄▄▄•▀▀▀▀▀ ]
  23. [▄▄▄▄▄ • ▀▀▀▀▀]
  24. [█▄▄▄ • ▀▀▀█]
  25. [██▄ • ▀██]
  26. [██▀ • ▄██]
  27. [█▀▀▀ • ▄▄▄█]
  28. [█▀▀▀▀ • ▄▄▄▄█]
  29. [ ▀▀▀▀▀•▄▄▄▄▄ ]
  30. [ ▀▀▀▀█▄▄▄▄ ]
  31. [ ▀▀███▄▄ ]
  32. */
  33. /*
  34. 0 = Blank
  35. 1 = Center Character
  36. 2 = Top
  37. 3 = Bottom
  38. 4 = Full Block
  39. */
  40. func SpinRiteInit(width uint8, length uint8, color string) SpinRite {
  41. if color == "" {
  42. color = ColorText("CYAN ON BLUE")
  43. }
  44. var center uint8 = ((width - 1) / 2)
  45. var start uint8 = ((length - 1) / 2)
  46. var result SpinRite = SpinRite{Width: width,
  47. Length: length,
  48. Color: color,
  49. CenterPos: center,
  50. StartPos: start,
  51. Buffer: make([]uint8, width),
  52. Index: 0}
  53. if Unicode {
  54. result.OutputR = make([]rune, width)
  55. result.Runes = []rune{' ', '\u221e', '\u2580', '\u2584', '\u2588'}
  56. } else {
  57. result.OutputB = make([]byte, width)
  58. result.Bytes = []byte{' ', 0xec, 0xdf, 0xdc, 0xdb}
  59. }
  60. return result
  61. }
  62. func (sr *SpinRite) PosToIndex(pos int8, top bool) (index uint8, level bool) {
  63. if top {
  64. if pos >= int8(sr.Width) {
  65. // wrap around
  66. level = !top
  67. idx := int8(sr.Width) + (int8(sr.Width) - (pos + 1))
  68. index = uint8(idx)
  69. } else {
  70. level = top
  71. index = uint8(pos)
  72. }
  73. } else {
  74. // bottom
  75. if pos < 0 {
  76. level = !top
  77. pos++
  78. index = uint8(-pos)
  79. } else {
  80. level = top
  81. index = uint8(pos)
  82. }
  83. }
  84. return
  85. }
  86. func (sr *SpinRite) Calculate() {
  87. for i := range sr.Buffer {
  88. sr.Buffer[i] = 0
  89. }
  90. sr.Buffer[sr.CenterPos] = 1
  91. // [ S C s ]
  92. var top int8 = int8(sr.CenterPos) - int8(sr.StartPos) + int8(sr.Index)
  93. var bottom int8 = int8(sr.CenterPos) + int8(sr.StartPos) - int8(sr.Index)
  94. var l int8
  95. for l = 0; l < int8(sr.Length); l++ {
  96. var index uint8
  97. var level bool
  98. index, level = sr.PosToIndex(top+l, true)
  99. // log.Println("TOP", l, top+l, index, level)
  100. if level {
  101. sr.Buffer[index] |= 0x02
  102. } else {
  103. sr.Buffer[index] |= 0x04
  104. }
  105. index, level = sr.PosToIndex(bottom-l, false)
  106. // log.Println("BOT", l, bottom-l, index, level)
  107. if level {
  108. sr.Buffer[index] |= 0x02
  109. } else {
  110. sr.Buffer[index] |= 0x04
  111. }
  112. }
  113. // log.Println("Index", sr.Index, "Buffer", sr.Buffer)
  114. var reset bool = true
  115. // Convert from buffer to output
  116. if Unicode {
  117. for l = 0; l < int8(sr.Width); l++ {
  118. switch sr.Buffer[l] {
  119. case 0:
  120. sr.OutputR[l] = sr.Runes[0]
  121. case 1:
  122. sr.OutputR[l] = sr.Runes[1]
  123. reset = false
  124. case 2, 3:
  125. sr.OutputR[l] = sr.Runes[2]
  126. reset = false
  127. case 4, 5:
  128. sr.OutputR[l] = sr.Runes[3]
  129. reset = false
  130. case 6, 7:
  131. sr.OutputR[l] = sr.Runes[4]
  132. }
  133. }
  134. } else {
  135. for l = 0; l < int8(sr.Width); l++ {
  136. switch sr.Buffer[l] {
  137. case 0:
  138. sr.OutputB[l] = sr.Bytes[0]
  139. case 1:
  140. sr.OutputB[l] = sr.Bytes[1]
  141. reset = false
  142. case 2, 3:
  143. sr.OutputB[l] = sr.Bytes[2]
  144. reset = false
  145. case 4, 5:
  146. sr.OutputB[l] = sr.Bytes[3]
  147. reset = false
  148. case 6, 7:
  149. sr.OutputB[l] = sr.Bytes[4]
  150. }
  151. }
  152. }
  153. if reset {
  154. // log.Println("RESET")
  155. sr.Index = 0
  156. }
  157. }
  158. func (sr *SpinRite) Output() string {
  159. // var result string
  160. var result strings.Builder
  161. // sr.Result.Reset()
  162. result.WriteString(sr.Color)
  163. sr.Calculate()
  164. if Unicode {
  165. // result = string(sr.OutputR)
  166. /*
  167. for _, r := range sr.OutputR {
  168. result.WriteRune(r)
  169. }
  170. */
  171. result.WriteString(string(sr.OutputR))
  172. } else {
  173. //result = string(sr.OutputB)
  174. result.WriteString(string(sr.OutputB))
  175. }
  176. sr.Index++
  177. // return sr.Color + result
  178. return result.String()
  179. }
  180. type SpinRiteMsg struct {
  181. SpinRite
  182. Messages []string
  183. MsgIndex int
  184. Next bool
  185. }
  186. func SpinRiteMsgInit(width uint8, length uint8, color string, messages []string) SpinRiteMsg {
  187. var result SpinRiteMsg = SpinRiteMsg{SpinRite: SpinRiteInit(width, length, color)}
  188. if Unicode {
  189. result.Runes[1] = result.Runes[0]
  190. } else {
  191. result.SpinRite.Bytes[1] = result.SpinRite.Bytes[0]
  192. }
  193. result.Messages = messages
  194. result.MsgIndex = 0
  195. result.Next = false
  196. return result
  197. }
  198. func (sr *SpinRiteMsg) Output() string {
  199. var result string
  200. sr.Calculate()
  201. if sr.Next && sr.Index == 0 {
  202. sr.MsgIndex++
  203. if sr.MsgIndex == len(sr.Messages) {
  204. sr.MsgIndex = 0
  205. }
  206. }
  207. if sr.Index != 0 {
  208. sr.Next = true
  209. }
  210. // Place message
  211. var msg string = sr.Messages[sr.MsgIndex]
  212. var pos int = int(sr.CenterPos)
  213. // Bug: If we're changing to next message (sr.Next == True) ... but the
  214. // message is > SpinRite.Length, it shows the text beyond what it should.
  215. var texthalf int = StringLen(msg) / 2
  216. // Place text center, outwards. Stopping if there's no space.
  217. for i := 0; i < texthalf+1; i++ {
  218. if Unicode {
  219. if sr.OutputR[pos+i] == ' ' {
  220. if texthalf+i < StringLen(msg) {
  221. sr.OutputR[pos+i] = []rune(msg)[texthalf+i]
  222. }
  223. } else {
  224. break
  225. }
  226. if i != 0 {
  227. if sr.OutputR[pos-i] == ' ' {
  228. sr.OutputR[pos-i] = []rune(msg)[texthalf-i]
  229. } else {
  230. break
  231. }
  232. }
  233. } else {
  234. if sr.OutputB[pos+i] == ' ' {
  235. if texthalf+i < StringLen(msg) {
  236. sr.OutputB[pos+i] = byte(msg[texthalf+i])
  237. }
  238. } else {
  239. break
  240. }
  241. if i != 0 {
  242. if sr.OutputB[pos-i] == ' ' {
  243. sr.OutputB[pos-i] = byte(msg[texthalf-i])
  244. } else {
  245. break
  246. }
  247. }
  248. }
  249. }
  250. /*
  251. for i := 0; i < len(msg); i++ {
  252. if Unicode {
  253. if sr.OutputR[pos+i] == ' ' {
  254. sr.OutputR[pos+i] = []rune(msg)[i]
  255. }
  256. } else {
  257. if sr.OutputB[pos+i] == ' ' {
  258. sr.OutputB[pos+i] = byte(msg[i])
  259. }
  260. }
  261. }
  262. */
  263. if Unicode {
  264. result = string(sr.OutputR)
  265. } else {
  266. result = string(sr.OutputB)
  267. }
  268. sr.Index++
  269. return sr.Color + result
  270. }