package pad import ( "slices" "strings" log "github.com/sirupsen/logrus" ) type Dirpad struct { current node pad [][]rune locations map[rune]coords } func NewDirpad() *Dirpad { pad := [][]rune{ {'.', '^', 'A'}, {'<', 'v', '>'}, } locations := make(map[rune]coords) for y, row := range pad { for x, value := range row { locations[value] = coords{x, y} } } return &Dirpad{ current: newNode(2, 0, 'A'), pad: pad, locations: locations, } } func (dp *Dirpad) valueAt(c coords) rune { return dp.pad[c.y][c.x] } func (dp *Dirpad) nextTarget(c rune) node { coords := dp.locations[c] return newNode(coords.x, coords.y, c) } func (dp *Dirpad) Generate(code string) string { var sb strings.Builder for _, c := range code { target := dp.nextTarget(c) moved := newMove(dp.current.x, target.x, dp.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 dp.valueAt(coords{dp.current.x + moved.x, dp.current.y}) == '.' { sb.WriteString(vb.String()) sb.WriteString(hb.String()) } else if dp.valueAt(coords{dp.current.x, dp.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') dp.current = target } log.Tracef("\n%s\n", dp.trace(sb.String())) return sb.String() } func (dp *Dirpad) trace(visited string) string { log.Debug(visited) temp := slices.Clone(dp.pad) next := coords{2, 0} 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") }