Robots Musterlösung

Aus Vokabulabor
Version vom 3. Dezember 2023, 17:39 Uhr von Hamatoma (Diskussion | Beiträge) (→‎Zielsetzung)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
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";