Skip to content

Instantly share code, notes, and snippets.

@adhocore
Last active Oct 8, 2017
Embed
What would you like to do?
Maqe Bot (PHP7). Sample usage: `php maqebot.php W5RW5RW2RW1R`
<?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