package pad import ( "slices" "strings" log "github.com/sirupsen/logrus" ) type Numpad struct { current node pad [][]rune locations map[rune]coords } func NewNumpad() *Numpad { pad := [][]rune{ {'7', '8', '9'}, {'4', '5', '6'}, {'1', '2', '3'}, {'.', '0', 'A'}, } locations := make(map[rune]coords) for y, row := range pad { for x, value := range row { locations[value] = coords{x, y} } } return &Numpad{ current: newNode(2, 3, 'A'), pad: pad, locations: locations, } } func (np *Numpad) valueAt(c coords) rune { return np.pad[c.y][c.x] } func (np *Numpad) nextTarget(c rune) node { coords := np.locations[c] return newNode(coords.x, coords.y, c) } func (np *Numpad) Generate(code string) string { var sb strings.Builder for _, c := range code { target := np.nextTarget(c) moved := newMove(np.current.x, target.x, np.current.y, target.y) var hb, vb strings.Builder for range absInt(moved.x) { if moved.x >= 0 { hb.WriteRune('>') } else { hb.WriteRune('<') } } for range absInt(moved.y) { if moved.y <= 0 { vb.WriteRune('^') } else { vb.WriteRune('v') } } if np.valueAt(coords{np.current.x + moved.x, np.current.y}) == '.' { sb.WriteString(vb.String()) sb.WriteString(hb.String()) } else if np.valueAt(coords{np.current.x, np.current.y + moved.y}) == '.' { sb.WriteString(hb.String()) sb.WriteString(vb.String()) } else if moved.x < 0 { sb.WriteString(hb.String()) sb.WriteString(vb.String()) } else if moved.x >= 0 { sb.WriteString(vb.String()) sb.WriteString(hb.String()) } sb.WriteRune('A') np.current = target } log.Tracef("\n%s\n", np.trace(sb.String())) return sb.String() } func (np *Numpad) trace(visited string) string { log.Debug(visited) temp := slices.Clone(np.pad) next := coords{2, 3} for _, c := range visited { next = neighbours(next, c) temp[next.y][next.x] = 'X' } output := []string{} for _, row := range temp { output = append(output, string(row)) } return strings.Join(output, "\n") }