#!/usr/bin/env python


import sys
from copy import deepcopy
from dataclasses import dataclass, field
from enum import Enum, IntEnum, auto
from typing import List, NamedTuple


class ParameterMode(IntEnum):
    POSITION = 0  # Acts on address
    IMMEDIATE = 1  # Acts on the immediate value
    RELATIVE = 2  # Acts on offset to relative base


class Instruction(NamedTuple):
    address: int  # The address of the instruction, for convenience
    op: int  # The opcode
    p1_mode: ParameterMode  # Which mode is the first parameter in
    p2_mode: ParameterMode  # Which mode is the second parameter in
    p3_mode: ParameterMode  # Which mode is the third parameter in


def lookup_ops(index: int, memory: List[int]) -> Instruction:
    digits = list(map(int, str(memory[index])))
    a, b, c, d, e = [0] * (5 - len(digits)) + digits  # Pad with default values
    return Instruction(
        address=index,
        op=d * 10 + e,
        p1_mode=ParameterMode(c),
        p2_mode=ParameterMode(b),
        p3_mode=ParameterMode(a),
    )


class InputInterrupt(Exception):
    pass


class OutputInterrupt(Exception):
    pass


@dataclass
class Computer:
    memory: List[int]  # Memory space
    rip: int = 0  # Instruction pointer
    input_list: List[int] = field(default_factory=list)
    output_list: List[int] = field(default_factory=list)
    is_halted: bool = field(default=False, init=False)
    relative_base: int = field(default=0, init=False)

    def run(self) -> None:
        while not self.is_halted:
            self.run_single()

    def run_no_output_interrupt(self) -> None:
        while not self.is_halted:
            try:
                self.run_single()
            except OutputInterrupt:
                continue

    def run_single(self):  # Returns True when halted
        instr = lookup_ops(self.rip, self.memory)
        if instr.op == 99:  # Halt
            self.is_halted = True
        elif instr.op == 1:  # Sum
            self._do_addition(instr)
        elif instr.op == 2:  # Multiplication
            self._do_multiplication(instr)
        elif instr.op == 3:  # Load from input
            self._do_input(instr)
        elif instr.op == 4:  # Store to output
            self._do_output(instr)
        elif instr.op == 5:  # Jump if true
            self._do_jump_if_true(instr)
        elif instr.op == 6:  # Jump if false
            self._do_jump_if_false(instr)
        elif instr.op == 7:  # Less than
            self._do_less_than(instr)
        elif instr.op == 8:  # Equal to
            self._do_equal_to(instr)
        elif instr.op == 9:  # Change relative base
            self._do_change_relative_base(instr)
        else:
            assert False  # Sanity check

    def _fill_to_addres(self, address: int) -> None:
        values = address - len(self.memory) + 1
        if values <= 0:
            return
        for __ in range(values):
            self.memory.append(0)

    def _get_value(self, mode: ParameterMode, val: int) -> int:
        if mode == ParameterMode.POSITION:
            assert 0 <= val  # Sanity check
            self._fill_to_addres(val)
            return self.memory[val]
        elif mode == ParameterMode.RELATIVE:
            val += self.relative_base
            assert 0 <= val  # Sanity check
            self._fill_to_addres(val)
            return self.memory[val]
        assert mode == ParameterMode.IMMEDIATE  # Sanity check
        return val

    def _set_value(self, mode: ParameterMode, address: int, value: int) -> None:
        if mode == ParameterMode.RELATIVE:
            address += self.relative_base
        else:
            assert mode == ParameterMode.POSITION  # Sanity check

        assert address >= 0  # Sanity check
        self._fill_to_addres(address)

        self.memory[address] = value

    def _do_addition(self, instr: Instruction) -> None:
        lhs = self._get_value(instr.p1_mode, self.memory[instr.address + 1])
        rhs = self._get_value(instr.p2_mode, self.memory[instr.address + 2])
        dest = self.memory[instr.address + 3]

        self._set_value(instr.p3_mode, dest, lhs + rhs)

        self.rip += 4  # Length of the instruction

    def _do_multiplication(self, instr: Instruction) -> None:
        lhs = self._get_value(instr.p1_mode, self.memory[instr.address + 1])
        rhs = self._get_value(instr.p2_mode, self.memory[instr.address + 2])
        dest = self.memory[instr.address + 3]

        self._set_value(instr.p3_mode, dest, lhs * rhs)

        self.rip += 4  # Length of the instruction

    def _do_input(self, instr: Instruction) -> None:
        if len(self.input_list) == 0:
            raise InputInterrupt  # No input, halt until an input is provided

        value = int(self.input_list.pop(0))
        param = self.memory[instr.address + 1]

        self._set_value(instr.p1_mode, param, value)

        self.rip += 2  # Length of the instruction

    def _do_output(self, instr: Instruction) -> None:
        value = self._get_value(instr.p1_mode, self.memory[instr.address + 1])

        self.output_list.append(value)

        self.rip += 2  # Length of the instruction
        raise OutputInterrupt  # Alert that we got an output to give

    def _do_jump_if_true(self, instr: Instruction) -> None:
        cond = self._get_value(instr.p1_mode, self.memory[instr.address + 1])
        value = self._get_value(instr.p2_mode, self.memory[instr.address + 2])

        if cond != 0:
            self.rip = value
        else:
            self.rip += 3  # Length of the instruction

    def _do_jump_if_false(self, instr: Instruction) -> None:
        cond = self._get_value(instr.p1_mode, self.memory[instr.address + 1])
        value = self._get_value(instr.p2_mode, self.memory[instr.address + 2])

        if cond == 0:
            self.rip = value
        else:
            self.rip += 3  # Length of the instruction

    def _do_less_than(self, instr: Instruction) -> None:
        lhs = self._get_value(instr.p1_mode, self.memory[instr.address + 1])
        rhs = self._get_value(instr.p2_mode, self.memory[instr.address + 2])
        dest = self.memory[instr.address + 3]

        self._set_value(instr.p3_mode, dest, 1 if lhs < rhs else 0)

        self.rip += 4  # Length of the instruction

    def _do_equal_to(self, instr: Instruction) -> None:
        lhs = self._get_value(instr.p1_mode, self.memory[instr.address + 1])
        rhs = self._get_value(instr.p2_mode, self.memory[instr.address + 2])
        dest = self.memory[instr.address + 3]

        self._set_value(instr.p3_mode, dest, 1 if lhs == rhs else 0)

        self.rip += 4  # Length of the instruction

    def _do_change_relative_base(self, instr: Instruction) -> None:
        value = self._get_value(instr.p1_mode, self.memory[instr.address + 1])

        self.relative_base += value
        self.rip += 2  # Length of the instruction


