johnsonjh/randgoart

View on GitHub
randgoart.go

Summary

Maintainability
A
0 mins
Test Coverage
// Package randgoart generates visual hashes
// See https://pthree.org/2013/05/30/openssh-keys-and-the-drunken-bishop/
package randgoart

import (
    "bytes"
    "io"
)

const (
    // SSHChars ...
    SSHChars = " .o+=*BOX@%&#/^"
)

// GABishop ...
type GABishop struct {
    board      [][]byte
    y, x       int
    ymax, xmax int
    chars      string
}

// NewSSH ...
func NewSSH() *GABishop {
    return New(9, 17, SSHChars)
}

// New ...
func New(y, x int, chars string) *GABishop {
    board := make([][]byte, y)
    for i := range board {
        board[i] = make([]byte, x)
    }
    return &GABishop{
        board: board,
        y:     (y - 1) / 2,
        x:     (x - 1) / 2,
        ymax:  y,
        xmax:  x,
        chars: chars,
    }
}

func (b *GABishop) Write(buf []byte) (int, error) {
    n := len(buf)
    m := moves{data: buf}
    for {
        r, err := m.next()
        if err == io.EOF {
            break
        }
        moveSouth, moveEast := (r >> 1), (r & 1)
        if moveSouth == 1 && b.y < (b.ymax-1) {
            b.y++
        } else if moveSouth == 0 && b.y > 0 {
            b.y--
        }
        if moveEast == 1 && b.x < (b.xmax-1) {
            b.x++
        } else if moveEast == 0 && b.x > 0 {
            b.x--
        }
        b.board[b.y][b.x]++
    }
    return n, nil
}

func (b *GABishop) String() string {
    xstart := (b.xmax - 1) / 2
    ystart := (b.ymax - 1) / 2
    var buf bytes.Buffer
    buf.Write([]byte("+-----------------+\n"))
    for y := range b.board {
        buf.WriteByte('|')
        for x := range b.board[y] {
            count := b.board[y][x]
            var ch byte
            if int(count) < len(b.chars) {
                ch = b.chars[count]
            } else {
                ch = b.chars[len(b.chars)-1]
            }
            if x == xstart && y == ystart {
                ch = 'S'
            } else if x == b.x && y == b.y {
                ch = 'E'
            }
            buf.WriteByte(ch)
        }
        buf.Write([]byte{'|', '\n'})
    }
    buf.Write([]byte("+-----------------+"))
    return buf.String()
}

type moves struct {
    data  []byte
    b     byte
    count int
}

func (m *moves) next() (byte, error) {
    if len(m.data) == 0 && m.count == 0 {
        return 0, io.EOF
    }
    if m.count == 0 {
        m.b = m.data[0]
        m.count = 8
        m.data = m.data[1:]
    }
    r := (m.b & 0x3)
    m.b >>= 2
    m.count -= 2
    return r, nil
}