Skip to content

Instantly share code, notes, and snippets.

@martenlienen
Created April 27, 2011 23:27
Show Gist options
  • Save martenlienen/945463 to your computer and use it in GitHub Desktop.
Save martenlienen/945463 to your computer and use it in GitHub Desktop.
BwInf Runde 2 Aufgabe 2
<?php
/**
* Ein Logger fuer die Kranbewegungen
*/
class logger
{
/**
* Lognachrichten
*
* @var array
*/
protected $messages = array();
/**
* Anzahl der Bewegungen
*
* @var int
*/
protected $movements = 0;
/**
* Loggt eine Bewegung
*
* @param bool $forward Vorwaerts oder rueckwaerts
* @return void
*/
public function logMove ($forward)
{
$this->movements++;
if ($forward === true)
{
$this->log('1 Schritt vorwaerts');
}
else
{
$this->log('1 Schritt rueckwaerts');
}
}
/**
* Loggt eine Nachricht
*
* @param string $msg Nachricht
* @return void
*/
public function log ($msg)
{
$this->messages[] = (string)$msg;
}
/**
* Gibt die geloggten Informationen auf der Standardausgabe aus
*
* @return void
*/
public function dump ()
{
foreach ($this->messages as $message)
{
echo $message . "\n";
}
echo "\nAnzahl der Bewegungen: " . $this->getNumberOfMovements() . "\n";
}
/**
* Gibt die Anzahl der geloggten Bewegungen zurueck
*
* @return int
*/
public function getNumberOfMovements ()
{
return $this->movements;
}
}
/**
* Das Dock mit den Containern
*/
class dock
{
/**
* Anzahl der Container
*
* @var int
*/
protected $numberOfContainers = 0;
/**
* Positionen der Container
*
* @var array
*/
protected $positions = array();
/**
* Position des Krans
*
* @var int
*/
protected $position = 0;
/**
*
*
* @var int
*/
protected $container = -1;
/**
* Der Logger
*
* @var logger
*/
protected $logger = null;
/**
* Erzeugt eine zufällige Reihenfolge der Container
*
* @param int $numberOfContainers Anzahl der Container
* @param logger $logger Logger
*/
public function __construct ($numberOfContainers, logger $logger)
{
$this->logger = $logger;
$numberOfContainers = (int)$numberOfContainers;
if ($numberOfContainers < 1)
{
throw new Exception();
}
$this->numberOfContainers = $numberOfContainers;
$containers = range(0, $numberOfContainers - 1);
shuffle($containers);
for ($i = 0; $i < $numberOfContainers; $i++)
{
$this->positions[] = array(-1, array_pop($containers));
}
}
public function getThisShitStarted ()
{
$this->solve();
}
/**
* Verteilt die Container auf den Zug
*
* @return void
*/
protected function solve ()
{
try
{
$nextBorder = $this->getNextSubsystemBorder(
$this->positions,
$this->position
);
}
catch (Exception $e)
{
$nextBorder = false;
}
$start = $this->position;
do
{
// Wenn man sich an einer Grenze befindet
if ($nextBorder !== false
&& $this->position + 1 === $nextBorder)
{
$this->dropOnTrain();
$this->moveForward();
$this->solve();
$nextBorder = false;
$this->moveBack();
}
$this->handleContainers();
$this->move();
if ($this->position === $start)
{
$this->handleContainers();
}
}
while ($this->position !== $start);
}
/**
* Bewegt den Kran vorwaerts
*
* @return void
*/
protected function moveForward ()
{
$this->logger->logMove(true);
$this->position++;
}
/**
* Bewegt den Kran vorwaerts
*
* @return void
*/
protected function moveBack ()
{
$this->logger->logMove(false);
$this->position--;
}
/**
* Bewegt den Kran so, dass der geladene Container naeher an sein Ziel kommt
*
* @return void
*/
protected function move ()
{
if ($this->isCraneLoaded() === false)
{
return;
}
else if ($this->container - $this->position > 0)
{
$this->moveForward();
}
else
{
$this->moveBack();
}
}
/**
* Behandelt die Container an der aktuellen Stelle
*
* @return void
*/
protected function handleContainers ()
{
if (!$this->isCraneLoaded())
{
$this->pickFromStore();
}
// Wenn der geladene Container an seinem Ziel angekommen ist
if ($this->container - $this->position === 0)
{
$this->dropOnTrain();
if (!$this->isStoreEmpty())
{
$this->pickFromStore();
}
}
// Wenn der Container im Lager seinem Ziel direkt gegenueber liegt
else if ($this->positions[$this->position][1] - $this->position === 0)
{
$this->dropOnTrain();
$this->switchTrainAndStore();
$this->pickFromStore();
}
else
{
// Wenn der Container im Lager noch eine weitere Strecke in die
// gleiche Richtung zuruecklegen muss als der aktuell geladene
if ($this->positions[$this->position][1] > $this->container)
{
$this->dropOnTrain();
$this->pickFromStore();
}
// Wenn der Container auf dem Zug noch eine weitere Strecke "nach
// rechts" zuruecklegen muss als der aktuell geladene und der
// Container auf dem Zug nicht schon an seinem Bestimmungsort
// angekommen ist
else if ($this->positions[$this->position][0] > $this->container
&& $this->positions[$this->position][0] - $this->position !== 0)
{
$this->dropInStore();
$this->pickFromTrain();
}
}
}
/**
* Hebt den Container aus dem Lager
*
* @return void
* @throws Exception wenn der Kran schon beladen ist
*/
protected function pickFromStore ()
{
if ($this->container !== -1)
{
throw new Exception(
'Crane is already loaded and is therefore not able to pick from store'
);
}
if ($this->positions[$this->position][1] === -1)
{
return;
}
$this->logger->log('Nimm aus dem Lager');
$this->container = $this->positions[$this->position][1];
$this->positions[$this->position][1] = -1;
}
/**
* Hebt den Container vom Zug
*
* @return void
* @throws Exception wenn der Kran schon beladen ist
*/
protected function pickFromTrain ()
{
if ($this->isCraneLoaded())
{
throw new Exception(
'Crane is already loaded and is therefore not able to pick from train'
);
}
if ($this->positions[$this->position][0] === -1)
{
return;
}
$this->logger->log('Nimm von dem Zug');
$this->container = $this->positions[$this->position][0];
$this->positions[$this->position][0] = -1;
}
/**
* Laedt den geladenen Container auf dem Zug ab
*
* Wenn nicht direkt abgeladen werden kann, wird versucht den Container ins
* Lager zu legen und dann Lager und Zug zu vertauschen.
*
* @return void
*/
protected function dropOnTrain ()
{
if (!$this->isTrainEmpty())
{
$this->dropInStore();
$this->switchTrainAndStore();
}
else
{
if ($this->isCraneLoaded() === false)
{
return;
}
$this->logger->log('Lege auf den Zug');
$this->positions[$this->position][0] = $this->container;
$this->container = -1;
}
}
/**
* Laedt den geladenen Container im Lager ab
*
* @return void
* @throws Exception wenn das Lager nicht leer ist
*/
protected function dropInStore ()
{
if ($this->isStoreEmpty() === false)
{
throw new Exception('Store is not empty');
}
if ($this->isCraneLoaded() === false)
{
return;
}
$this->logger->log('Lege ins Lager');
$this->positions[$this->position][1] = $this->container;
$this->container = -1;
}
/**
* Vertauscht den Inhalt von Lager und Zug an der aktuellen Position
*
* @return void
* @throws Exception wenn der Kran nicht leer ist
*/
protected function switchTrainAndStore ()
{
if ($this->isCraneLoaded())
{
throw new Exception(
'Crane has to be unloaded to switch train and store'
);
}
$this->logger->log('Vertausche die Container in Lager und Zug');
$tmp = $this->positions[$this->position][1];
$this->positions[$this->position][1] = $this->positions[$this->position][0];
$this->positions[$this->position][0] = $tmp;
}
/**
* Checkt, ob der Zug an der aktuellen Position leer ist
*
* @return bool
*/
protected function isTrainEmpty ()
{
if ($this->positions[$this->position][0] === -1)
{
return true;
}
else
{
return false;
}
}
/**
* Checkt, ob das Lager an der aktuellen Position leer ist
*
* @return bool
*/
protected function isStoreEmpty ()
{
if ($this->positions[$this->position][1] === -1)
{
return true;
}
else
{
return false;
}
}
/**
* Checkt, ob der Kran beladen ist
*
* @return bool
*/
protected function isCraneLoaded ()
{
if ($this->container !== -1)
{
return true;
}
else
{
return false;
}
}
/**
* Gibt die Position des ersten Containers des naechsten Subsystems zurueck
*
* @param array $positions
* @param int $start
* @throws Exception wenn es keine weitere Grenze gibt
* @return int
*/
protected function getNextSubsystemBorder (array $positions, $start)
{
$lastContainer = count($positions) - 1;
$maxContainer = $positions[$start][1];
for ($i = $start; $i <= $lastContainer; $i++)
{
if ($maxContainer < $positions[$i][1])
{
$maxContainer = $positions[$i][1];
}
if ($maxContainer === $i)
{
break;
}
}
if ($i === $lastContainer)
{
throw new Exception('There are no more subsystems');
}
$i++;
return $i;
}
/**
* Gibt den Zug und das Lager aus
*
* @return void
*/
public function dumpContainers ()
{
for ($i = 0; $i < count($this->positions); $i++)
{
echo $i . ': ' . $this->positions[$i][0] . ', ' . $this->positions[$i][1] . "\n";
}
echo "\n";
}
}
try
{
$logger = new logger();
$dock = new Dock($_SERVER['argv'][1], $logger);
$dock->dumpContainers();
$dock->getThisShitStarted();
$logger->dump();
}
catch (Exception $e)
{
?>
Das Programm erwartet als ersten Parameter eine Zahl, die die Anzahl der Container angibt.
<?php
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment