Code viewer for World: Breadth-first search (Kevi...
// Breadth-first search

// Port from:
// https://github.com/nature-of-code/NOC-S17-2-Intelligence-Learning/tree/master/week1-graphs/P2_six_degrees_kevin_bacon
// https://www.youtube.com/watch?v=piBq7VD0ZSo

// Hard to visualise graph 


  AB.headerRHS(); 

  AB.newDiv("selectdiv");
  
  $("#selectdiv").css({
      "margin": "30",
      });

  $("#selectdiv").html(" Pick an actor: <span id='actorlist'></span> ");

  const end_name = 'Kevin Bacon';


// Daniel Shiffman
// Nature of Code: Intelligence and Learning
// https://github.com/shiffman/NOC-S17-2-Intelligence-Learning

// Graph object

function Graph() 
{
  // store nodes by key and also in an array
  this.graph = {};
  this.nodes = [];
  // Start and end
  this.start = null;
  this.end = null;
}

// Set the start
Graph.prototype.setStart = function(node) 
{
  this.start = node;
}

// Set the end
Graph.prototype.setEnd = function(node) 
{
  this.end = node;
}

// Add a node
Graph.prototype.addNode = function(label) 
{
  var n = new Node(label);
  // Add to both the graph object and the nodes array
  this.graph[label] = n;
  this.nodes.push(n);
  return n;
}

// Clear all searched and parent values
Graph.prototype.clear = function() 
{
  for (var i = 0; i < this.nodes.length; i++) 
  {
    this.nodes[i].searched = false;
    this.nodes[i].parent = null;
  }
}







// Daniel Shiffman
// Nature of Code: Intelligence and Learning
// https://github.com/shiffman/NOC-S17-2-Intelligence-Learning

// Node object
function Node(label) 
{
  // Has a label
  this.label = label;
  // zero or more edges
  this.edges = [];
  // No parent and not searched by default
  this.parent = null;
  this.searched = false;
}

// Connect one or more neighbors
Node.prototype.connect = function(neighbor)         // one Node (movie) has a connection to another Node (person)
{
  // This is a fancy way of having a function
  // that can accept a variable number of arguments
  for (var i = 0; i < arguments.length; i++) 
  {
    this.edges.push(arguments[i]);              // increase the size of the array 
    // Connect both ways
    arguments[i].edges.push(this);
  }
}






// Daniel Shiffman
// Nature of Code: Intelligence and Learning
// https://github.com/shiffman/NOC-S17-2-Intelligence-Learning

// The data
var data;

// The graph
var graph;
// A lookup table for actors
// (redundant, the graph could handle this)
var actors;
// Dropdown menu for actors
var actorlist;

function preload() 
{
  data = loadJSON('/uploads/codingtrain/bacon.json');
}

function setup() 
{
//RQ This is the setup. This sets up the canvas, and runs before a button is clicked
 noCanvas();


  // Create the graph
  graph = new Graph();
  // A separate lookup table for actors
  actors = {};
  // For all movies
  var movies = data.movies;
  
  for (var i = 0; i < movies.length; i++) 
  {
    // Title and castlist
    var movie = movies[i].title;
    var cast = movies[i].cast;
    // Add the movie to the graph
    var movieNode = graph.addNode(movie);       // Node movie 
    // Go through all the cast list
    // console.log ("title and castlist setup for movie title " + movies[i].title);
    // console.log ("and for cast " + movies[i].cast);
    for (var j = 0; j < cast.length; j++) 
    {
      var name = cast[j];
      var actorNode;
      
      // Does the actor exist already?
      if (actors[name]) actorNode = actors[name];
      // If not add a new node
      else 
      {
        actorNode = graph.addNode(name);        // Node person 
        actors[name] = actorNode;
      }
      
      // Connect movie and actor
      movieNode.connect(actorNode);             // movie connects to person 
    }
  }

  // Create dropdown
  actorlist = createSelect();           // https://p5js.org/reference/#/p5/createSelect 
  actorlist.parent('actorlist');
  var allactors = Object.keys(actors);
  // Add all the actors
  for (var i = 0; i < allactors.length; i++) 
    actorlist.option(allactors[i]);

  
  // Set up an event
  actorlist.changed(findbacon);
}


function findbacon() 
{
  // RQ this function executes the once at runtime, once an actor is selected
  // Clear everyone from having been searched
  graph.clear();
  // Start and end
  var start = actors[actorlist.value()];
  var end = actors[end_name];
  graph.setStart(start);
  graph.setEnd(end);
  // Run the search!
  bfs();
}


function bfs() 
{
  // Create a queue ad path
  var queue = [];
  var path = [];
  //const end_name = 'Kevin Bacon';
  //graph.setEnd(end);

  // Get started
  queue.push(graph.start);
  //section of function up to this point executes once at runtime
  while (queue.length > 0)      // inside the loop we keep adding things to queue
  {
    var node = queue.shift();               // remove first item
    console.log ("======" );
    if (!node.searched)  //RQ FIX if statement fix added here to check if a node has been already added to the queue, if it has, then it is not queued again
    {
    console.log ("start of search of " + node.label);
    
    // Are we done?
    if (node == graph.end) 
    {
      console.log ("found goal node");
      // Figure out the path
      path.push(node);
      var next = node.parent;
      while (next) 
      {
        path.push(next);
        next = next.parent;
      }
      break;
    } 
    else
    {
     console.log ("checking neighbours of " + node.label);
     // Check all neighbors
      var next = node.edges;
      //console.log ("node.edges is " + node.edges);
	  //console.log ("end is " + end);
      //str = JSON.stringify(end);
      //str = JSON.stringify(end, null, 4); // (Optional) beautiful indented output.
      //console.log("string version of end is " + str); // Logs output to dev tools console.
     // if (node.edges==graph.end)  //object1.name === object2.name
      //{
       // console.log ("found goal node1 " + neighbor.label + " breaking out of function");			  
       // break;  			
     // }
      // console.log ("checking " + next.length + " neighbours");
      for (var i = 0; i < next.length; i++) 
      {
        var neighbor = next[i];
        //RQ FIX Add in fix here to check for goal node and if it returns then exit
        if (neighbor.label===end_name)  //object1.name === object2.name
        {
         // console.log ("found goal node2 " + neighbor.label + " breaking out of function");			  
         // break; 
          console.log ("found goal node "+neighbor.label); //print goal node to log
          // Figure out the path
		  path.push(graph.end); //add the goal("Kevin Bacon") to the end of the path output on screen
          path.push(node);
          var next = node.parent;
          while (next) 
          {
            path.push(next);
            next = next.parent;
          }
		  //var skip_to_end='y'
          break;		 
        }
		//console.log ("next[i].label is " + next[i].label);
		//console.log ("neighbor.label " + neighbor.label);
		//console.log ("graph.end " + graph.end);
        // Any neighbor not already searched add to queue
		// Any neighbor not already queued and searched add to queue
        if (!neighbor.searched) 
		{
          console.log ("adding unsearched neighbour " + neighbor.label + " to queue");
          queue.push(neighbor);
          // Update the parent
          neighbor.parent = node;
	      // Mark node as searched
        }
      }
      // Mark node as queued
      //node.queue = true;
      // Mark node as searched
      node.searched = true;
     console.log ("end of search of " + node.label);
    // console.log ("======" );
	}
	}
  }         // end of while loop
  

// now output path 
  console.log('finished search for path');
 // console.log ("path.length is " + path.length);
  // path = bacon + movie + x + movie + x ... + movie + x
  if (path.length===0) //RQ fix for path not found, if it is true, then print a "Path not found" messgae to output
  {
   // console.log('In the path not found if section');
    var s='Path not found'; 	  
  }
  else
  {  
    //console.log('In the standard closing else section');
    var s = '<h1> Path length ' + path.length + '</h1>';
  
    for (var i = path.length-1; i >= 0; i--) 
    {
      if (i % 2 == 0)  //RQ fix if statement to add highlighted text for the movie name
      {
        var path_highlight=path[i].label;
      }
      else 
      {
        var path_highlight='<h4>'+path[i].label+'</h4>';
      }
      s = s + path_highlight +"<br>";
    }	  
  }  
//  "<p style='color:red'>"+ "</p>"+
  
  AB.newDiv("theoutput");
  
  $("#theoutput").css({
      "margin": "30",
      "padding": "30",
      "display": "inline-block",
      "border": "1px solid black"
      });
	  
	  //      "font-weight": "900"
//	   "tr:odd": "#FF0000",
	//  "tr:even": "#00FF00"
 // $("#theoutput tr:odd").css("background", "#FF0000");
  //$("#theoutput tr:even").css("background", "#00FF00");

  $("#theoutput").html(s);


}