diff --git a/2023/during-the-day/tank-wars-tanks/coffinmaker_agent.py b/2023/during-the-day/tank-wars-tanks/coffinmaker_agent.py new file mode 100644 index 0000000000000000000000000000000000000000..1e2ead034ec2fbdb45eed6f072fe23855b9521ab --- /dev/null +++ b/2023/during-the-day/tank-wars-tanks/coffinmaker_agent.py @@ -0,0 +1,229 @@ +from agents.agent import Agent +from game.rendering import Renderer +from game.environment import Environment +import math +from game.config import ARENA_CENTER, ARENA_RADIUS +import numpy as np + +class PexAgent(Agent): + def __init__(self): + self.name = "Coffin Maker" + self.color = (0,0,0) + self.nof_opponents = -1 + + # create a list to store old locations + self.memory = [] + + # create two simple p-controller gains + self.kp_dist = 0.5 + self.kp_theta = 0.5 + + + def action(self, observation): + """Log the location of the first opponent, and try to track it""" + # unpack the observation + my_state, other_tanks, projectiles, time = observation + +# if self.nof_opponents == -1: +# self.nof_opponents = len(other_tanks) +# print("### nof_opponents=%d" % self.nof_opponents) +# colors = [] +# names = [] +# for player_no in range(self.nof_opponents): +# colors.append([128,128,128]) +# names.append("%d" % player_no) +# self.env = Environment(colors, names) +# self.env.reset(seed = 1337) + + + # Sort the projectiles according to distance: + + + + nof_opponents = len(other_tanks) +# print("### t=%0.2f") +# print(other_tanks) + #Propagate the opponents 1 second ahead: + dt = 1.0 + propagated_tanks = other_tanks.copy() + for opponent_no in range(nof_opponents): + this_tank = other_tanks[opponent_no] + """Move the tank forward by a specified distance based on its current angle.""" + # Using basic trigonometry to calculate the new x and y coordinates + this_tank["x"] += this_tank["v"] * math.cos(math.radians(this_tank["theta"])) * dt + this_tank["y"] += this_tank["v"] * math.sin(math.radians(this_tank["theta"])) * dt + propagated_tanks[opponent_no] = this_tank + + + propagated_my = my_state.copy() + propagated_my_left = my_state.copy() + propagated_my_right = my_state.copy() + + propagated_my["x"] += my_state["v"] * math.cos(math.radians(my_state["theta"])) * dt + propagated_my["y"] += my_state["v"] * math.sin(math.radians(my_state["theta"])) * dt + propagated_my_left["x"] += my_state["v"] * math.cos(math.radians(my_state["theta"] + 15)) * dt + propagated_my_left["y"] += my_state["v"] * math.sin(math.radians(my_state["theta"] + 15)) * dt + propagated_my_right["x"] += my_state["v"] * math.cos(math.radians(my_state["theta"] - 15)) * dt + propagated_my_right["y"] += my_state["v"] * math.sin(math.radians(my_state["theta"] - 15)) * dt + + + # Sort the tanks according to distance: + dists = [] + dists_left = [] + dists_right = [] + for opponent_no in range(nof_opponents): + dist_x = abs(propagated_my["x"] - propagated_tanks[opponent_no]["x"]); + dist_y = abs(propagated_my["y"] - propagated_tanks[opponent_no]["y"]); + dists.append(math.sqrt(dist_x*dist_x + dist_y*dist_y)); + + for opponent_no in range(nof_opponents): + dist_x = abs(propagated_my_left["x"] - propagated_tanks[opponent_no]["x"]); + dist_y = abs(propagated_my_left["y"] - propagated_tanks[opponent_no]["y"]); + dists_left.append(math.sqrt(dist_x*dist_x + dist_y*dist_y)); + + for opponent_no in range(nof_opponents): + dist_x = abs(propagated_my_right["x"] - propagated_tanks[opponent_no]["x"]); + dist_y = abs(propagated_my_right["y"] - propagated_tanks[opponent_no]["y"]); + dists_right.append(math.sqrt(dist_x*dist_x + dist_y*dist_y)); +# print("### dists:") +# print(dists); +# print("### dists_left:") +# print(dists_left); +# print("### dists_right:") +# print(dists_right); + straight = min(dists) + left = min(dists_left) + right = min(dists_right) + + # Add the distance to the edge: + dist_x = abs(propagated_my["x"]); + dist_y = abs(propagated_my["y"]); + my_radius=math.sqrt(dist_x*dist_x + dist_y*dist_y); + dist_to_edge = ARENA_RADIUS - my_radius + + + # Add the distance to the edge: + dist_x = abs(propagated_my_left["x"]); + dist_y = abs(propagated_my_left["y"]); + my_radius=math.sqrt(dist_x*dist_x + dist_y*dist_y); + dist_to_edge_left = ARENA_RADIUS - my_radius + + + # Add the distance to the edge: + dist_x = abs(propagated_my_right["x"]); + dist_y = abs(propagated_my_right["y"]); + my_radius=math.sqrt(dist_x*dist_x + dist_y*dist_y); + dist_to_edge_right = ARENA_RADIUS - my_radius + + + + straight = min(straight,dist_to_edge) + left = min(left,dist_to_edge_left) + right = min(right,dist_to_edge_right) + +# print("### my rad=") +# print(my_radius) +# print("### dist_to_edge=") +# print(dist_to_edge) + + + + + go_straight = False + go_right = False + go_left = False + if (right > left): + go_right = True + else: + go_left = True + go_straight = False + + + + def should_we_shoot(self, observation): + my_state, other_tanks, projectiles, time = observation + x, y, theta = my_state["x"], my_state["y"], my_state["theta"] + for opponent in other_tanks: + if opponent["lives"]>0: + x_opp, y_opp = opponent["x"], opponent["y"] + dx = x_opp - x + dy = y_opp - y + angle = np.arctan2(dy,dx)*180/math.pi + + if np.mod(abs(angle-theta),360) < 10 or np.mod(abs(angle-theta),360) > 350: + return True + return False + + shall_we_shoot = should_we_shoot(self,observation) + + + + def someone_looking_at_us(self, observation): + # unpack the observation + my_state, other_tanks, projectiles, time = observation + # get my current state and calculate the error + x, y, theta = my_state["x"], my_state["y"], my_state["theta"] + for opponent in other_tanks: + # get the opponent's location + x_opp, y_opp, theta_opp = opponent["x"], opponent["y"], opponent["theta"] + dx = x - x_opp + dy = y - y_opp + dtheta = (math.atan2(dy,dx))*180/math.pi + turn = False + if abs(dtheta-theta_opp)%360 < 25: + turn = True + return turn + + someone_looking = someone_looking_at_us(self,observation) + + acceleration = -1 + if someone_looking==True: + if (time%5 < 2): + go_right=True + else: + go_left=True + + if go_right == True: + turn_rate = -1 + elif go_left == True: + turn_rate = 1 + + + return (acceleration, turn_rate, shall_we_shoot) + + +## print(projectiles) +##[{'x': -103.492851909847, 'y': -11.236957838912705, 'theta': 157.23121240722895, 'v': 200}] +# +## print(other_tanks) +## print(my_state) +# +# # get the first opponent +# opponent = other_tanks[0] +# +# # get the opponent's location +# x_opp, y_opp = opponent["x"], opponent["y"] +# +# # log the location +# self.memory.append((x_opp,y_opp)) +# +# # in the first 1 seconds, go to the initial position of the target +# if time <= 1: +# xr, yr = self.memory[0] +# # after 1 seconds, start following the trajectory of target +# else: +# xr, yr = self.memory.pop(0) +# +# # get my current state and calculate the error +# x, y, theta = my_state["x"], my_state["y"], my_state["theta"] +# dx, dy = xr - x, yr - y +# +# # calculate the acceleration and turn rate +# acceleration = self.kp_dist * (dx**2 + dy**2)**0.5 +# theta_error = math.atan2(dy, dx)% (2*math.pi) - math.radians(theta) +# theta_error = theta_error +# theta_error = math.sin(theta_error) +# +# turn_rate = self.kp_theta * theta_error +# +# return (acceleration, turn_rate, False) \ No newline at end of file diff --git a/2023/during-the-day/tank-wars-tanks/emmy_agent.py b/2023/during-the-day/tank-wars-tanks/emmy_agent.py new file mode 100644 index 0000000000000000000000000000000000000000..719748797f29720550c8c98331c0d34ddb9fca08 --- /dev/null +++ b/2023/during-the-day/tank-wars-tanks/emmy_agent.py @@ -0,0 +1,113 @@ +from agents.agent import Agent + +from game.config import ARENA_RADIUS as r +from game.config import DRAG as d +from game.config import ACCELERATION as a0 +from game.config import TURN_SPEED as w0 +from game.config import PROJECTILE_SPEED as vp +from game.config import DT as dt + +from math import * + +# TODO :: change parameters in environment +# from game.environment import Environment + + +class EmmyAgent(Agent): + def __init__(self): + self.name = "EMMY" + self.color = (100,100,0) + self.debug = False + + self.position_log = [] + self.integral_gain = 1337 + + self.prev_x = 0 + self.prev_y = 0 + self.still = 0 + self.turn = 0 + self.left = True + self.which_to_kill = 0 + + def fixTheta(self, theta): + if (self.debug): + print(f"from theta = {theta}") + while(theta > pi): + theta = theta - 2*pi + while(theta < -pi): + theta = theta + 2*pi + if (self.debug): + print(f"to theta = {theta}") + return theta + + def action(self, observation): + my_state, other_tanks, projectiles, time = observation + + if (self.turn > 0): + self.turn = self.turn - 1 + if (self.left): + return (1, 1, True) + else: + return (1, -1, True) + if (self.turn == 0): + self.left = not self.left + + + tank_to_kill = other_tanks[self.which_to_kill] + + if (tank_to_kill["lives"] == 0): + for i in range(len(other_tanks)): + tank_to_kill = other_tanks[i] + if (tank_to_kill["lives"] > 0): + self.which_to_kill = i + break + if (tank_to_kill["lives"] == 0): + return (0, 0, False) + # print(self.which_to_kill) + + + my_x = my_state['x'] + my_y = my_state['y'] + my_theta = self.fixTheta(radians(my_state['theta'])) + my_v = my_state['v'] + + kill_x = tank_to_kill['x'] + kill_y = tank_to_kill['y'] + kill_theta = radians(tank_to_kill['theta']) + kill_v = tank_to_kill['v'] + + # print(f"distance = {sqrt((my_x - kill_x)**2 + (my_y - kill_y)**2)}") + + if (sqrt((my_x - kill_x)**2 + (my_y - kill_y)**2) < 50): + return (0, 0, True) + + if (sqrt((my_x - self.prev_x)**2 + (my_y - self.prev_y)**2) < 1e-13): + # print("turn!") + self.still = self.still + 1 + self.turn = 50 + return (1, 1, False) + self.prev_x = my_x + self.prev_y = my_y + self.still = 0 + + dx = kill_x - my_x + dy = kill_y - my_y + + angle = atan2(dy, dx) + + angle_diff = angle - my_theta + + if (self.debug): + print(f"my_theta = {my_theta} kill_theta = {kill_theta} angle = {angle} angle_diff = {angle_diff}") + + to_shoot = False + if (abs(angle_diff) < 0.1): + to_shoot = True + + if (angle_diff >= 0): + return (1, 1, to_shoot) + else: + return (1, -1, to_shoot) + + + return (1, 1, True) \ No newline at end of file diff --git a/2023/during-the-day/tank-wars-tanks/right_agent.py b/2023/during-the-day/tank-wars-tanks/right_agent.py new file mode 100644 index 0000000000000000000000000000000000000000..221454118654d1321d6ce208543d05678b1e1d7c --- /dev/null +++ b/2023/during-the-day/tank-wars-tanks/right_agent.py @@ -0,0 +1,11 @@ +from agents.agent import Agent + +class RightAgent(Agent): + def __init__(self): + self.name = "RIGHT, BABY!" + self.color = (0,0,250) + + def action(self, observation): + """Drive right and shoot""" + + return (1, -1, True) \ No newline at end of file diff --git a/2023/during-the-day/tank-wars-tanks/tank_you.py b/2023/during-the-day/tank-wars-tanks/tank_you.py new file mode 100644 index 0000000000000000000000000000000000000000..b715e7bb26b371be4e47e641cbbc5175af26d42b --- /dev/null +++ b/2023/during-the-day/tank-wars-tanks/tank_you.py @@ -0,0 +1,96 @@ +from agents.agent import Agent +from game.config import TANK_SIZE, PROJECTILE_SIZE, PROJECTILE_SPEED, OVERLAP_PADDING_HITS, DT, ARENA_RADIUS, OVERLAP_PADDING_WALLS, ACCELERATION, DRAG, TURN_SPEED +from math import cos, sin, radians +import random + +class DoubleTankAgent(Agent): + def __init__(self): + self.name = "Tank You" + #self.color = (240, 204, 174) + self.color = (255,0,127) + self.N = 40 + + + def is_colliding_tank_bullet(self, tank, bullet): + return (tank["x"] - bullet["x"])**2 + (tank["y"] - bullet["y"])**2 <= (TANK_SIZE + PROJECTILE_SIZE)**2 * OVERLAP_PADDING_HITS + + def is_colliding_tank_tank(self, tank, other): + return (tank["x"] - other["x"])**2 + (tank["y"] - other["y"])**2 <= (2 * TANK_SIZE)**2 + + def cost(self, projectiles, tank, tanks): + tot = 0 + for proj in projectiles: + if self.is_colliding_tank_bullet(tank, proj): + print("Found collision") + tot += 1000 + for other_tank in tanks: + if self.is_colliding_tank_tank(tank, other_tank): + tot += 10 + if tank["x"]**2 + tank["y"]**2 + 20 > (ARENA_RADIUS - TANK_SIZE)**2: + tot += 10 + return tot + + def action(self, observation): + """Log the location of the first opponent, and try to track it""" + # unpack the observation + my_state, other_tanks, projectiles, time = observation + + tot = 500 + acc = 0 + first_turn = 0 + + N_POL = 25 + acc = -1 + for i in range(N_POL): + projectiles = [proj.copy() for proj in projectiles] + tank = my_state.copy() + tot = 0 + turn = random.choice([-1, 0, 1]) + for j in range(10): + first_turn = turn + for i in range(self.N // 10): + # Update tank with random action, and remember first in sequence + tank["a"] = ACCELERATION * max(-1, min(acc, 1)) + tank["v"] = tank["v"] - tank["v"] * DT * DRAG + tank["a"] * DT + tank["angle_change"] = TURN_SPEED * max(-1, min(turn, 1)) * DT + tank["theta"] += tank["angle_change"] + tank["theta"] %= 360 + tank["x"] += tank["v"] * cos(radians(tank["theta"])) * DT + tank["y"] += tank["v"] * sin(radians(tank["theta"])) * DT + + for proj in projectiles: + proj["x"]+= PROJECTILE_SPEED * cos(radians(proj["theta"])) * DT + proj["y"] += PROJECTILE_SPEED * sin(radians(proj["theta"])) * DT + tot += self.cost(projectiles, tank, other_tanks) + turn = random.choice([-1, 0, 1]) + if tot < 100: + return (acc, first_turn, True) + + acc = 1 + for i in range(N_POL): + projectiles = [proj.copy() for proj in projectiles] + tank = my_state.copy() + tot = 0 + turn = random.choice([-1, 0, 1]) + for j in range(10): + first_turn = turn + for i in range(self.N // 10): + # Update tank with random action, and remember first in sequence + tank["a"] = ACCELERATION * max(-1, min(acc, 1)) + tank["v"] = tank["v"] - tank["v"] * DT * DRAG + tank["a"] * DT + tank["angle_change"] = TURN_SPEED * max(-1, min(turn, 1)) * DT + tank["theta"] += tank["angle_change"] + tank["theta"] %= 360 + tank["x"] += tank["v"] * cos(radians(tank["theta"])) * DT + tank["y"] += tank["v"] * sin(radians(tank["theta"])) * DT + + for proj in projectiles: + proj["x"]+= PROJECTILE_SPEED * cos(radians(proj["theta"])) * DT + proj["y"] += PROJECTILE_SPEED * sin(radians(proj["theta"])) * DT + tot += self.cost(projectiles, tank, other_tanks) + turn = random.choice([-1, 0, 1]) + if tot < 100: + return (acc, first_turn, True) + + return (acc, first_turn, True) + \ No newline at end of file diff --git a/2023/during-the-day/tank-wars-tanks/team6_agent.py b/2023/during-the-day/tank-wars-tanks/team6_agent.py new file mode 100644 index 0000000000000000000000000000000000000000..d6e4327ce160b2006426b88d3f4e28f338ed2987 --- /dev/null +++ b/2023/during-the-day/tank-wars-tanks/team6_agent.py @@ -0,0 +1,57 @@ +from agents.agent import Agent +import math +import numpy as np + +class Team6Agent(Agent): + def __init__(self): + self.name = "Totally not military grade" + self.color = (0,100,0) + + # create a list to store old locations + self.memory = [] + + # create two simple p-controller gains + self.kp_dist = 0.5 + self.kp_theta = 0.5 + self.hproj = [] + self.opp = [] + self.opp_omega = [] + self.w = 0 + self.aggro = True + self.a = 0 + self.di = 1.5 + self.T = 0 + + + def action(self, observation): + """Log the location of the first opponent, and try to track it""" + # unpack the observation + my_state, other_tanks, projectiles, time = observation + + # get the first opponent + opponent = other_tanks[0] + + # get the opponent's location + my_theta = my_state["theta"] +# x_opp, y_opp, theta_opp, v_opp = opponent["x"], opponent["y"], opponent["theta"], opponent["v"] + projspeed = 200 + DT = 1/60 + self.fire = True + self.T += DT + if self.T>1: + self.di = self.di*-1 + self.T = 0 + if my_state["cooldown"] > 0.0: + self.a = np.random.uniform(self.di-1,self.di+1) + self.w = np.random.uniform(-1,1) + mx, my = (np.mean([o["x"] for o in other_tanks if o["lives"]>0]), np.mean([o["y"] for o in other_tanks if o["lives"]>0])) + x, y, theta = my_state["x"], my_state["y"], my_state["theta"] + theta = theta%360 + dx = mx-x + dy = my-y + rtheta = (math.degrees(math.atan2(dy,dx)))%360 + self.w = rtheta-theta + + + + return (self.a, self.w, self.aggro) diff --git a/2023/during-the-day/tank-wars-tournament.md b/2023/during-the-day/tank-wars-tournament.md new file mode 100644 index 0000000000000000000000000000000000000000..ea17eb2424352813b32c3f6cd2c03ac265fbdcac --- /dev/null +++ b/2023/during-the-day/tank-wars-tournament.md @@ -0,0 +1,11 @@ +# Tournament Schedule +Here is the schedule for the [tank wars](https://gitlab.control.lth.se/felix/tank-wars) tournament. + +## Semifinals 1 +| RIGHT | Emmy | **Team6** | + +## Semifinals 2 +| **CoffinMaker** | TankYou | WinningTank | + +## Finals +| **Team6** | CoffinMaker | \ No newline at end of file