Skip to content

Commit 7041fef

Browse files
Updated solve signature for compatibility. Updated version numbers and readme.
1 parent 37906ef commit 7041fef

File tree

6 files changed

+51
-13
lines changed

6 files changed

+51
-13
lines changed

dockworkerrobot.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
var strips = require('./strips');
1+
var strips = require('strips');
22
strips.verbose = true;
33

44
// Load the domain and problem.
55
strips.load('./examples/dockworkerrobot/domain.txt', './examples/dockworkerrobot/problem.txt', function(domain, problem) {
66
// Use A* search to run the problem against the domain.
7-
var solutions = strips.solve(domain, problem, null, null, cost);
7+
var solutions = strips.solve(domain, problem, cost);
88

99
// Display solution.
1010
var solution = solutions[0];

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "strips-demo",
3-
"version": "0.0.2",
3+
"version": "0.0.3",
44
"description": "Basic AI planning with STRIPS and PDDL.",
55
"author": {
66
"name": "Kory Becker",

starcraft.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
var strips = require('./strips');
1+
var strips = require('strips');
22
strips.verbose = true;
33

44
// Load the domain and problem.
55
strips.load('./examples/starcraft/domain.txt', './examples/starcraft/marine.txt', function(domain, problem) {
66
// Use A* search to run the problem against the domain.
7-
var solutions = strips.solve(domain, problem, null, null, cost);
7+
var solutions = strips.solve(domain, problem, cost);
88

99
// Display solution.
1010
var solution = solutions[0];

strips/Readme.md

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ Methods
5555

5656
Loads a domain and problem PDDL file and returns a domain and problem object in the callback.
5757

58-
#### solve(domain, problem, isDepthFirstSearch = true, maxSolutions = 1)
58+
#### solve(domain, problem, isDepthFirstSearch = true, maxSolutions = 1, cost = null)
5959

60-
Searches for a solution to the given problem by using depth-first-search or breadth-first-search. The default setting uses depth-first-search and returns the first solution found. To return more solutions, set maxSolutions to a higher value. Note, you can write your own solution algorithm by using the methods below.
60+
Searches for a solution to the given problem by using depth-first-search, breadth-first-search, or A*. The default setting uses depth-first-search and returns the first solution found. To return more solutions, set maxSolutions to a higher value. To use A* search, provide a function for the "cost" parameter, using the format cost(state), to serve as a heuristic for A*. The function should return an integer, representing the cost of the given state. See [starcraft.js](https://github.com/primaryobjects/strips/blob/master/starcraft.js) for an example. The cost function may also be passed as the 3rd parameter (ie., solve(domain, problem, cost)). Note, you can also write your own solution algorithm by using the methods below.
6161

6262
#### getChildStates(domain, state)
6363

@@ -164,11 +164,34 @@ Of course, the real power is in designing your own search algorithm using the st
164164

165165
### A* Search
166166

167-
You can implement your own A* search to find a solution. A* works by using a heuristic to guide it down the path of possible moves in the domain. In this manner, it is much faster than simple breadth-first or depth-first search. It will also find an optimal solution that contains the least number of steps.
167+
A* search works by using a heuristic to guide it down the path of possible moves in the domain. In this manner, it is much faster than simple breadth-first or depth-first search. It will also find an optimal solution that contains the least number of steps.
168168

169-
Since the strips library exposes its internal methods, you can implement your own search algorithm. Here is an [example](https://github.com/primaryobjects/strips/blob/master/starcraft.js) of an A* search method for the [starcraft](https://github.com/primaryobjects/strips/blob/master/examples/starcraft/domain.txt) domain, to train a [marine](https://github.com/primaryobjects/strips/blob/master/examples/starcraft/marine.txt).
169+
Strips comes with a built-in A* search algorithm that accepts your own cost function to use as a heuristic. See the section "methods" above. You simply write your own cost function that takes "state" as input and returns an integer as the resulting cost. Here is an [example](https://github.com/primaryobjects/strips/blob/master/starcraft.js) from the Starcraft [domain](https://github.com/primaryobjects/strips/blob/master/examples/starcraft/domain.txt) to train a [marine](https://github.com/primaryobjects/strips/blob/master/examples/starcraft/marine.txt):
170170

171-
The core idea to a custom search method is to use the strips methods isGoal() and getChildStates() to iterate through all states and actions. Once you have a list of child states, apply your heuristic to calculate a cost for each state. Then sort the states by cost so that A* can choose the next cheapest state to move to. You can see the details in the example.
171+
```javascript
172+
var solutions = strips.solve(domain, problem, cost);
173+
174+
function cost(state) {
175+
// This is our A* heuristic method to calculate the cost of a state.
176+
// For Starcraft, the heuristic will be how many required buildings have been built. Subtract x from cost for each correct building, with 0 meaning all required buildings have been made and we're done.
177+
var cost = 10;
178+
179+
for (var i in state.actions) {
180+
var action = state.actions[i].action;
181+
182+
if (action == 'depot') {
183+
cost -= 5;
184+
}
185+
else if (action == 'barracks') {
186+
cost -= 5;
187+
}
188+
}
189+
190+
return cost;
191+
}
192+
```
193+
194+
You can also implement your own A* search to find a solution. Since the strips library exposes its internal methods, you can implement your own search algorithm. The core idea to a custom search method is to use the strips methods isGoal() and getChildStates() to iterate through all states and actions. Once you have a list of child states, apply your heuristic to calculate a cost for each state. Then sort the states by cost so that A* can choose the next cheapest state to move to. You can see the details in the solve() methods in strips.
172195

173196
Have fun!
174197

strips/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "strips",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"description": "Basic AI planning with STRIPS and PDDL.",
55
"author": {
66
"name": "Kory Becker",
@@ -43,6 +43,6 @@
4343
"sussman",
4444
"sussman anomaly"
4545
],
46-
"_id": "[email protected].3",
46+
"_id": "[email protected].4",
4747
"_from": "strips"
4848
}

strips/strips.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,27 @@ StripsManager = {
553553

554554
solve: function(domain, problem, isDfs, maxSolutions, cost) {
555555
// Find solution using A*, depth-first, or breadth-first search.
556-
if (isDfs == null) {
556+
if (typeof(isDfs) == 'function' && !cost) {
557+
// Allow passing cost as 3rd parameter.
558+
cost = isDfs;
559+
}
560+
else if (isDfs == null) {
561+
// If no other option specified, use depth-first-search by default.
557562
isDfs = true;
558563
}
559564

560565
maxSolutions = maxSolutions || 1;
561566

567+
if (cost && typeof(cost) != 'function') {
568+
console.log('ERROR: parameter "cost" must be a function to serve as the A* algorithm heuristic. Method: solve(domain, problem, isDepthFirstSearch, cost, maxSolutions). Usage: solve(domain, problem), solve(domain, problem, false), solve(domain, problem, cost).');
569+
return;
570+
}
571+
572+
if (StripsManager.verbose) {
573+
console.log('Using ' + (cost ? 'A*' : (isDfs ? 'depth' : 'breadth') + '-first-search') + '.');
574+
console.log('');
575+
}
576+
562577
return cost ? StripsManager.solveAs(domain, problem.states[0], problem.states[1], cost) :
563578
(isDfs ? StripsManager.solveDfs(domain, problem.states[0], problem.states[1], maxSolutions) :
564579
StripsManager.solveBfs(domain, problem.states[0], problem.states[1], maxSolutions));

0 commit comments

Comments
 (0)