Repository navigation
Expand file tree
/
Copy pathmain.cpp
More file actions
322 lines (276 loc) · 10.6 KB
/
Copy pathmain.cpp
File metadata and controls
322 lines (276 loc) · 10.6 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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
//
// main.cpp
// Project Beta Draft 2 - Working QLearner
//
// Created by Jan Lao on 3/18/17.
// Copyright © 2017 University Nevada, Reno. All rights reserved.
//
#include <algorithm>
#include <iostream>
#include <assert.h>
#include <vector>
#include <random>
#include <fstream>
#define LYRAND (double)rand()/RAND_MAX
using namespace std;
long int supergoodreward = 100000;
/////================== Class: Agent ========================
class Agent{
public:
void set_state(int s); //SENSE();
int decide(); //DECIDE();
void react(double r); //REACT();
void Qtableinit();
int state_alt;
int prevstate_alt;
int state;
int prevstate;
//Learner Inputs
int action;
double reward;
double maxvalue;
int maxindex;
//Qlearner stuff
double alpha = 0.1;
double epsilon = 0.1;
double gamma = 0.9;
vector<vector<double>> Qtable;
vector<double> Qrow;
double Q;
double Qmax;
void TestD(vector<vector<double>> Qtable, vector<double> Qrow);
void TestF();
};
/////============== Class: GridWorld =========================
class GridWorld {
public:
//Preliminary Initializers
void calc_agentstate();
void start();
int run(); //AGENT: ACT();
//Agent Input
int choice;
//GridWorld stuff
int x_dim;
int y_dim;
int body_x;
int body_y;
int target_x;
int target_y;
Agent* p1;
//Qtable Construction
vector<vector<double>> Qtable;
vector<double> Qrow;
void TestE();
void TestG();
};
/////--------------- Agent Functions -------------------------
//// Set state function
void Agent::set_state(int s){ //Did this back in the day.
state = s;
state_alt = s;
}
void Agent::Qtableinit(){ // Did this back in the day.
for(int i=0; i<25; i++){ // (x_dim+1)*(y_dim+1)
for(int j=0; j<4; j++){ //4 zero's in one row ~ For each direction
Qrow.push_back(LYRAND); //Initialize a row of nums close-to-zero's. Qrow is a vector per iteration (state).
}
//Qrow.resize(4);
Qtable.push_back(Qrow); //Initialize a table of zero's
Qrow.clear(); //Stop the rows from increasing in size every state iteration
}
}
//// Decide() Function
int Agent::decide(){
action = 0;
double placeholder = LYRAND;
cout << placeholder << endl; //debugging
if (placeholder <= epsilon){
//Choose the random action (epsilon)% of the time
cout << "Random action taken..." << endl;
action = rand()%4;
}
else if(placeholder > epsilon){ //BELOW is bubble structure found online.
cout << "Greedy action taken..." << endl;
//cout << Qtable.at(state).at(0) << "..." << Qtable.at(state).at(1) << "..." << Qtable.at(state).at(2) << "..." << Qtable.at(state).at(3) << endl; //debugging purposes
maxindex = 0;
maxvalue = *max_element(Qtable.at(state).begin(), Qtable.at(state).end());
for(int c=0;c<4;c++){
if(Qtable.at(state).at(c) == maxvalue){ //Finding its index in the original Qrow vector
maxindex = c;
}
}
action = maxindex;
//cout << maxvalue << " ... " << maxindex << endl; //For debugging purposes prior reward structure
}
else{
cout << "For some reason the placeholder did not fall within the epsilon, decide func" << endl;
}
cout << "The current action is: " << action << endl;
return action;
}
//// React() Function
void Agent::react(double r){ //Buddy coded with Chris Jackson.
//filling the Qtable per timestep using the stateful, action-value learner
reward = r;
Q = Qtable.at(prevstate).at(action); //Each element of a Qrow vectors
//For equation purposes: Q = whatever is in the placement
for(int d=0;d<4;d++){
if(Qtable.at(state).at(d) == maxvalue){
maxindex = d;
}
}
Qmax = *max_element(Qtable.at(state).begin(), Qtable.at(state).end());
Q = Q + alpha * (reward + gamma * Qmax - Q);
//cout << "Qmax = " << Qmax << endl;
//cout << "Reward = " << reward << endl;
Qtable.at(prevstate).at(action) = Q; //Updating from values of the function
//For Placement purposes: The placement of the table is the updated Q value
}
//// TestD() Function
void Agent::TestD(vector<vector<double>> Qtable, vector<double> Qrow){
//int numStates = Qrow.size();
for(int u=0; u< Qrow.size(); u++){
assert(Q < reward);
//comparing each Qvalue to the reward. Seeing if the reward is bigger than the Qvalue at every iteration.
}
}
//// TestF() Function
void Agent::TestF(){
int optimalsteps = 7; //Least number of moves to get to the goal (0,0) -> (2,3)
assert(Qtable.size() <= optimalsteps); //NOTE~~~What is a better way to implement this?
//THE ASSERT IS GONNA FAIL: That is why it is commented out; but this assert logic for TestF() seems sound.
}
/////------------ Gridworld functions -----------------------
//// Calc_agentstate() function
void GridWorld::calc_agentstate(){ //Did this back in the day.
p1->prevstate = p1->state;
p1->state = body_x + body_y * x_dim; //Calculates each cell, which is indexed numerically
p1->set_state(p1->state);
}
//// TestE() Function
void GridWorld::TestE(){
//Checking to see if it reinitializes
assert(body_x == 0); //NOTE~~~What is a better way to implement this?
assert(body_y == 0);
//Checking to see if the Qvalue = the original placeholder when initializing the Qtable
assert(p1->Q != 0); //The Qtable doesnt reset: Qvalue != initializer (zero or close to zero)
}
//// TestG() function
void GridWorld::TestG(){
p1->prevstate_alt = p1->state_alt;
p1->state_alt = body_y + body_x * y_dim; //Calc each cell based on y-dim. Find alt way to calculate?
p1->set_state(p1->state_alt);
}
//// Start() Function
void GridWorld::start(){
x_dim = 4;
y_dim = 4;
body_x = 0;
body_y = 0;
target_x = 2;
target_y = 3;
}
//// Run() Function
int GridWorld::run(){
ofstream fout("/Users/Jan/Desktop/ProjectBetaResults1.txt", fstream::trunc);
start();
p1->Qtableinit();
calc_agentstate();
TestG(); //Calculate alternate state
for(int w=0; w<100; w++){ //100 episodes per statistical run
int moves = 0;
while(body_x != target_x || body_y != target_y){
cout << "============================================================" << endl;
cout << endl << "Q-Learner: New Iteration" << endl;
cout << "-------------------------------------------------" << endl;
cout << "For debug sake: the Goal is at (x,y)= (" << target_x << "," << target_y << ")" << endl;
cout << " Before Choice: X-Location: ((" << body_x << ")) " << "Y_Location: ((" << body_y << "))" << endl << endl;
p1->decide(); //dereference the pointer to do the decide function in the agent
choice = p1->action; //choice = dereferenced action from the agent
/// Actual Movement
if (choice == 0 ){
body_x--;
}
if (choice == 1){
body_y--;
}
if (choice == 2){
body_y++;
}
if (choice == 3){
body_x++;
}
if (choice != 0 && choice != 1 && choice != 2 && choice != 3){
cout << "That is not a valid choice. Please enter 0, 1, 2, or 3" << endl;
}
cout << "The choice made was: " << choice << endl << endl;
/// Boundary Teleportation
while(body_x<0){
body_x++;
cout << "Agent Bounced Back into the GridWorld" << endl;
}
while(body_y<0){
body_y++;
cout << "Agent Bounced Back into the GridWorld" << endl;
}
while(body_x > x_dim){
body_x--;
cout << "Agent Bounced Back into the GridWorld" << endl;
}
while(body_y>y_dim){
body_y--;
cout << "Agent Bounced Back into the GridWorld" << endl;
}
/// Reward Structure
double r;
if(body_x == target_x && body_y == target_y){
r = supergoodreward;
}
else {
r = -1;
}
/// Finish off the Run()
calc_agentstate();
TestG(); //Calcluate alternate state
moves++;
p1->react(r); //dereference the pointer to the react function of the agent
cout << " After Choice: X-Location: ((" << body_x << ")) " << "Y_Location: ((" << body_y << "))" << endl << endl;
cout << "The Agent/Human has not yet met the Goal..." << endl << endl;
}
cout << "...THE AGENT/HUMAN HAS MET THE GOAL" << endl << endl;
cout << "============================================================" << endl;
cout << "The moves taken are: " << moves << endl << endl;
fout << moves << endl;
cout << "============================================================" << endl;
cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "GAME/EPISODE " << w+1 << " ENDED." << endl;
cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
start();
TestE();
}
fout.close();
p1->TestD(Qtable, Qrow);
p1->TestF();
//Qtable.clear();
return 1;
}
////==================== MAIN =============================================
int main(){
srand( static_cast<unsigned int>(time(NULL))); //debugging purposes
GridWorld grid;
Agent agent;
cout << "Welcome to GridWorld, Human/Agent!" << endl;
Agent* p1;
p1 = &agent; //pointer references to the agent's address
grid.p1 = p1;
// Grid pointer a = agent pointer a. Inputting the agent to the grid
grid.run();
//If assert fails the program will stop here
cout << "GAME/STATISTICAL RUN ENTIRELY TERMINATED." << endl << endl << endl;
return 0;
}