Robots Musterlösung
Zur Navigation springen
Zur Suche springen
Links
Zielsetzung
Dies ist eine funktionierende Lösung der Robotersimulaltion.
<?php
define('BLACK', '*');
define('DEFAULT_COLOR', "\t");
define('WHITE', ' ');
class Sheet
{
public array $lines;
public int $width;
public int $height;
public function __construct(int $width = 80, int $height = 40)
{
$this->width = $width;
$this->height = $height;
$this->clearSheet();
}
public function clearTerminal()
{
echo "\x1b\x5b\x48\x1b\x5b\x32\x4a\xc";
}
public function clearSheet()
{
$this->lines = [];
for ($y = 0; $y < $this->height; $y++) {
array_push($this->lines, str_repeat(' ', $this->width));
}
}
public function setRandomPosition(&$point)
{
do {
$x = rand(0, $this->width - 1);
$y = rand(0, $this->height - 1);
} while ($this->isOccupied($x, $y));
$point->x = $x;
$point->y = $y;
}
public function showDrawing()
{
$this->clearTerminal();
echo str_repeat('-', $this->width + 2), "\n";
for ($y = $this->height - 1; $y >= 0; $y--) {
echo '|', $this->lines[$y], "|\n";
}
echo str_repeat('-', $this->width + 2), "\n";
}
public function setPoint(int $x, int $y, string $color = BLACK)
{
if ($x >= 0 && $x < $this->width && $y >= 0 && $y < $this->height) {
$this->lines[$y][$x] = $color;
}
}
public function isOccupied(int $x, int $y): bool
{
$color = $this->lines[$y][$x];
return $color !== WHITE && $color < "a";
}
}
class Point
{
public int $x;
public int $y;
public string $color;
public function __construct(int $x, int $y, string $color)
{
$this->x = $x;
$this->y = $y;
$this->color = $color;
}
public function draw(Sheet &$sheet, string $color = DEFAULT_COLOR)
{
if ($color == DEFAULT_COLOR){
$color = $this->color;
}
$sheet->setPoint($this->x, $this->y, $color);
}
}
class Rectangle extends Point
{
public $width;
public $height;
public function __construct(int $x, int $y, int $width, int $height, string $color = BLACK)
{
parent::__construct($x, $y, $color);
$this->width = $width;
$this->height = $height;
}
public function draw(Sheet &$sheet, string $color = DEFAULT_COLOR)
{
if ($color === DEFAULT_COLOR){
$color = $this->color;
}
for ($x = $this->x; $x < $this->x + $this->width; $x++) {
for ($y = $this->y; $y <= $this->y + $this->height; $y++) {
$sheet->setPoint($x, $y, $color);
}
}
}
}
class Robot extends Point
{
public $target;
public string $color;
public string $colorTarget;
public int $xDirection = 1;
public int $yDirection = 1;
public function __construct(string $color, Sheet &$sheet)
{
parent::__construct(0, 0, $color);
$this->target = null;
$this->color = $color;
$this->colorTarget = strtolower($color);
$sheet->setRandomPosition($this);
$this->setTarget($sheet);
}
public function checkDirection(Sheet &$sheet)
{
if ($this->x <= 0) {
$this->xDirection = 1;
} elseif ($this->x >= $sheet->width - 1) {
$this->xDirection = -1;
}
if ($this->y <= 0) {
$this->yDirection = 1;
} elseif ($this->y >= $sheet->height - 1) {
$this->yDirection = -1;
}
}
public function move(Sheet &$sheet): bool
{
$rc = false;
$x = -1;
$y = -1;
if ($this->target->x == $this->x && $this->target->y == $this->y) {
// $sheet->setRandomPosition($this->target, $sheet);
} else {
$this->target->draw($sheet);
$x = $this->x;
$y = $this->y;
if ($this->target !== $x) {
$x = $this->target->x < $x ? $x - 1 : $x + 1;
}
if ($this->target->y !== $y) {
$y = $this->target->y < $y ? $y - 1 : $y + 1;
}
$this->checkDirection($sheet);
if ($sheet->isOccupied($x, $y)) {
$x = $this->x + $this->xDirection;
$y = $this->y;
if ($sheet->isOccupied($x, $y)) {
$x = $this->x;
$y = $this->y + $this->yDirection;
}
}
if (!$sheet->isOccupied($x, $y)) {
// Remove current point:
$this->draw($sheet, WHITE);
$this->x = $x;
$this->y = $y;
$this->draw($sheet);
$rc = true;
}
}
return $rc;
}
public function setTarget(Sheet &$sheet){
if ($this->target == null){
$this->target = new Point(0, 0, $this->colorTarget);
} else {
$sheet->setPoint($this->target->x, $this->target->y, WHITE);
}
$sheet->setRandomPosition($this->target);
$sheet->setPoint($this->target->x, $this->target->y, $this->colorTarget);
}
}
class Simulator
{
public array $statics = [];
public array $mobiles = [];
public Sheet $sheet;
public function __construct(Sheet &$sheet)
{
$this->sheet = $sheet;
}
public function add($item, bool $isStatic)
{
if ($isStatic) {
array_push($this->statics, $item);
$item->draw($this->sheet);
} else {
array_push($this->mobiles, $item);
$item->draw($this->sheet);
}
}
public function buildHouses(int $rows = 5, int $cols = 5)
{
$width = ($this->sheet->width - 1) / $rows / 2;
$height = ($this->sheet->height - 1) / $cols / 2;
for ($row = 0; $row < $rows; $row++) {
for ($col = 0; $col < $cols; $col++) {
$x = $width / 2 + $row * 2 * $width;
$y = $height / 2 + $col * 2 * $height;
$item = new Rectangle($x, $y, $width, $height);
$this->add($item, true);
}
}
}
public function buildRobots(int $count)
{
$names = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ($ix = 0; $ix < $count; $ix++) {
$car = new Robot($names[$ix], $this->sheet);
$this->add($car, false);
}
}
public function show()
{
$this->sheet->clearTerminal();
$this->sheet->showDrawing();
}
public function step()
{
$moves = 0;
foreach ($this->mobiles as $car) {
if ($car->move($this->sheet)){
$moves++;
};
}
return $moves > 0;
}
}
$sheet = new Sheet(40, 40);
$simulator = new Simulator($sheet);
$simulator->buildHouses(3, 3);
$simulator->buildRobots(5);
$simulator->show();
$rounds = 0;
while ($simulator->step()){
$rounds++;
$simulator->show();
sleep(1);
}
echo "== ready after $rounds rounds\n";