class Position(NamedTuple):
    x: int
    y: int


class Direction(Enum):
    NORTH = auto()
    WEST = auto()
    SOUTH = auto()
    EAST = auto()


DIRECTIONS = [d for d in Direction]
ARROW_DIRECTION = {
    "^": Direction.NORTH,
    "v": Direction.SOUTH,
    "<": Direction.WEST,
    ">": Direction.EAST,
}
DIRECTION_OFFSET = {
    Direction.NORTH: (-1, 0),
    Direction.SOUTH: (1, 0),
    Direction.WEST: (0, -1),
    Direction.EAST: (0, 1),
}


def turn(d: Direction, turn: str) -> Direction:
    def turn_left() -> Direction:
        return DIRECTIONS[(DIRECTIONS.index(d) + 1) % len(DIRECTIONS)]

    def turn_right() -> Direction:
        return DIRECTIONS[DIRECTIONS.index(d) - 1]

    if turn == "L":
        return turn_left()
    elif turn == "R":
        return turn_right()
    assert False  # Sanity check


def find_arrow(mapped_view: List[List[str]]) -> Position:
    for x in range(len(mapped_view)):
        for y in range(len(mapped_view[0])):
            if mapped_view[x][y] in ARROW_DIRECTION:
                return Position(x, y)

    assert False  # Sanity check


def get_path(mapped_view: List[List[str]]) -> List[str]:
    pos = find_arrow(mapped_view)

    def pos_is_valid(p: Position) -> bool:
        return 0 <= p.x < len(mapped_view) and 0 <= p.y < len(mapped_view[0])

    def pos_is_scaffold(p: Position) -> bool:
        return pos_is_valid(p) and mapped_view[p.x][p.y] != "."

    direction = ARROW_DIRECTION[mapped_view[pos.x][pos.y]]
    ans: List[str] = []

    def advance_until_stopped(turn_string: str) -> bool:
        nonlocal pos
        nonlocal direction
        d = turn(direction, turn_string)
        offset = DIRECTION_OFFSET[d]
        neighbor = Position(*(a + b for a, b in zip(pos, offset)))
        tot = 0
        while pos_is_scaffold(neighbor):
            tot += 1
            mapped_view[pos.x][pos.y] = "@"
            pos = neighbor
            neighbor = Position(*(a + b for a, b in zip(pos, offset)))

        if tot == 0:
            return False
        direction = d
        ans.append(turn_string)
        ans.append(str(tot))
        return True

    has_no_neighbors = False
    while not has_no_neighbors:
        for turn_string in ("L", "R"):
            if advance_until_stopped(turn_string):
                break
        else:
            has_no_neighbors = True
    return ans


def sequitur_algorithm(path: str) -> None:
    # FIXME: seems like a good candidate for compression
    pass


def main() -> None:
    memory = [int(n) for n in sys.stdin.read().split(",")]
    camera = Computer(deepcopy(memory))

    camera.run_no_output_interrupt()

    view = "".join(chr(c) for c in camera.output_list)
    mapped_view = [[c for c in line] for line in view.split("\n") if line != ""]

    path = get_path(mapped_view)
    print(path)

    # I didn't want to write the compression algorithm when I could just use Vim
    # The answere is A,B,B,A,C,A,A,C,B,C
    # A: R,8,L,12,R,8
    # B: R,12,L,8,R,10
    # C: R,8,L,8,L,8,R,8,R,10

    ans = "A,B,B,A,C,A,A,C,B,C"
    A = "R,8,L,12,R,8"
    B = "R,12,L,8,R,10"
    C = "R,8,L,8,L,8,R,8,R,10"

    assert len(ans) <= 20  # Sanity check
    assert len(A) <= 20  # Sanity check
    assert len(B) <= 20  # Sanity check
    assert len(C) <= 20  # Sanity check

    memory[0] = 2  # Wake up the robot
    robot = Computer(memory)

    for c in ans:
        robot.input_list.append(ord(c))
    robot.input_list.append(ord("\n"))
    for c in A:
        robot.input_list.append(ord(c))
    robot.input_list.append(ord("\n"))
    for c in B:
        robot.input_list.append(ord(c))
    robot.input_list.append(ord("\n"))
    for c in C:
        robot.input_list.append(ord(c))
    robot.input_list.append(ord("\n"))

    for c in "n\n":  # Do not output the video feed
        robot.input_list.append(ord(c))

    robot.run_no_output_interrupt()
    print(robot.output_list.pop())


if __name__ == "__main__":
    main()