<?php class Robot { const DIRECTION_NORTH = 'north'; const DIRECTION_EAST = 'east'; const DIRECTION_SOUTH = 'south'; const DIRECTION_WEST = 'west'; /** * * @var int[] */ protected $position; /** * * @var string */ protected $direction; public function __construct(array $position, string $direction) { $this->position = $position; $this->direction = $direction; } /** * Make protected properties read-only. * __get() is slow, but it's ok for the given task. * * @param string $name * @return mixed */ public function __get($name) { return property_exists(self::class, $name) ? $this->$name : null; } /** * Turn the Robot clockwise * @return Robot */ public function turnRight() { $this->direction = self::listDirectionsClockwize()[$this->direction]; return $this; } /** * Turn the Robot counterclockwise * @return Robot */ public function turnLeft() { $this->direction = self::listDirectionsCounterClockwize()[$this->direction]; return $this; } /** * Advance the Robot one step forward * @return Robot */ public function advance() { switch ($this->direction) { case self::DIRECTION_NORTH: $this->position[1]++; break; case self::DIRECTION_EAST: $this->position[0]++; break; case self::DIRECTION_SOUTH: $this->position[1]--; break; case self::DIRECTION_WEST: $this->position[0]--; break; } return $this; } /** * Move the Robot according to instructions: R = Turn Right, L = Turn Left and A = Advance */ public function instructions($instructions) { if (!preg_match('/^[LAR]+$/', $instructions)) { throw new InvalidArgumentException('Malformed instructions'); } foreach ($this->mapInsructionsToActions($instructions) as $action) { $this->$action(); } return $this; } /** * List all possible clockwise turn combinations * @return array */ public static function listDirectionsClockwize() { return [ self::DIRECTION_NORTH => self::DIRECTION_EAST, self::DIRECTION_EAST => self::DIRECTION_SOUTH, self::DIRECTION_SOUTH => self::DIRECTION_WEST, self::DIRECTION_WEST => self::DIRECTION_NORTH, ]; } /** * List all possible counterclockwise turn combinations * @return array */ public static function listDirectionsCounterClockwize() { return array_flip(self::listDirectionsClockwize()); } /** * Translate instructions string to actions * @param string $stringInstructions * @return string[] */ protected function mapInsructionsToActions($stringInstructions) { return array_map(function ($x) { return [ 'L' => 'turnLeft', 'R' => 'turnRight', 'A' => 'advance', ][$x]; }, str_split($stringInstructions)); } }