Last active
October 8, 2017 11:22
-
-
Save adhocore/76d68520feaa6ebabf5f44e62be98e05 to your computer and use it in GitHub Desktop.
Maqe Bot (PHP7). Sample usage: `php maqebot.php W5RW5RW2RW1R`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* The Bot. | |
*/ | |
class Bot | |
{ | |
const DIR_NORTH = 0; | |
const DIR_EAST = 1; | |
const DIR_SOUTH = 2; | |
const DIR_WEST = 3; | |
/** @var integer Represents x coordinate */ | |
private $x; | |
/** @var integer Represents y coordinate */ | |
private $y; | |
/** @var integer Represents the currently facing direction */ | |
private $dir; | |
/** | |
* Class Constructor that initializes the bot. | |
* | |
* @param integer $x The initial x coordinate. | |
* @param integer $y The initial y coordinate. | |
* @param integer $dir The initial direction. | |
*/ | |
public function __construct(int $x = 0, int $y = 0, int $dir = 0) | |
{ | |
$this->x = $x; | |
$this->y = $y; | |
$this->dir = $dir; | |
} | |
/** | |
* Rotate right (clockwise), | |
* | |
* @return Bot | |
*/ | |
public function turnRight(): Bot | |
{ | |
// Since we have incremental sequence clockwise, just add 1 | |
// but check it never gets past WEST (3). | |
$this->dir += 1; | |
if ($this->dir > self::DIR_WEST) { | |
$this->dir = self::DIR_NORTH; | |
} | |
return $this; | |
} | |
/** | |
* Rotate left (anticlockwise), | |
* | |
* @return Bot | |
*/ | |
public function turnLeft(): Bot | |
{ | |
// Since we have decremental sequence anticlockwise, just subtract 1 | |
// but check it never gets below NORTH (0). | |
$this->dir -= 1; | |
if ($this->dir < self::DIR_NORTH) { | |
$this->dir = self::DIR_WEST; | |
} | |
return $this; | |
} | |
/** | |
* Move the bot by given step(s). | |
* | |
* @param integer $step | |
* | |
* @return Bot | |
*/ | |
public function walk(int $step = 1): Bot | |
{ | |
switch ($this->dir) { | |
case self::DIR_NORTH; | |
$this->y += $step; | |
break; | |
case self::DIR_EAST; | |
$this->x += $step; | |
break; | |
case self::DIR_SOUTH; | |
$this->y -= $step; | |
break; | |
case self::DIR_WEST; | |
$this->x -= $step; | |
break; | |
} | |
return $this; | |
} | |
/** | |
* Get x coordinate. | |
* | |
* @return int | |
*/ | |
public function getX(): int | |
{ | |
return $this->x; | |
} | |
/** | |
* Get y coordinate. | |
* | |
* @return int | |
*/ | |
public function getY(): int | |
{ | |
return $this->y; | |
} | |
/** | |
* Get Direction. | |
* | |
* @return int | |
*/ | |
public function getDir(): int | |
{ | |
return $this->dir; | |
} | |
/** | |
* Get the coordinates and direction. | |
* | |
* @return array | |
*/ | |
public function getPosition(): array | |
{ | |
$dirs = ['North', 'East', 'South', 'West']; | |
return [ | |
'x' => $this->x, | |
'y' => $this->y, | |
'direction' => $dirs[$this->dir], | |
]; | |
} | |
} | |
/** | |
* The controller for Bot, | |
*/ | |
class Controller | |
{ | |
/** @var Bot The bot this controller controls */ | |
private $bot; | |
/** | |
* Class Constructor. | |
* | |
* @param Bot $bot | |
*/ | |
public function __construct(Bot $bot) | |
{ | |
$this->bot = $bot; | |
} | |
/** | |
* Parse the signal, make it understandable by Bot and send the signal to Bot. | |
* | |
* @param string $signal Eg: LW10RW1 | |
* | |
* @return Controller | |
* | |
* @throws \InvalidArgumentException If the signal is anything other than RLW and whitespace. | |
*/ | |
public function signal(string $signal): Controller | |
{ | |
$operations = $this->getOperations($signal); | |
foreach ($operations as $operation) { | |
$action = ucfirst($operation[0][0]); | |
if ($action === 'R') { | |
$this->bot->turnRight(); | |
} elseif ($action === 'L') { | |
$this->bot->turnLeft(); | |
} elseif ($action === 'W') { | |
// The single W with no quantifier is assumed 1. | |
$this->bot->walk($operation[1] ?? 1); | |
} | |
// If not whitespace, throw up! | |
elseif (trim($action) !== '') { | |
throw new \InvalidArgumentException("Invalid operation `{$operation[0]}` in '{$signal}'"); | |
} | |
} | |
return $this; | |
} | |
/** | |
* Prints the current position of underlying Bot. | |
* | |
* @return void | |
*/ | |
public function printPosition(): void | |
{ | |
foreach ($this->bot->getPosition() as $key => $value) { | |
echo ucfirst($key), ': ', $value, ' '; | |
} | |
echo PHP_EOL; | |
} | |
/** | |
* Get the operations runnable for Bot from the argument signal. | |
* | |
* @param string $signal | |
* | |
* @return array | |
*/ | |
private function getOperations(string $signal): array | |
{ | |
$flags = PREG_SET_ORDER; | |
preg_match_all('/R|L|W(\d+)|.+/i', trim($signal), $operations, $flags); | |
return $operations ?: []; | |
} | |
} | |
// Run! | |
try { | |
(new Controller(new Bot)) | |
->signal($_SERVER['argv'][1] ?? '') | |
->printPosition() | |
; | |
} catch (\Throwable $e) { | |
echo $e->getMessage(), PHP_EOL; | |
exit(1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment