randgoart.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Package randgoart generates visual hashes
  2. // See https://pthree.org/2013/05/30/openssh-keys-and-the-drunken-bishop/
  3. package randgoart
  4. import (
  5. "bytes"
  6. "io"
  7. )
  8. const (
  9. // SSHChars ...
  10. SSHChars = " .o+=*BOX@%&#/^"
  11. )
  12. // GABishop ...
  13. type GABishop struct {
  14. board [][]byte
  15. y, x int
  16. ymax, xmax int
  17. chars string
  18. }
  19. // NewSSH ...
  20. func NewSSH() *GABishop {
  21. return New(9, 17, SSHChars)
  22. }
  23. // New ...
  24. func New(y, x int, chars string) *GABishop {
  25. board := make([][]byte, y)
  26. for i := range board {
  27. board[i] = make([]byte, x)
  28. }
  29. return &GABishop{
  30. board: board,
  31. y: (y - 1) / 2,
  32. x: (x - 1) / 2,
  33. ymax: y,
  34. xmax: x,
  35. chars: chars,
  36. }
  37. }
  38. func (b *GABishop) Write(buf []byte) (int, error) {
  39. n := len(buf)
  40. m := moves{data: buf}
  41. for {
  42. r, err := m.next()
  43. if err == io.EOF {
  44. break
  45. }
  46. moveSouth, moveEast := (r >> 1), (r & 1)
  47. if moveSouth == 1 && b.y < (b.ymax-1) {
  48. b.y++
  49. } else if moveSouth == 0 && b.y > 0 {
  50. b.y--
  51. }
  52. if moveEast == 1 && b.x < (b.xmax-1) {
  53. b.x++
  54. } else if moveEast == 0 && b.x > 0 {
  55. b.x--
  56. }
  57. b.board[b.y][b.x]++
  58. }
  59. return n, nil
  60. }
  61. func (b *GABishop) String() string {
  62. xstart := (b.xmax - 1) / 2
  63. ystart := (b.ymax - 1) / 2
  64. var buf bytes.Buffer
  65. buf.Write([]byte("+-----------------+\n"))
  66. for y := range b.board {
  67. buf.WriteByte('|')
  68. for x := range b.board[y] {
  69. count := b.board[y][x]
  70. var ch byte
  71. if int(count) < len(b.chars) {
  72. ch = b.chars[count]
  73. } else {
  74. ch = b.chars[len(b.chars)-1]
  75. }
  76. if x == xstart && y == ystart {
  77. ch = 'S'
  78. } else if x == b.x && y == b.y {
  79. ch = 'E'
  80. }
  81. buf.WriteByte(ch)
  82. }
  83. buf.Write([]byte{'|', '\n'})
  84. }
  85. buf.Write([]byte("+-----------------+"))
  86. return buf.String()
  87. }
  88. type moves struct {
  89. data []byte
  90. b byte
  91. count int
  92. }
  93. func (m *moves) next() (byte, error) {
  94. if len(m.data) == 0 && m.count == 0 {
  95. return 0, io.EOF
  96. }
  97. if m.count == 0 {
  98. m.b = m.data[0]
  99. m.count = 8
  100. m.data = m.data[1:]
  101. }
  102. r := (m.b & 0x3)
  103. m.b >>= 2
  104. m.count -= 2
  105. return r, nil
  106. }