-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCompetitivePlanner.java
More file actions
197 lines (177 loc) · 6.69 KB
/
Copy pathCompetitivePlanner.java
File metadata and controls
197 lines (177 loc) · 6.69 KB
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
187
188
189
190
191
192
193
194
195
196
197
package planners;
import actions.Action;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import storygenerator.World;
import storygenerator.WorldProperty;
/**
* This planner allows the hero and the villain to take turns picking actions.
* It is based on the forward planner.
* @author etienne
*/
public class CompetitivePlanner extends Planner {
//Lists of world properties to make true or achieve in the plan
private ArrayList<WorldProperty> aHeroGoalsToMakeTrue;
private ArrayList<WorldProperty> aHeroGoalsToMakeFalse;
private ArrayList<WorldProperty> aAntiGoals;
public CompetitivePlanner(World pWorld) {
super(pWorld);
aHeroGoalsToMakeTrue = new ArrayList<WorldProperty>();
aHeroGoalsToMakeFalse = new ArrayList<WorldProperty>();
aAntiGoals = new ArrayList<WorldProperty>();
for (WorldProperty p : aWorld.getMainCharacter().getGoalsTrue()) {
aHeroGoalsToMakeTrue.add(p);
}
for (WorldProperty p : aWorld.getMainCharacter().getGoalsFalse()) {
aHeroGoalsToMakeFalse.add(p);
}
for (WorldProperty p : aWorld.getVillain().getAntiGoals()) {
aAntiGoals.add(p);
}
}
@Override
public boolean makePlan() {
aActionSequence = new LinkedList<Action>();
//Get all possible actions
ArrayList<Action> allHeroActions = aWorld.getHeroActions();
ArrayList<Action> allVillainActions = aWorld.getVillainActions();
//List to hold the world state and modify it
ArrayList<WorldProperty> currentWorldState = new ArrayList<WorldProperty>();
for (WorldProperty p : aWorld.getWorldState()) {
currentWorldState.add(p);
}
//Loop to add actions
//We add an action to the hero if i is even and to the villain if i is odd
int i = 0;
while (i < MAX_LENGTH
&& !aWorld.getMainCharacter().checkGoalCompletion(currentWorldState)
&& !aWorld.getVillain().checkAntiGoalCompletion(currentWorldState)) {
Action nextAction = allHeroActions.get(0);
if (i % 2 == 0) {
int distance = 99999;
Collections.shuffle(allHeroActions, rand);
for (Action a : allHeroActions) {
if (a.verifyPreconditions(currentWorldState)) {
ArrayList<WorldProperty> tempWorldState = new ArrayList<WorldProperty>();
for (WorldProperty p : currentWorldState) {
tempWorldState.add(p);
}
a.applyPostconditions(tempWorldState);
int d = computeDistanceFromGoal(a, tempWorldState, false);
if (d < distance) {
distance = d;
nextAction = a;
}
}
}
}
else {
//Villain action
int distance = 99999;
Collections.shuffle(allVillainActions);
for (Action a : allVillainActions) {
if (a.verifyPreconditions(currentWorldState)) {
ArrayList<WorldProperty> tempWorldState = new ArrayList<WorldProperty>();
for (WorldProperty p : currentWorldState) {
tempWorldState.add(p);
}
a.applyPostconditions(tempWorldState);
int d = computeDistanceFromGoal(a, tempWorldState, true);
if (d < distance) {
distance = d;
nextAction = a;
}
}
}
}
aActionSequence.add(nextAction);
nextAction.applyPostconditions(currentWorldState);
i++;
}
return true;
}
@Override
public void executePlan() {
aWorld.executeActionSequence(aActionSequence);
}
/**
* Heuristic to help choose an action. The lowest it is, the likeliest the
* action is to be taken. Things taken into account are:
* - number of unsolved goals (weight: 5)
* - number of times this exact action has been taken (weight: 2)
* - number of times an action with the same type has been taken (weight: 1)
* @param pAction
* @param pWorldState
* @return
*/
public int computeDistanceFromGoal(Action pAction, ArrayList<WorldProperty> pWorldState, boolean pIsVillain) {
int total = 0;
if (!pIsVillain) total = total + (5*countUnsolvedGoals(pWorldState));
else total = total + (5*countUnsolvedAntiGoals(pWorldState));
total = total + (2*countExactOccurrences(pAction));
total = total + (1*countTypeOccurrences(pAction));
return total;
}
/**
* Heuristic to determine how close a world state is to goal completion.
* It just counts the number of goals that are not satisfied in the world
* state.
* @return
*/
public int countUnsolvedGoals(ArrayList<WorldProperty> pWorldState) {
int total = 0;
for (WorldProperty tp : aHeroGoalsToMakeTrue) {
if (!pWorldState.contains(tp)) {
total++;
}
}
for (WorldProperty fp : aHeroGoalsToMakeFalse) {
if (pWorldState.contains(fp)) {
total++;
}
}
return total;
}
/**
* Returns 1 if at least one antigoal is fulfilled, 0 otherwise.
* @return
*/
public int countUnsolvedAntiGoals(ArrayList<WorldProperty> pWorldState) {
for (WorldProperty ag : aAntiGoals) {
if (pWorldState.contains(ag)) {
return 1;
}
}
return 0;
}
/**
* Counts occurrences of pAction in the action sequence (completely equal
* actions only).
* @param pAction
* @return
*/
public int countExactOccurrences(Action pAction) {
int total = 0;
for (Action a : aActionSequence) {
if (a.equals(pAction)) {
total++;
}
}
return total;
}
/**
* Counts occurrences of pAction in the action sequence (same action type).
* @param pAction
* @return
*/
public int countTypeOccurrences(Action pAction) {
int total = 0;
for (Action a : aActionSequence) {
if (a.getClass().getName().equals(pAction.getClass().getName())) {
total++;
}
}
return total;
}
}