spinrite.go 6.0 KB

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