-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphysical_agent.py
More file actions
212 lines (166 loc) · 7.58 KB
/
Copy pathphysical_agent.py
File metadata and controls
212 lines (166 loc) · 7.58 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
import sys
import os
import pygame
import random
import csv
import time
from math import sqrt
## Class PhysAgent
""" It is the representation of an agent in the environment
It MUST NOT be used by the rescuer or explorer """
class PhysAgent:
# States of the body of the agent
ENDED = 2 # Successfully ended
ACTIVE = 1 # still running
IDLE = 0 # not active, but alive
DEAD = -1 # fatal error
# Possible results for the walk action
BUMPED = -1 # agent bumped into a wall or reached the end of the grid
TIME_EXCEEDED = -2 # agent reached the time limit - no more battery
EXECUTED = 1 # action successfully executed
# Possible results for the check_obstacles method
CLEAR = 0
WALL = 1
END = 2
def __init__(self, mind, env, x_base, y_base, state=ACTIVE):
"""Instatiates a physical agent
@param self: the physical agent
@param mind: the mind of the physical agent
@param env: the environment object
@param x_base: initial value for the coordinate x
@param y_base: initial value for the coordinate y"""
self.mind = mind # it is the agent's mind
self.env = env # it is the environment
self.x_base = x_base # x coordinate of the base
self.y_base = y_base # y coordinate of the base
self.x = x_base # current x coordinate: at Base
self.y = y_base # current y coordinate
self.rtime = mind.TLIM # current remaining time
self.state = state # -1=dead 0=successfully ended 1=alive
def set_state(self, state):
self.state = state
def end_of_time(self):
""" This method test if time limit was reached and if the agent is at the base.
@return: True - time exceeded
False - time not exceeded"""
if self.rtime < 0.0:
return True
return False
def at_base(self):
""" This method test if the agent is at the base.
@return: True - the agent is at the base position
False - the agent is not at the base position"""
if self.x == self.env.dic["BASE"][0] and self.y == self.env.dic["BASE"][1]:
return True
return False
def walk(self, dx, dy):
""" Public method for moving the agent's body one cell to any direction (if possible)
@param dx: an int value corresponding to deplacement in the x axis
@param dy: an int value corresponding to deplacement in the y axis
@returns -1 = the agent bumped into a wall or reached the end of grid
@returns -2 = the agent has no enough time to execute the action
@returns 1 = the action is succesfully executed
In every case, action's executing time is discounted from time limit"""
## consume time
if dx != 0 and dy != 0: # diagonal
self.rtime -= self.mind.COST_DIAG
else:
self.rtime -= self.mind.COST_LINE
## agent is dead
if self.rtime < 0:
return PhysAgent.TIME_EXCEEDED
new_x = self.x + dx
new_y = self.y + dy
if new_x >= 0 and new_x < self.env.dic["GRID_WIDTH"]and new_y >= 0 and new_y < self.env.dic["GRID_HEIGHT"] and self.env.walls[new_x][new_y] == 0:
self.x = new_x
self.y = new_y
self.env.visited[new_x][new_y] = self.mind.TRACE_COLOR
return PhysAgent.EXECUTED
else:
return PhysAgent.BUMPED
def check_obstacles(self):
""" Public method for checking obstacles in the neighborhood of the current position of the agent.
@returns a vector of eight integers indexed in a clockwise manner. The first position in the vector is
above the current position of the agent, the second is in the upper right diagonal direction, the third is to the right, and so on."
Each vector position containg one of the following values: {CLEAR, WALL, END}
CLEAR means that there is no obstacle (value = 0)
WALL means that there is a wall (value = 1)
END means the end of the grid (value = 2)
"""
delta = [(0,-1),(1,-1),(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1)]
obstacles = [PhysAgent.CLEAR] * 8
i = 0
for d in delta:
new_x = self.x + d[0]
new_y = self.y + d[1]
if new_x < 0 or new_x >= self.env.dic["GRID_WIDTH"] or new_y < 0 or new_y >= self.env.dic["GRID_HEIGHT"]:
obstacles[i] = PhysAgent.END
elif self.env.walls[new_x][new_y] == 1:
obstacles[i] = PhysAgent.WALL
i += 1
#print(f"({self.x},{self.y}): obstacles={obstacles}")
return obstacles
def check_for_victim(self):
""" Public method for testing if there is a victim in the current position of the agent
@returns int: the sequential number of the victim starting from zero (in the list that corresponds to the
victims.txt and sinais_vitais.txt)
@returns -1: if there is no victim at the current position of the agent"""
seq = -1
if (self.x, self.y) in self.env.victims:
seq = self.env.victims.index((self.x, self.y))
return seq
def read_vital_signals(self, seq):
""" Public method for reading the vital signals and marking a victim as found.
@param seq: identifies the victim starting from zero
@returns list of vital signals if seq corresponds to a victim or an empty
list if the seq is not found."""
## Consume time
self.rtime -= self.mind.COST_READ
## Agent is dead
if self.rtime < 0:
return PhysAgent.TIME_EXCEEDED
## Null victim
if seq >= self.env.nb_of_victims:
return []
# Mark the victim as found by this agent.
# More than one agent can found the same victim, so it's a list
self.env.found[seq].append(self)
return self.env.signals[seq]
def first_aid(self, seq):
""" Public method for dropping the first aid package to the victim identified
by the seq number. This method marks the victim as saved.
@param seq: identifies the victim starting from zero
@returns list of vital signals if seq corresponds to a victim or an empty
list if the seq is not found."""
## Consume time
self.rtime -= self.mind.COST_FIRST_AID
## Agent is dead
if self.rtime < 0:
return PhysAgent.TIME_EXCEEDED
## Null victim
if seq >= self.env.nb_of_victims:
return False
# Mark the victim as found by this agent.
# More than one agent can drop a first-aid package to the same victim, so it's a list
self.env.saved[seq].append(self)
return True
def get_found_victims(self):
""" Public method for returning the number of found victims by the agent
@returns a list with the sequential number of found victims """
victims = []
v = 0
for finders in self.env.found:
if self in finders:
victims.append(v)
v = v + 1
return victims
def get_saved_victims(self):
""" Public method for returning the number of saved victims by the agent
@returns a list with the sequential number of saved victims """
victims = []
v = 0
for rescuers in self.env.saved:
if self in rescuers:
victims.append(v)
v = v + 1
return victims