def move(self, distance, index=None): if len(self.balls) == 0: return 0 count = 0 if index is None: index = len(self.balls) - 1 while index >= 0: try: ball = self.balls[index] except IndexError: print('f**k!') return new_point = self.ellipse.next_point(ball.point, distance) if new_point is None: self.balls.pop(index) count += 1 else: ball.point = new_point if index > 0: distance = max( 2 * self.radius - mathExt.get_distance( self.balls[index].point, self.balls[index - 1].point), 0) index -= 1 if len(self.balls) > 0: self._right = None self._left = None return count
def next_point(self, point, distance, finish=None): if not finish: finish = self.finish start = get_angle(point) middle = tern_search(start, finish, lambda x: get_distance( self.get_coordinates(x), point)) angle1 = bin_search(start, middle, lambda x: get_distance( self.get_coordinates(x), point), distance) angle2 = bin_search(middle, finish, lambda x: -get_distance( self.get_coordinates(x), point), distance) dist1 = get_distance(self.get_coordinates(angle1), point) dist2 = get_distance(self.get_coordinates(angle2), point) if abs(dist1 - distance) < 1e-6: return self.get_coordinates(angle1) if abs(dist2 - distance) < 1e-6: return self.get_coordinates(angle2) return None
def test_update(self): random.seed = 100 for repeat in range(100000): x = random.random() y = random.random() speed = random.random() % 100 angle = random.random() % (2 * math.pi) shot = Shot(x, y, None, angle, speed) shot.update() x1 = shot.x y1 = shot.y self.assertAlmostEqual(math_ext.get_angle((x1 - x, y1 - y)), angle) self.assertAlmostEqual(math_ext.get_distance((x1, y1), (x, y)), speed)
def test_previous_point(self): random.seed = 100 for repeat in range(100000): start, finish, width, height, ellipse = self.get_random_ellipse() radius = random.randint(1, 5) angle = random.random() % math.pi point = ellipse.get_coordinates(angle) previous_point = ellipse.previous_point(point, radius) if previous_point is None: self.assertLess(get_distance(point, ellipse.start_point), radius - 1e-6) return dist = get_distance(previous_point, point) self.assertTrue( previous_point in ellipse, previous_point[0] * previous_point[0] / (ellipse.width * ellipse.width) + previous_point[1] * previous_point[1] / (ellipse.height * ellipse.height)) self.assertLess(abs(dist - radius), 1e-6, msg=f"{previous_point[0]}, {previous_point[1]}," f" {dist}, {radius}")
def insert_ball(self, point, color): # point lies between left & right if not(self.right[0] < point[0] < self.left[0] and len(self.balls) > 0): return 0 count = 0 position = self.find_position(point[0]) ball = None if position < len(self.balls): distance = 2 * self.radius - mathExt.get_distance( point, self.balls[position].point ) if distance > -1e-6: point = self.ellipse.next_point(point, distance) if not point: count += 1 return count ball = Ball(point, color) if position > 0: distance = 2 * self.radius - mathExt.get_distance( point, self.balls[position - 1].point ) if distance > -1e-6: count = self.move(distance, position - 1) position -= count ball = Ball(point, color) ball.collapsing = True if position == len(self.balls): self.add_ball(color) else: self.balls.insert(position, ball) return count
def check_point_finished(self, point, distance): point_angle = get_angle(point) return ( self.finish < point_angle or get_distance(point, self.finish_point) < distance )
def check_point_pre_started(self, point, distance): point_angle = get_angle(point) return ( point_angle < self.start or get_distance(point, self.start_point) < distance )
def get_distance(self, angle1, angle2): return get_distance(self.get_coordinates(angle1), self.get_coordinates(angle2))
def is_space(self, last, radius): return get_distance(last, self.get_coordinates(self.start)) > 3 * radius
def __eq__(self, other): return (self.color == other.color and get_distance(self.point, other.point) < 1e-4)