Date: 2019/10/27
Lecturer: 土豆
設計一個Robot,幫我們拿取包裹,並送至指定地點
這是村莊的地圖
如果用OOP的概念該怎麼設計這個程式
1. Robot
這個程式中的物件有哪些?
2. Village
3. Parcel
4. Place
......
全部寫成Class!
如果你是這樣想,那就錯了
物件導向這種東西,剛剛好就好
不是你(X
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"
];
一種資料結構
{
'Alice\'s House': [ 'Bob\'s House', 'Cabin', 'Post Office' ],
'Bob\'s House': [ 'Alice\'s House', 'Town Hall' ],
Cabin: [ 'Alice\'s House' ],
'Post Office': [ 'Alice\'s House', 'Marketplace' ],
'Town Hall': [ 'Bob\'s House', 'Daria\'s House', 'Marketplace', 'Shop' ],
'Daria\'s House': [ 'Ernie\'s House', 'Town Hall' ],
'Ernie\'s House': [ 'Daria\'s House', 'Grete\'s House' ],
'Grete\'s House': [ 'Ernie\'s House', 'Farm', 'Shop' ],
Farm: [ 'Grete\'s House', 'Marketplace' ],
Shop: [ 'Grete\'s House', 'Marketplace', 'Town Hall' ],
Marketplace: [ 'Farm', 'Post Office', '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;
}
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);
}
}
}
Place: 目前robot所在地
Parcels: 待送包裹
parcels:
[ { place: 'Marketplace', address: 'Bob\'s House' },
{ place: 'Alice\'s House', address: 'Marketplace' },
{ place: 'Bob\'s House', address: 'Daria\'s House' },
{ place: 'Town Hall', address: 'Post Office' },
{ place: 'Post Office', address: 'Ernie\'s House' } ]
如果目的地不在graph上,則不動
否則
1. 確認所有parcel
2. 過濾掉已經到達地點的包裹,亦即place = address
如果目前不在包裹的位置,則包裹狀態不變
如果在包裹目前位置(原本初始位置 or 正被你帶在身上),則更新包裹位置至目標地點
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);
}
}
// Class VillageState
let first = new VillageState(
"Post Office",
[{place: "Post Office", address: "Alice's House"}]
);
let next = first.move("Alice's House");
console.log(first.place);
// → Post Office
console.log(next.place);
// → Alice's House
console.log(next.parcels);
// → []
function randomPick(array) {
let choice = Math.floor(Math.random() * array.length);
return array[choice];
}
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);
};
定義成static
function randomPick(array) {
let choice = Math.floor(Math.random() * array.length);
return array[choice];
}
class VillageState {
// constructor
// move
static random(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);
}
}
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}`);
}
}
// buildGraph
// Class Village
// runRobot
function randomPick(array) {
let choice = Math.floor(Math.random() * array.length);
return array[choice];
}
function randomRobot(state) {
return {direction: randomPick(roadGraph[state.place])};
}
它不需要memory
// ...
runRobot(VillageState.random(), randomRobot, []);
// Your code
runRobotAnimation(VillageState.random(), randomRobot, []);
// buildGraph
// Class Village
// runRobot
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)};
}
OK!
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 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 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"
];
const roadGraph = buildGraph(roads);
function findRoute(graph, from, to) {
let work = [{at: from, route: []}];
for (let i = 0; i < work.length; i++) {
console.log("------------------------------------");
console.log(work[i]);
console.log(work);
let {at, route} = work[i];
for (let place of graph[at]) {
console.log(place);
if (place == to) return route.concat(place);
if (!work.some(w => w.at == place)) {
work.push({at: place, route: route.concat(place)});
}
}
}
}
console.log(findRoute(roadGraph, "Alice's House", "Shop"));
function goalOrientedRobot(state, route) {
if (route.length == 0) {
let parcel = state.parcels[0];
if (parcel.place != state.place) {
route = findRoute(roadGraph, state.place, parcel.place);
} else {
route = findRoute(roadGraph, state.place, parcel.address);
}
}
return {direction: route[0], memory: route.slice(1)};
}