Skip to content

Instantly share code, notes, and snippets.

@parap
Created January 31, 2013 20:00
Show Gist options
  • Save parap/4685904 to your computer and use it in GitHub Desktop.
Save parap/4685904 to your computer and use it in GitHub Desktop.
PHP Network class for Olexander Bondarenko
<?php
/**
* @task Write a php class Network.
* The constructor should take a positive integer value indicating the number of elements in the set.
* Passing in an invalid value should throw InvalidArgumentException.
*
* The class should also provide two public methods, connect and query.
*
* The first method, connect will take two integers indicating the elements to connect.
* This method should throw InvalidArgumentException or OutOfBoundsException as appropriate.
*
* The second method, query will also take two integers and should also throw InvalidArgumentException
* or OutOfBoundsException as appropriate.
* It should return true if the elements are connected, directly or indirectly, and false if the elements are not connected.
*
* The class can have as many private or protected members as needed for a good implementation.
* Also note that the exceptions mentioned are SPL exceptions and you should not define them.
*/
interface NetworkInterface
{
public function __construct($total);
public function connect($firstElement, $secondElement);
public function query($firstElement, $secondElement);
}
abstract class NetworkAbstract implements NetworkInterface
{
protected $groups = array();
protected $total;
abstract public function __construct($total);
abstract public function connect($firstElement, $secondElement);
abstract public function query($firstElement, $secondElement);
}
abstract class ConnectedElementsGroupAbstract
{
protected $elements;
abstract public function __construct(Pair $pair);
/**
* @param Pair $pair
* @returns void
*/
abstract public function add(Pair $pair);
/**
* @param Pair $pair
* @returns boolean
*/
abstract public function contains(Pair $pair);
}
class ConnectedElementsGroup extends ConnectedElementsGroupAbstract
{
public function __construct(Pair $pair)
{
$this->elements[] = $pair->getElements()[0];
$this->elements[] = $pair->getElements()[1];
}
public function add(Pair $pair)
{
foreach ($this->elements as $element) {
if ($pair->has($element)) {
$this->elements[] = $pair->other($element);
break;
}
}
}
public function hasElement($input)
{
foreach ($this->elements as $element) {
if ($input == $element) {
return true;
}
}
return false;
}
public function contains(Pair $pair)
{
foreach ($this->elements as $element) {
if ($pair->has($element)) {
return true;
}
}
return false;
}
}
class Pair
{
private $firstElement;
private $secondElement;
public function __construct($firstElement, $secondElement)
{
$this->firstElement = $firstElement;
$this->secondElement = $secondElement;
}
public function has($element)
{
return $this->firstElement == $element || $this->secondElement == $element;
}
public function other($element)
{
if ($this->firstElement == $element) {
return $this->secondElement;
}
if ($this->secondElement == $element) {
return $this->firstElement;
}
throw new InvalidArgumentException("Wrong $element passed. Bug in Pair->other()");
}
public function getElements()
{
return array($this->firstElement, $this->secondElement);
}
}
class Verifier
{
public static function verify($max, $firstElement, $secondElement)
{
$firstElement = (int)$firstElement;
$secondElement = (int)$secondElement;
if ($firstElement !== (int)$firstElement) {
throw new InvalidArgumentException("$firstElement parameter must be integer");
}
if ($secondElement !== (int)$secondElement) {
throw new InvalidArgumentException("$secondElement parameter must be integer");
}
if (0 >= $firstElement) {
throw new InvalidArgumentException("$firstElement parameter must be positive");
}
if ($max < $firstElement) {
throw new InvalidArgumentException("$firstElement parameter must be below or equal $max");
}
if (0 >= $secondElement) {
throw new InvalidArgumentException("$secondElement parameter must be positive");
}
if ($max < $secondElement) {
throw new InvalidArgumentException("$secondElement parameter must be below or equal $max");
}
}
public static function checkPositive($max)
{
if (0 >= (int)$max) {
throw new InvalidArgumentException('Total must be positive');
}
}
}
class Network extends NetworkAbstract
{
public function __construct($total)
{
Verifier::checkPositive($total);
$this->total = (int)$total;
}
/**
* @param Pair $pair
*
* @brief Check all groups, if they contain any element from the pair. If yes, add whole pair to this group
* @brief Otherwise, create new group with this pair
*
* @return void
*/
public function connect($firstElement, $secondElement)
{
Verifier::verify($this->total, $firstElement, $secondElement);
$pair = new Pair($firstElement, $secondElement);
foreach ($this->groups as $group) {
if ($group->contains($pair)) {
$group->add($pair);
return;
}
}
$this->groups[] = new ConnectedElementsGroup($pair);
}
/**
* @param $firstElement
* @param $secondElement
*
* @brief check all groups, if they contain first element of the pair
* @brief check all groups, if they contain second element of the pair
* @brief if both 1. and 2. are true, return true. Otherwise return false
*
* @return bool
*/
public function query($firstElement, $secondElement)
{
Verifier::verify($this->total, $firstElement, $secondElement);
$pair = new Pair($firstElement, $secondElement);
$elements = $pair->getElements();
$results = array(false, false);
if (empty($this->groups)) {
return false;
}
foreach ($this->groups as $group) {
if ($group->hasElement($elements[0])) {
$results[0] = true;
}
if ($group->hasElement($elements[1])) {
$results[1] = true;
}
}
return $results[0] && $results[1];
}
}
// DEBUG
$x = new Network(10);
$x->connect(1, 4);
$x->connect(4, 7);
$x->connect(1, 4);
var_dump($x->query(1, 7));
//var_dump($x->query(-50, 7));
var_dump($x->query(1, 10));
$x->connect(10, 7);
var_dump($x->query(1, 10));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment