class Tank(object): def __init__(self, position): self.position = position self.rotation = random.random() * 2 * math.pi self.bearing = Vector(math.cos(self.rotation), math.sin(self.rotation)) self.neural_net = NeuralNet(4, 1, 10, 3) self.fitness = 0 def update(self, mines): mines = sorted(mines, key=lambda m: m.position.distance(self.position)) # closest mine closest_mine = mines[0] # look_at vector look_at = Vector(self.position.x - closest_mine.position.x, self.position.y - closest_mine.position.y) look_at.normalize() outputs = self.neural_net.update( [look_at.x, look_at.y, self.bearing.x, self.bearing.y]) # rotation self.rotation += (outputs[0] - outputs[1]) * 0.01 # speed self.speed = outputs[2] # calcuate new bearing degrees = self.rotation * 180 / math.pi self.bearing.x = -math.sin(degrees) self.bearing.y = math.cos(degrees) # calculate new position self.position.x += self.bearing.x * self.speed self.position.y += self.bearing.y * self.speed if self.position.x > WIDTH: self.position.x = 0 if self.position.x < 0: self.position.x = WIDTH if self.position.y > HEIGHT: self.position.y = 0 if self.position.y < 0: self.position.y = HEIGHT return closest_mine def __repr__(self): return 'Tank(position=[%s], bearing=[%s], fitness=%s)'\ % (self.position, self.bearing, self.fitness)
class Tank(object): def __init__(self, position): self.position = position self.rotation = random.random() * 2 * math.pi self.bearing = Vector(math.cos(self.rotation), math.sin(self.rotation)) self.neural_net = NeuralNet(4,1,10,3) self.fitness = 0 def update(self, mines): mines = sorted(mines, key = lambda m: m.position.distance(self.position)) # closest mine closest_mine = mines[0] # look_at vector look_at = Vector(self.position.x - closest_mine.position.x, self.position.y - closest_mine.position.y) look_at.normalize() outputs = self.neural_net.update([look_at.x, look_at.y, self.bearing.x, self.bearing.y]) # rotation self.rotation += (outputs[0] - outputs[1]) * 0.01 # speed self.speed = outputs[2] # calcuate new bearing degrees = self.rotation * 180 / math.pi self.bearing.x = -math.sin(degrees) self.bearing.y = math.cos(degrees) # calculate new position self.position.x += self.bearing.x * self.speed self.position.y += self.bearing.y * self.speed if self.position.x > WIDTH: self.position.x = 0 if self.position.x < 0: self.position.x = WIDTH if self.position.y > HEIGHT: self.position.y = 0 if self.position.y < 0: self.position.y = HEIGHT return closest_mine def __repr__(self): return 'Tank(position=[%s], bearing=[%s], fitness=%s)'\ % (self.position, self.bearing, self.fitness)
class Plane(object): def __init__(self, position, usage, speed, angle): self.position = position self.rotation = angle self.bearing = Vector(math.cos(self.rotation), math.sin(self.rotation)) self.neural_net = NeuralNet(5, 1, 10, 1) self.usage = usage self.speed = speed self.reset() def reset(self): self.fitness = 0 self.beam = None self.th = 0 self.action = 0 def update(self, beams): beams = sorted([ b for b in beams if ((self.beam and b.load < self.beam.load) or self.beam == None) and b != self.beam and b.position.distance(self.position) <= b.radius ], key=lambda b: b.load) # other beam next_beam = beams[0] if beams else None if self.beam and abs(self.beam.position.distance( self.position)) >= self.beam.radius: self.beam.load -= self.usage * 1.0 / self.beam.capacity self.beam = None if next_beam: self.th = 0 sigmoid = lambda x, x0, a, b: a - a / (1 + np.exp(-b * (x - x0))) perf = lambda x: np.round(sigmoid(x, 0.9, 1.0, 3.0), 2) self.lc = self.beam.load if self.beam else 1 self.ln = next_beam.load if next_beam else 1 self.ld = perf(self.ln) - perf(self.lc) # current beam self.fc = 1 if self.beam else -1 # next beam self.fn = 1 if next_beam else -1 # time since handover if self.beam: self.th += 1 max_th = 10 self.th = min([self.th, max_th]) state = [self.ld, self.fc, self.fn, self.th, self.speed] outputs = self.neural_net.update(state) self.action = outputs[0] if self.action < 0.5: # handover if self.beam: self.beam.load -= self.usage * 1.0 / self.beam.capacity if next_beam: # minimize handovers penalty = 2 * max([0, (max_th - self.th + 1)]) if next_beam.load < self.beam.load: penalty *= 0.1 self.fitness -= penalty self.th = 0 if next_beam: self.beam = next_beam self.beam.load += self.usage * 1.0 / self.beam.capacity else: if self.beam: self.beam = None self.fitness -= 50 else: # no current beam pass else: if self.beam and next_beam: if self.beam.load > next_beam: self.fitness -= 0.5 * self.th if self.beam: fitness = 100 * np.power(perf(self.beam.load), 1) self.fitness += fitness # calculate new position self.position.x += self.bearing.x * self.speed self.position.y += self.bearing.y * self.speed if self.position.x > WIDTH: self.position.x = 0 if self.position.x < 0: self.position.x = WIDTH if self.position.y > HEIGHT: self.position.y = 0 if self.position.y < 0: self.position.y = HEIGHT return self.beam def __repr__(self): return 'Beam(position=[%s], bearing=[%s], fitness=%s)'\ % (self.position, self.bearing, self.fitness)