Step3_03_IteratedLinks = {
const graph = DeerialiseGraph(Step3_03_AddLinks);
console.log("processing links");
const get_last = (arr) => arr[arr.length - 1];
let iterations = 0;
graph.forEachNode(function (node) {
node.data = {
appears: node.links.length,
type:
node.links.length == 1
? "single"
: node.links.length == 2
? "double"
: "hub"
};
});
graph.forEachLink(function (link) {
if (!link) return;
if (link.fromId == link.toId) {
graph.removeLink(link);
}
});
function whittle() {
let idx = 0;
let errors = [];
iterations++;
let didMakeUpdates = false;
graph.forEachLink(function (link) {
if (!link) return;
// our link:
// ◎-●-●-●-◎
// | ↳ node_last
// ↳ node_first
const node_first = graph.getNode(link.data.absorbed[0]);
if (!node_first.data) {
node_first.data = {
appears: node_first.links.length,
type:
node_first.links.length == 1
? "single"
: node_first.links.length == 2
? "double"
: "hub"
};
}
const node_last = graph.getNode(get_last(link.data.absorbed));
if (!node_last.data) {
node_last.data = {
appears: node_last.links.length,
type:
node_last.links.length == 1
? "single"
: node_last.links.length == 2
? "double"
: "hub"
};
}
let operation_first = "ignore";
let operation_last = "ignore";
if (node_first.data.type == "single") {
// ▣-●-●-●-◎
// ↳ our first node is an endpoint
} else if (node_first.data.type == "hub") {
// >-●-●-●-◎
// ↳ our first node is a hub
} else if (node_first.data.type == "double") {
// ?-◉-●-●-●-◎
// ↳ our first node has links before it
operation_first = "absorb";
}
if (node_last.data.type == "single") {
// ◎-●-●-●-▣
// ↳ our last node is an endpoint
} else if (node_last.data.type == "hub") {
// ◎-●-●-●-<
// ↳ our last node is a hub
} else if (node_last.data.type == "double") {
// ◎-●-●-●-◉-?
// ↳ our last node has links before it
operation_last = "absorb";
}
if (node_first.id == node_last.id) {
operation_first = "ignore";
operation_last = "ignore";
}
let will_need_to_rewrite_link = false;
let absorbed = link.data.absorbed;
if (operation_first == "absorb") {
let invert = false;
const left_link_before_current_find = node_first.links.find((l) => {
if (l.id == link.id) return false;
else if (
l.data.absorbed.indexOf(node_last.id) ==
l.data.absorbed.length - 1
) {
invert = false;
return true;
} else if (l.data.absorbed.indexOf(node_last.id) == 0) {
invert = true;
return true;
}
});
/*
let left_link_before_current_find = node_first.links.find(
(l) => get_last(l.data.absorbed) == node_first.id
);*/
if (left_link_before_current_find) {
const left_link_after_current_find_absorbed = invert
? left_link_before_current_find.data.absorbed.toReversed()
: left_link_before_current_find.data.absorbed;
const node_attach_left_link = graph.getNode(
left_link_after_current_find_absorbed[0]
);
// ◉-●-◉-●-●-●-◎
// | | ↳ node_first
// | ↳ left_link_before_current_find
// ↳ node_attach_left_link
// what we want to do is remove left_link_before_current_find
// and rewrite node_attach_left_link to attach to our link.
will_need_to_rewrite_link = true;
absorbed = [
...left_link_after_current_find_absorbed, //.slice(0, -1),
...absorbed
];
// now we must remove node_first.
graph.removeNode(node_first.id);
graph.removeLink(left_link_before_current_find);
} else {
operation_first == "error";
errors.push(`LEFT_SIDE:${idx}`);
}
console.groupEnd();
}
if (operation_last == "absorb") {
let invert = false;
const right_link_after_current_find = node_last.links.find((l) => {
if (l.id == link.id) return false;
else if (l.data.absorbed.indexOf(node_last.id) == 0) {
invert = false;
return true;
} else if (
l.data.absorbed.indexOf(node_last.id) ==
l.data.absorbed.length - 1
) {
invert = true;
return true;
}
});
if (right_link_after_current_find) {
const right_link_after_current_find_absorbed = invert
? right_link_after_current_find.data.absorbed.toReversed()
: right_link_after_current_find.data.absorbed;
const node_attach_right_link = graph.getNode(
get_last(right_link_after_current_find_absorbed)
);
// ◎-●-●-●-◉-●-◉
// | | ↳ node_attach_right_link
// | ↳ right_link_after_current_find
// ↳ node_last
// what we want to do is remove right_link_after_current_find
// and rewrite node_attach_right_link to attach to our link.
will_need_to_rewrite_link = true;
absorbed = [
...absorbed,
...right_link_after_current_find_absorbed //.slice(1)
];
// now we must remove node_last.
graph.removeNode(node_last.id);
graph.removeLink(right_link_after_current_find);
} else {
operation_last = "error";
errors.push(`RIGHT_SIDE:${idx}`);
}
console.groupEnd();
}
if (will_need_to_rewrite_link) {
graph.removeLink(link);
graph.addLink(absorbed[0], get_last(absorbed), {
absorbed,
ops: {
left: operation_first,
right: operation_last
},
was_op: true
});
didMakeUpdates = true;
}
});
graph.forEachNode(function (node) {
node.data = {
appears: node.links.length,
type:
node.links.length == 1
? "single"
: node.links.length == 2
? "double"
: "hub"
};
});
return didMakeUpdates;
}
let keepRunning = true;
while (keepRunning == true) {
keepRunning = whittle();
}
console.log("Done in", iterations, "iterations...");
return SerialiseGraph(graph);
}