-
Notifications
You must be signed in to change notification settings - Fork 77
/
Planner.ts
186 lines (155 loc) · 6.4 KB
/
Planner.ts
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import {WorldState} from "./World";
import {Successor, Graph, SearchResult} from "./Graph";
import {aStarSearch} from "./AStarSearch";
import {ShrdliteResult, DNFFormula, Literal} from "./Types";
/********************************************************************************
** Planner
The goal of the Planner module is to take the interpetation(s)
produced by the Interpreter module and to plan a sequence of
actions for the robot to put the world into a state compatible
with the user's command, i.e. to achieve what the user wanted.
You should implement the function 'makePlan'.
The planner should use your A* search implementation to find a plan.
********************************************************************************/
//////////////////////////////////////////////////////////////////////
// exported functions, classes and interfaces/types
/* Top-level driver for the Planner.
* It calls `makePlan` for each given interpretation generated by the Interpreter.
* You don't have to change this function.
*
* @param interpretations: List of possible interpretations.
* @param world: The current state of the world.
* @returns: List of planner results, which are the interpretation results augmented with plans.
* Each plan is represented by a list of strings.
* If there's a planning error, it throws an error with a string description.
*/
export function plan(interpretations : ShrdliteResult[], world : WorldState) : ShrdliteResult[] {
var errors : string[] = [];
var plans : ShrdliteResult[] = [];
var planner : Planner = new Planner(world);
for (var result of interpretations) {
try {
var theplan : string[] = planner.makePlan(result.interpretation);
} catch(err) {
errors.push(err);
continue;
}
result.plan = theplan;
if (result.plan.length == 0) {
result.plan.push("The interpretation is already true!");
}
plans.push(result);
}
if (plans.length == 0) {
// merge all errors into one
throw errors.join(" ; ");
}
return plans;
}
/* The core planner class.
* The code here are just templates; you should rewrite this class entirely.
* In this template, the code produces a dummy plan which is not connected
* to the argument 'interpretation'. Your version of the class should
* analyse 'interpretation' in order to figure out what plan to return.
*/
class Planner {
constructor(
private world : WorldState
) {}
/* The core planner method.
* Note that you should not change the API (type) of this method, only its body.
* This method should call the A* search implementation with
* your implementation of the ShrdliteGraph.
*
* @param interpretation: The logical interpretation of the user's desired goal.
* @returns: A plan, represented by a list of strings.
* If there's a planning error, it throws an error with a string description.
*/
makePlan(interpretation : DNFFormula) : string[] {
// This currently returns a dummy plan which picks up a random object
// and moves it around before dropping it down.
var state = this.world;
var plan : string[] = [];
// Select a random nonempty stack
do {
var pickstack = Math.floor(Math.random() * state.stacks.length);
} while (state.stacks[pickstack].length == 0);
// First move the arm to the selected stack
if (pickstack < state.arm) {
plan.push("Moving left to stack " + pickstack);
for (var i = state.arm; i > pickstack; i--) {
plan.push("l");
}
} else if (pickstack > state.arm) {
plan.push("Moving right to stack " + pickstack);
for (var i = state.arm; i < pickstack; i++) {
plan.push("r");
}
}
// Then pick up the topmost object in the selected stack
var obj = state.stacks[pickstack][state.stacks[pickstack].length-1];
plan.push("Picking up the " + state.objects[obj].form,
"p");
if (pickstack > 0) {
// Then move the arm to the leftmost stack
plan.push("Moving as far left as possible");
for (var i = pickstack; i > 0; i--) {
plan.push("l");
}
}
// Select a random destination stack (either empty or the original pickup stack)
do {
var dropstack = Math.floor(Math.random() * state.stacks.length);
} while (!(state.stacks[dropstack].length == 0 || dropstack == pickstack));
if (dropstack > 0) {
// Then move the arm to the destination stack
plan.push("Moving right to the destination stack " + dropstack);
for (var i = 0; i < dropstack; i++) {
plan.push("r");
}
}
// Finally put the object down again
plan.push("Dropping the " + state.objects[obj].form,
"d");
return plan;
}
}
//////////////////////////////////////////////////////////////////////
// A* search nodes, to be implemented and cleaned
class ShrdliteNode {
constructor(
public first_field : number,
public second_field : string,
public another_field : Literal // Note: you probably don't want any Literal here...
) {
this.id = "TO BE IMPLEMENTED FROM THE FIELDS";
}
// These are for making the nodes possible to compare efficiently:
public id : string;
public toString() : string {
return this.id;
}
public compareTo(other : ShrdliteNode) {
return this.id.localeCompare(other.id);
}
// Possibly some additional private fields or methods:
private private_field : string;
private privateMethod(argument : string) : number {
throw "Not implemented";
}
}
//////////////////////////////////////////////////////////////////////
// A* search graph, to be implemented and cleaned
class ShrdliteGraph implements Graph<ShrdliteNode> {
successors(current : ShrdliteNode) : Successor<ShrdliteNode>[] {
throw "Not implemented";
}
compareNodes(a : ShrdliteNode, b : ShrdliteNode) : number {
return a.compareTo(b);
}
// Possibly some additional private fields or methods:
private private_field : string;
private privateMethod(argument : string) : number {
throw "Not implemented";
}
}