Skip to content

Instantly share code, notes, and snippets.

@feynon
Created July 23, 2019 19:06
Show Gist options
  • Save feynon/63ae8ecb1abb03782bd6eec03cc1f348 to your computer and use it in GitHub Desktop.
Save feynon/63ae8ecb1abb03782bd6eec03cc1f348 to your computer and use it in GitHub Desktop.
const roads = [
"Alice's House-Bob's House", "Alice's House-Cabin",
"Alice's House-Post Office", "Bob's House-Town Hall",
"Daria's House-Ernie's House", "Daria's House-Town Hall",
"Ernie's House-Grete's House", "Grete's House-Farm",
"Grete's House-Shop", "Marketplace-Farm",
"Marketplace-Post Office", "Marketplace-Shop",
"Marketplace-Town Hall", "Shop-Town Hall"
];
function buildGraph(edges) {
let graph = Object.create(null);
function addEdge(from, to) {
if (graph[from] == null) {
graph[from] = [to];
} else {
graph[from].push(to);
}
}
for (let [from, to] of edges.map(r => r.split("-"))) {
addEdge(from, to);
addEdge(to, from);
}
return graph;
}
const roadGraph = buildGraph(roads);
class VillageState {
constructor(place, parcels) {
this.place = place;
this.parcels = parcels;
}
move(destination) {
if (!roadGraph[this.place].includes(destination)) {
return this;
} else {
let parcels = this.parcels
.map(p => {
if (p.place != this.place) return p;
return { place: destination, address: p.address };
})
.filter(p => p.place != p.address);
return new VillageState(destination, parcels);
}
}
}
let first = new VillageState(
"Post Office",
[{ place: "Post Office", address: "Alice's House" }]
);
let next = first.move("Alice's House");
console.log(next.place);
// → Alice's House
console.log(next.parcels);
// → []
console.log(first.place);
// → Post Office
function runRobot(state, robot, memory) {
for (let turn = 0; ; turn++) {
if (state.parcels.length == 0) {
console.log(`Done in ${turn} turns`);
break;
}
let action = robot(state, memory);
state = state.move(action.direction);
memory = action.memory;
console.log(`Moved to ${action.direction}`);
}
function randomPick(array) {
let choice = Math.floor(Math.random() * array.length);
return array[choice];
}
function randomRobot(state) {
return { direction: randomPick(roadGraph[state.place]) };
}
VillageState.random = function (parcelCount = 5) {
let parcels = [];
for (let i = 0; i < parcelCount; i++) {
let address = randomPick(Object.keys(roadGraph));
let place;
do {
place = randomPick(Object.keys(roadGraph));
} while (place == address);
parcels.push({ place, address });
}
return new VillageState("Post Office", parcels);
};
runRobot(VillageState.random(), randomRobot);
// → Moved to Marketplace
// → Moved to Town Hall
// → …
// → Done in 63 turns
//Now we will make a more sophsticated not so random but still not so intelligent robot
const mailRoute = [
"Alice's House", "Cabin", "Alice's House", "Bob's House",
"Town Hall", "Daria's House", "Ernie's House",
"Grete's House", "Shop", "Grete's House", "Farm",
"Marketplace", "Post Office"
];
function routeRobot(state, memory) {
if (memory.length == 0) {
memory = mailRoute;
}
return { direction: memory[0], memory: memory.slice(1) };
}
function findRoute(graph, from, to) {
let work = [{ at: from, route: [] }];
for (let i = 0; i < work.length; i++) {
let { at, route } = work[i];
for (let place of graph[at]) {
if (place == to) return route.concat(place);
if (!work.some(w => w.at == place)) {
work.push({ at: place, route: route.concat(place) });
}
}
}
};
function goalOrientedRobot({ place, parcels }, route) {
if (route.length == 0) {
let parcel = parcels[0];
if (parcel.place != place) {
route = findRoute(roadGraph, place, parcel.place);
} else {
route = findRoute(roadGraph, place, parcel.address);
}
}
return { direction: route[0], memory: route.slice(1) };
}
runRobotAnimation(VillageState.random(),
goalOrientedRobot, []);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment