Пример #1
0
    def shell_will_hit(self, shell, target, factor=1):
        """
        Returns True if shell will hit rectangular object
        """
        b = shell.angle
        e = Vector(1, 0)
        q = e.rotate(b)

        center = Vector(target.x - shell.x, target.y - shell.y)
        if center.scalar_product(q) < 0:
            return False

        a = target.angle

        c1 = center + Vector(target.width/2 * factor, target.height/2 * factor).rotate(a)
        c2 = center + Vector(- target.width/2 * factor, target.height/2 * factor).rotate(a)
        c3 = center + Vector(- target.width/2 * factor, - target.height/2 * factor).rotate(a)
        c4 = center + Vector(target.width/2 * factor, - target.height/2 * factor).rotate(a)
        if sign(c1.cross_product(q)) == sign(q.cross_product(c3)):
            #print("TEST", c1, c2, c3, c4, q)
            return True
        if sign(c2.cross_product(q)) == sign(q.cross_product(c4)):
            #print("TEST", c1, c2, c3, c4, q)
            return True
        return False
Пример #2
0
    def positions(self, tank, world):
        positions = []

        # Current position
        positions.append(Position(tank.x, tank.y, "CURRENT"))

        # Forward and back direction
        tank_v = Vector(tank.x, tank.y)
        tank_d_v = Vector(1, 0).rotate(tank.angle)
        forw = tank_v + tank_d_v * self.short_direction
        back = tank_v - tank_d_v * self.short_direction
        positions.append(Position(forw.x, forw.y, "FORWARD"))
        positions.append(Position(back.x, back.y, "BACKWARD"))

        fforw = tank_v + tank_d_v * self.long_direction
        fback = tank_v - tank_d_v * self.long_direction
        positions.append(Position(fforw.x, fforw.y, "FAR FORWARD"))
        positions.append(Position(fback.x, fback.y, "FAR BACKWARD"))

        # Low diagonal move
        DIAGONAL_ANGLE = PI/6
        for a in [DIAGONAL_ANGLE, - DIAGONAL_ANGLE, PI - DIAGONAL_ANGLE, DIAGONAL_ANGLE - PI]:
            pt = tank_v + tank_d_v.rotate(a) * 100
            positions.append(Position(pt.x, pt.y, "TURN %.0f" % degrees(a)))

        # Bonuses positions
        positions += [Position(b.x, b.y, "BONUS %s" % bonus_name_by_type(b.type)) for b in world.bonuses]

        return positions
Пример #3
0
    def shell_will_hit(self, shell, target, factor=1):
        """
        Returns True if shell will hit rectangular object
        """
        b = shell.angle
        e = Vector(1, 0)
        q = e.rotate(b)

        center = Vector(target.x - shell.x, target.y - shell.y)
        if center.scalar_product(q) < 0:
            return False

        a = target.angle

        c1 = center + Vector(target.width / 2 * factor,
                             target.height / 2 * factor).rotate(a)
        c2 = center + Vector(-target.width / 2 * factor,
                             target.height / 2 * factor).rotate(a)
        c3 = center + Vector(-target.width / 2 * factor,
                             -target.height / 2 * factor).rotate(a)
        c4 = center + Vector(target.width / 2 * factor,
                             -target.height / 2 * factor).rotate(a)
        if sign(c1.cross_product(q)) == sign(q.cross_product(c3)):
            #print("TEST", c1, c2, c3, c4, q)
            return True
        if sign(c2.cross_product(q)) == sign(q.cross_product(c4)):
            #print("TEST", c1, c2, c3, c4, q)
            return True
        return False
Пример #4
0
    def will_hit_precise(self, tank, target, ricochet_angle=PI/4, factor=1, side_part=1):
        """
        Returns True if tank will hit rectangular object
        """
        b = tank.angle + tank.turret_relative_angle
        e = Vector(1, 0)
        q = e.rotate(b)

        tank_v = Vector(tank.x, tank.y)

        c = get_unit_corners(target, factor)

        hit_v = tank_v + MAX_DISTANCE * q

        def will_hit_side(p1, p2):
            p_mid = (p1 + p2)/2
            p1_new = p_mid + (p1 - p_mid) * side_part
            p2_new = p_mid + (p2 - p_mid) * side_part
            intersecting = segments_are_intersecting(tank_v, hit_v, p1_new, p2_new)
            angle = q.angle(p2 - p1)
            safe = ricochet_angle < angle < PI - ricochet_angle
            return intersecting and safe

        sides = [(c[0], c[1]), (c[1], c[2]), (c[2], c[3]), (c[3], c[0])]
        closest_corner = min(c, key=lambda x: x.distance(tank_v))
        closer_sides = list(filter(lambda s: s[0] == closest_corner or s[1] == closest_corner, sides))


        #result = will_hit_side(c1, c2) or will_hit_side(c2, c3) or will_hit_side(c3, c4) or will_hit_side(c4, c1)
        result = will_hit_side(closer_sides[0][0], closer_sides[0][1]) or will_hit_side(closer_sides[1][0], closer_sides[1][1])
        return result
Пример #5
0
    def positions(self, tank, world):
        positions = []

        # Current position
        positions.append(Position(tank.x, tank.y, "CURRENT"))

        # Forward and back direction
        tank_v = Vector(tank.x, tank.y)
        tank_d_v = Vector(1, 0).rotate(tank.angle)
        forw = tank_v + tank_d_v * self.short_direction
        back = tank_v - tank_d_v * self.short_direction
        positions.append(Position(forw.x, forw.y, "FORWARD"))
        positions.append(Position(back.x, back.y, "BACKWARD"))

        fforw = tank_v + tank_d_v * self.long_direction
        fback = tank_v - tank_d_v * self.long_direction
        positions.append(Position(fforw.x, fforw.y, "FAR FORWARD"))
        positions.append(Position(fback.x, fback.y, "FAR BACKWARD"))

        # Low diagonal move
        DIAGONAL_ANGLE = PI / 6
        for a in [
                DIAGONAL_ANGLE, -DIAGONAL_ANGLE, PI - DIAGONAL_ANGLE,
                DIAGONAL_ANGLE - PI
        ]:
            pt = tank_v + tank_d_v.rotate(a) * 100
            positions.append(Position(pt.x, pt.y, "TURN %.0f" % degrees(a)))

        # Bonuses positions
        positions += [
            Position(b.x, b.y, "BONUS %s" % bonus_name_by_type(b.type))
            for b in world.bonuses
        ]

        return positions
Пример #6
0
    def positions(self, tank, world):
        positions = []

        # Low diagonal move
        tank_v = Vector(tank.x, tank.y)
        tank_d_v = Vector(1, 0).rotate(tank.angle)

        for a in [self.angle, - self.angle, PI - self.angle, self.angle - PI]:
            pt = tank_v + tank_d_v.rotate(a) * 100
            positions.append(Position(pt.x, pt.y, "TURN %.0f" % degrees(a)))
        return positions
Пример #7
0
def draw_tank(tank):
    draw_unit(tank)

    b = tank.angle + tank.turret_relative_angle
    e = Vector(1, 0)
    q = e.rotate(b)

    tank_v = Vector(tank.x, tank.y)
    hit_v = tank_v + MAX_DISTANCE * q

    pygame.draw.line(window, (255, 0, 0), (tank.x, tank.y), (hit_v.x, hit_v.y))
Пример #8
0
def draw_tank(tank):
    draw_unit(tank)

    b = tank.angle + tank.turret_relative_angle
    e = Vector(1, 0)
    q = e.rotate(b)

    tank_v = Vector(tank.x, tank.y)
    hit_v = tank_v + MAX_DISTANCE * q

    pygame.draw.line(window, (255, 0, 0), (tank.x, tank.y), (hit_v.x, hit_v.y))
Пример #9
0
    def positions(self, tank, world):
        positions = []

        # Low diagonal move
        tank_v = Vector(tank.x, tank.y)
        tank_d_v = Vector(1, 0).rotate(tank.angle)

        for a in [self.angle, -self.angle, PI - self.angle, self.angle - PI]:
            pt = tank_v + tank_d_v.rotate(a) * 100
            positions.append(Position(pt.x, pt.y, "TURN %.0f" % degrees(a)))
        return positions
Пример #10
0
    def will_hit_precise(self,
                         tank,
                         target,
                         ricochet_angle=PI / 4,
                         factor=1,
                         side_part=1):
        """
        Returns True if tank will hit rectangular object
        """
        b = tank.angle + tank.turret_relative_angle
        e = Vector(1, 0)
        q = e.rotate(b)

        tank_v = Vector(tank.x, tank.y)

        c = get_unit_corners(target, factor)

        hit_v = tank_v + MAX_DISTANCE * q

        def will_hit_side(p1, p2):
            p_mid = (p1 + p2) / 2
            p1_new = p_mid + (p1 - p_mid) * side_part
            p2_new = p_mid + (p2 - p_mid) * side_part
            intersecting = segments_are_intersecting(tank_v, hit_v, p1_new,
                                                     p2_new)
            angle = q.angle(p2 - p1)
            safe = ricochet_angle < angle < PI - ricochet_angle
            return intersecting and safe

        sides = [(c[0], c[1]), (c[1], c[2]), (c[2], c[3]), (c[3], c[0])]
        closest_corner = min(c, key=lambda x: x.distance(tank_v))
        closer_sides = list(
            filter(lambda s: s[0] == closest_corner or s[1] == closest_corner,
                   sides))

        #result = will_hit_side(c1, c2) or will_hit_side(c2, c3) or will_hit_side(c3, c4) or will_hit_side(c4, c1)
        result = will_hit_side(closer_sides[0][0],
                               closer_sides[0][1]) or will_hit_side(
                                   closer_sides[1][0], closer_sides[1][1])
        return result
Пример #11
0
    def debug_value(self, target):
        tank = self.context.tank
        physics = self.context.physics

        b = tank.angle + tank.turret_relative_angle
        e = Vector(1, 0)
        q = e.rotate(b)

        target_v = Vector(target.x, target.y)
        target_direction = Vector(1, 0).rotate(target.angle)
        target_speed = Vector(target.speedX, target.speedY)

        def get_hit_time():
            v0 = INITIAL_SHELL_VELOCITY
            a = SHELL_ACCELERATION
            d = max(0, tank.get_distance_to_unit(target) - 60)
            return solve_quadratic(a / 2, v0, -d)

        def max_move_distance(v0, a, max_v, t):
            #TODO: this estimation is rough
            v0 = max(-max_v, min(v0, max_v))
            if fabs(v0 + a * t) > max_v:
                if a > 0:
                    t1 = fabs((max_v - v0) / a)
                else:
                    t1 = fabs((-max_v - v0) / a)
                t2 = t - t1
            else:
                t1 = t
                t2 = 0
            if a > 0:
                return a * t1**2 / 2 + v0 * t1 + max_v * t2
            else:
                return a * t1**2 / 2 + v0 * t1 - max_v * t2

        t = get_hit_time()
        center = Vector(target.x - tank.x, target.y - tank.y)

        v0 = target_speed.projection(target_direction)
        target_avoid_distance_forward = max_move_distance(
            v0, FICTIVE_TARGET_ACCELERATION, MAX_TARGET_SPEED, t)
        target_avoid_distance_backward = max_move_distance(
            v0, -FICTIVE_TARGET_ACCELERATION * 0.75, MAX_TARGET_SPEED, t)
        max_pos = target_v + target_avoid_distance_forward * target_direction
        min_pos = target_v + target_avoid_distance_backward * target_direction

        target_turret_n_cos = fabs(cos(fabs(b - target.angle) + PI / 2))

        var = fabs(
            (target_avoid_distance_forward - target_avoid_distance_backward) *
            target_turret_n_cos)

        estimate_pos = target_v + target_direction * (
            (target_avoid_distance_forward + target_avoid_distance_backward) /
            2)
        vulnerable_width = max(90 * target_turret_n_cos,
                               60 * (1 - target_turret_n_cos))

        shoot = physics.will_hit(
            tank, fictive_unit(
                target, max_pos.x, max_pos.y)) and physics.will_hit(
                    tank, fictive_unit(target, min_pos.x, min_pos.y))

        return "fw=%s, bw=%s, t=%s, var=%s, wid=%s, degree=%s, shoot=%s" % (
            int(target_avoid_distance_forward),
            int(target_avoid_distance_backward), int(t), int(var),
            vulnerable_width,
            fabs(tank.get_turret_angle_to(estimate_pos.x, estimate_pos.y)) /
            PI * 180, shoot)