-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjs.js
153 lines (137 loc) · 4.67 KB
/
js.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//every package has to be picked up and delivered some other place
//once every packaged has been picked up and delivered, the program is finished
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",
"Seth's House-Cabin"
];
//manual route created to run the mailman robot
const mailRoute = [
"Alice's House", "Cabin", "Seth'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 buildGraph(roads) {
let graph = Object.create(null);
function addPath(from, to) {
if (graph[from] == null) {
graph[from] = [to];
} else {
graph[from].push(to);
}
}
for (let [from, to] of roads.map(road => road.split("-"))) {
addPath(from, to);
addPath(to, from);
}
return graph;
}
const roadGraph = buildGraph(roads);
//helper functions
//makes a random selection from the roadGraph array
function randomPick(array) {
let choice = Math.floor(Math.random() * array.length);
return array[choice];
}
//use to find the shortest or one of the shortest routes
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)});
}
}
}
}
//robot types
//this is a robot that randomly picks its next destination
function randomRobot(state) {
return {direction: randomPick(roadGraph[state.place])};
}
//this robot keeps track of where it's been and removes
//a place its already been from its memory
//this is the mailman robot
function routeRobot(state, memory) {
if (memory.length == 0) {
memory = mailRoute;
}
return {direction: memory[0], memory: memory.slice(1)};
}
//smarter robot
function goalOrientedRobot({place, parcels}, route) {
if (route.length == 0) {
let parcel = parcels[0];
if (parcel.place != place) {
//find a route to pick up package
route = findRoute(roadGraph, place, parcel.place);
} else {
//find a route to deliver package
route = findRoute(roadGraph, place, parcel.address);
}
}
return {direction: route[0], memory: route.slice(1)};
}
//a class to keep track of 2 states
//1. - where the robot currently is
//2. - a parcels array that holds parcels
class VillageState {
constructor(place, parcels) {
//current location
this.place = place;
//array of object tupals, {place: "Bob's House", address: "Cabin"} first is pick up, second is delivery
this.parcels = parcels;
}
move(destination) {
if (!roadGraph[this.place].includes(destination)) {
return this;
} else {
let parcels = this.parcels.map(p => {
//if p.place is not where we currently are, then there is no package to pick up, so we just leave it alone
if (p.place != this.place) return p;
//else we pick that package up, and change its place to be the next place where headed, since we are just now going to carry it around with us until we find its spot to be delivered
return {place: destination, address: p.address};
//the filter is getting rid of packages that are ready to be delivered
}).filter(p => p.place != p.address);
return new VillageState(destination, parcels);
}
}
}
//function added to the state class to produce random parcels for testing
//our robot's route system
VillageState.random = function(parcelCount = 5) {
let parcels = [];
for (let i = 0; i < parcelCount; i++) {
//address is a delivery
let address = randomPick(Object.keys(roadGraph));
//place is a pick up
let place;
do {
place = randomPick(Object.keys(roadGraph));
} while (place == address);
parcels.push({place, address});
}
return new VillageState("Post Office", parcels);
};
//function to run the robot
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}`);
}
}
runRobot(VillageState.random(), goalOrientedRobot, []);