Choxx Choxx - 6 months ago 10
PHP Question

Solving Hydra-Shield - PHP

Below is a php script for this algorithmic problem:


The SHIELD is a secretive organization entrusted with the task of
guarding the world against any disaster. Their arch nemesis is the
organization called HYDRA. Unfortunately some members from HYDRA had
infiltrated into the SHIELD camp. SHIELD needed to find out all these
infiltrators to ensure that it was not compromised.

Nick Fury, the executive director and the prime SHIELD member figured out that every one in SHIELD could send a SOS signal to every
other SHIELD member he knew well. The HYDRA members could send bogus
SOS messages to others to confuse others, but they could never receive
a SOS message from a SHIELD member. Every SHIELD member would receive
a SOS message ateast one other SHIELD member, who in turn would have
received from another SHIELD member and so on till NickFury. SHIELD
had a sophisticated mechanism to capture who sent a SOS signal to
whom. Given this information, Nick needed someone to write a program
that could look into this data and figure out all HYDRA members.


Sample Input

Nick Fury : Tony Stark, Maria Hill, Norman Osborn
Hulk : Tony Stark, HawkEye, Rogers
Rogers : Thor,
Tony Stark: Pepper Potts, Nick Fury
Agent 13 : Agent-X, Nick Fury, Hitler
Thor: HawkEye, BlackWidow
BlackWidow:Hawkeye
Maria Hill : Hulk, Rogers, Nick Fury
Agent-X : Agent 13, Rogers
Norman Osborn: Tony Stark, Thor

Sample Output

Agent 13, Agent-X, Hitler


SCRIPT.php



<?php
//this is the input
$input="Nick Fury : Tony Stark, Maria Hill, Norman Osborn
Hulk : Tony Stark, HawkEye, Rogers
Rogers : Thor
Tony Stark: Pepper Potts, Nick Fury
Agent 13 : Agent-X, Nick Fury, Hitler
Thor: HawkEye, BlackWidow
BlackWidow:HawkEye
Maria Hill : Hulk, Rogers, Nick Fury
Agent-X : Agent 13, Rogers
Norman Osborn: Tony Stark, Thor";

/*this is an array for storing shield member names as
key-value pairs like Nick Fury=>Tony Stark, Maria Hill, Norman Osborn*/
$shield=array();


$keys=array(); //array for storing shield member names as keys
$values=array(); //array for storing shield member names as value


$shield_members=array(); //array which stores each valid shield member's name using below process
//$hydra=array();


$rows = explode("\n", $input); //creating array of given input row wise



$i=0;
//considering each row at once
while ($i<count($rows)) {
# code...
$temp=explode(":", $rows[$i]); //exploding row
$key=trim($temp[0]); //getting key
$value=trim($temp[1]); //getting value

$keys[]=$key; //storing each key in keys[]

$values[]=$value; //storing each value in values[]
$shield[$key]=$value; //storing these key-value pair as array in shield[]
$i++;
}

//loop to find all persons who are receiving messages from anyone
$i=0;
$recieiver_hydra=array(); //arrray to store all persons receiving messages
while($i<count($values)){
$temp = explode(",", $values[$i]); //exploding RHS values row wise
$j=0;
while ($j<count($temp)) {
# code...
if(!in_array($temp[$j], $recieiver_hydra)) //trying insert only unique values in recieiver_hydra[]
$recieiver_hydra[]=$temp[$j]; //========BUT NOT GETTING=======
$j++;

}

$i++;
}


$shield_members[]= "Nick Fury"; //starting from Nick Fury

$temp = explode(",",$shield["Nick Fury"]); //getting value from shield[] array for given key

$i=0;
while($i<count($temp)){
$shield_members[]= $temp[$i]; //adding shield members which are valid not the hydra people
$i++;
}

/* searching process for each valid shield member starting from nick fury upto last one found
and storing them in the sheil_members[] array */
for($i=1; $i<30; $i++){ //=============HERE DON'T GETTING WHAT SHOULD BE THE CONDITION TO STOP EXECUTING
if (array_key_exists(trim($shield_members[$i]),$shield))
$temp = explode(",",$shield[trim($shield_members[$i])]);
else continue;
$j=0;
while ($j<count($temp)) {
# code...

$shield_members[] = trim($temp[$j]);
$j++;
}


}


$i=0;
//printing all valid members added to shield_members[] including duplicate values
while ( $i<count($shield_members)) {
# code...
echo $shield_members[$i]."<br>";
$i++;
}

asort($shield_members); //sorting them

$res1 = array_diff($keys, $shield_members); //finding difference and getting HYDRA members from LHS
$res2= array_diff($recieiver_hydra, $shield_members); //finding difference and getting HYDRA members from RHS ======BUT NOT GETTING





/*
<form action=<?php echo $_SERVER["PHP_SELF"]?> method="POST">
**<i> Enter input in the textarea... </i>
<textarea name="input" rows="10" cols="90"></textarea><br>
<input type="submit" name="submit" value="Find HYDRA Members">

</form>
*/
?>


As per my coding and expectations,
$res1
must be having all HYDRA members from LHS of inputs and
$res2
must be having all HYDRA members from RHS of input.
But when printing them I am getting wrong results.

$res1 = Array ( [4] => Agent 13 [8] => Agent-X ) //THIS IS CORRECT
$res2 = Array ( [3] => HawkEye [4] => Rogers [7] => Nick Fury
[8] => Agent-X [9] => Hitler [11] => BlackWidow
[13] => Agent 13 [14] => Thor ) //WRONG RESULTS


Please help me knowing what am I doing wrong?
(I am not expert at algorithms. Whole this code I made using raw coding ideas and knowledge.)

Answer

This sounds like a exercise from some programming course. Normally i would say, that you should solve such a task by yourself (I think this will be the reason for the down votes of your question), but it is a funny problem, so here is my solution.

If i need to implement a new algorithm, i always try to split the problem into subproblems. Doing so,

  • it is easier to find a good solution
  • as result you get a much more readable code

So problem number one is to transform the input into an array structure to work with:

function transformInput($input) {
  foreach (explode("\n", $input) as $row) {
    list($receiver, $senders) = explode(':', $row);
    $memberTree[trim($receiver)] = array_map('trim', explode(',', $senders));    
  }
  return $memberTree;
}

The second problem is to find all real SHIELD members:

function extractShieldMembers($memberTree, $startMember, $shieldMembers = array()) {
  $shieldMembers[] = $startMember;  
  if (array_key_exists($startMember, $memberTree)) {
    foreach ($memberTree[$startMember] as $member) {
      if (!in_array($member, $shieldMembers)) {
        $shieldMembers = array_merge(
          $shieldMembers, 
          extractShieldMembers($memberTree, $member, $shieldMembers)
        );
      }
    }
  }
  return $shieldMembers;
}

With this two functions in your library, it is very easy to get the list with all SHIELD members:

$memberTree = transformInput($input);
$shieldMembers = array_unique(extractShieldMembers($memberTree, 'Nick Fury'));

Now, after knowing who really belongs to SHIELD you can find all HYDRA members with this functon:

function getHydraMembers($memberTree, $shieldMembers){
  $allMembers = array();
  foreach ($memberTree as $key => $value) {
    $allMembers[] = $key;
    $allMembers = array_merge($allMembers, $value);
  }
  return array_unique(array_diff($allMembers, $shieldMembers));
}

$hydraMembers = getHydraMembers($memberTree, $shieldMembers);

Is this the best solution for this problem? I don't think so, because it was just a quick approach. But as you can see, if you try to split your code into small logic functions, you get more readable code, that you can better debug. You also don't need as many temporary variables and counter.

Comments