Skip to content

Instantly share code, notes, and snippets.

@bluepnume
Last active February 7, 2020 06:29
Show Gist options
  • Save bluepnume/3b57e5340330513713ce1e6037280fe5 to your computer and use it in GitHub Desktop.
Save bluepnume/3b57e5340330513713ce1e6037280fe5 to your computer and use it in GitHub Desktop.
// Number of nodes
let NUM_NODES = 10;
// Connections between nodes
let CONNECTIONS = {
0: [ 1, 3 ],
1: [ 2, 3, 4 ],
2: [ 5 ],
3: [ 6 ],
4: [ 5, 7 ],
5: [ 7, 8 ],
6: [ 7, 9 ]
};
// Limit for active nodes to win game
let MAX_ACTIVE = 5;
// Starting node index to link
let START_NODE = 2;
// End node index to link
let END_NODE = 9;
// Range of numbers from 0..n
let range = (n) => {
return Array(n).fill(0).map((_, i) => i);
}
// Node instance
let node = (index) => {
let active = false;
let linkedNodes = [];
let getIndex = () => {
return index;
}
let isActive = () => {
return active;
}
let deactivate = () => {
active = false
}
let toggle = (toggleLinkedNodes = true) => {
active = !active;
if (toggleLinkedNodes) {
linkedNodes.forEach(linkedNode => linkedNode.toggle(false));
}
};
let getActiveSiblingNodes = () => {
return linkedNodes.filter(sibling => sibling.isActive());
};
let link = (otherNode) => {
linkedNodes.push(otherNode);
};
return { getIndex, isActive, deactivate, toggle, link, getActiveSiblingNodes };
}
// Set all nodes to inactive
let reset = (nodes) => {
nodes.forEach(node => node.deactivate());
}
// Check if we won the game
let didWin = (nodes, startIndex, endIndex, maxActive) => {
let count = 0;
let currentNode = nodes[startIndex];
let visitedNodes = {};
if (nodes.filter(node => node.isActive()).length > MAX_ACTIVE) {
return false;
}
while (count < maxActive) {
count += 1;
let currentIndex = currentNode.getIndex();
if (visitedNodes[currentIndex]) {
return false;
}
visitedNodes[currentIndex] = true;
if (currentIndex === endIndex) {
return true;
}
let unvisitedSiblingNodes = currentNode.getActiveSiblingNodes()
.filter(siblingNode => !visitedNodes[siblingNode.getIndex()]);
if (unvisitedSiblingNodes.length !== 1) {
return false;
}
currentNode = unvisitedSiblingNodes[0];
}
return false;
}
// Get array of linked nodes
let setupNodes = (numNodes, connections) => {
let nodes = range(numNodes).map(node);
for (let i in connections) {
i = parseInt(i);
for (let j of connections[i]) {
nodes[i].link(nodes[j]);
nodes[j].link(nodes[i]);
}
}
return nodes;
}
// Get all unique permutations from [ 0 * length ] to [ range * length ]
let permutations = (options, length, callback) => {
options.forEach(option => {
if (length === 1) {
callback([ option ]);
} else {
permutations(options.filter(opt => opt !== option), length -1, (permutation) => {
callback([ option, ...permutation ]);
});
}
});
}
let attemptMoves = (nodes, moves) => {
reset(nodes);
moves.forEach(move => {
nodes[move].toggle();
});
if (didWin(nodes, START_NODE, END_NODE, MAX_ACTIVE)) {
return true;
}
return false;
}
let playGame = () => {
let nodes = setupNodes(NUM_NODES, CONNECTIONS);
let attempted = {};
let numMoves = 1;
while (numMoves <= NUM_NODES) {
console.log('Attempting to win in', numMoves, 'moves');
permutations(range(NUM_NODES), numMoves, (moves) => {
moves.sort();
if (attempted[moves]) {
return;
}
attempted[moves] = true;
if (attemptMoves(nodes, moves)) {
console.log('Winner winner:', moves.map(move => move + 1).join(' -> '));
}
});
numMoves += 1;
}
}
playGame();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment