def close_claim(self, poly, speed, game): inside, outside = game_utils.cut_poly(self.game_area, poly) # we will triangulate only one of the guys # then we check if it is the bigger portion (last known area minus new) total_area = game_utils.total_area([self._start_game_area]) prev_remaining = total_area - game.stats['claimed_area'] rects_out = game_utils.triangulate(outside) or [] qixes = [qix for qix in self.qix if not qix.claimed] # flip sides if the qix is not in the game area - can't claim # qix space claimed_qix = [] for qix in qixes: if not game_utils.in_area((qix.x, qix.y), rects_out, on_line=True): claimed_qix.append(qix) claimed_area = prev_remaining - game_utils.total_area(rects_out) available_area = prev_remaining - claimed_area if (len(claimed_qix) > len(qixes) / 2.0) or (available_area < claimed_area and len(claimed_qix) >= len(qixes)): # outside normally should be bigger than inside # exception is when we have more qix on the smaller patch inside, outside = outside, inside rects_out = game_utils.triangulate(outside) or [] claimed_area = prev_remaining - game_utils.total_area(rects_out) for qix in qixes: if not game_utils.in_area((qix.x, qix.y), rects_out, on_line=True): qix.claimed = True self.game_rects = rects_out self.game_area = outside self.game_area_path.points = outside claimed = sprites.ClaimedPoly(inside, speed) self.claimed_polys_containter.add_child(claimed) claimed.appear() self.claimed_polys.append((inside, 1)) for qix in self.qix: # make sure they are not easing some place nasty qix.next_target() game.update_score(claimed_area, speed)
def in_free_area(self, dot): """checks if the dot is in the free area""" if not self.in_game_bounds(dot): # first we check if the dot is within out game area return False return game_utils.in_area(dot, self.game_rects, on_line=True)
def next_target(self, sprite=None): self.prev_x, self.prev_y = self.x, self.y scene = self.get_scene() if not scene: return game_rects, game_poly = scene.board.game_rects, scene.board.game_area game_lines = [(dot1, dot2) for dot1, dot2 in zip(game_poly, game_poly[1:])] delta_angle = 0 angle_range = 180 in_area, stuck = False, 0 while not in_area and stuck < 10: stuck += 1 delta_angle = self.current_angle - math.radians(angle_range / 2) + random.random() * math.radians(angle_range) distance = random.randint(self.min_distance, self.max_distance) x, y = self.x + distance * math.cos(delta_angle), self.y + distance * math.sin(delta_angle) x, y = int(x), int(y) dots = [(x, y)] in_area = all((game_utils.in_area(dot, game_rects) for dot in dots)) if in_area: # check for overlaps line_pairs = ((((x, y), (self.x, self.y)), line) for line in game_lines) for pair in line_pairs: if game_utils.intersection(*pair): in_area = False break if not in_area: angle_range += 60 self.current_angle = delta_angle % math.radians(360) self.steps = random.randint(self.min_steps, self.max_steps) self.current_step = 0 if stuck < 10: self.next_x, self.next_y = x, y self.next_distance = distance
def _handle_keys(self, keys_down, game): x, y = self.cube.x, self.cube.y # if we have direction, we know that user wants to do something # when drawing hasn't been initiated, user can move around the game poly # moving around game poly means the dot is on the line at any given time # when drawing is started, user can move all over the place but can't bump # into the current drawing polygon # path is closed if the move ends up on the game poly # # both cases we will want to adjust the new_x or new direction so that # it is somewhere on the line game_poly_dot, non_game_poly_dot = None, None current_pos = (self.cube.x, self.cube.y) if current_pos in self.game_area: current_line = [game_utils.prev_dot(current_pos, self.game_area), current_pos, game_utils.next_dot(current_pos, self.game_area)] else: current_line = game_utils.on_line(current_pos, self.game_area) key_directions = { gdk.KEY_Left: "left", gdk.KEY_j: "left", gdk.KEY_J: "left", gdk.KEY_Right: "right", gdk.KEY_l: "right", gdk.KEY_L: "right", gdk.KEY_Up: "up", gdk.KEY_i: "up", gdk.KEY_I: "up", gdk.KEY_Down: "down", gdk.KEY_k: "down", gdk.KEY_K: "down", } direction = None for keyval in reversed(keys_down): if keyval in key_directions: direction = key_directions[keyval] break if not direction: return speed_direction = 1 if direction in ("right", "down") else -1 # find the furthest step we can take for the next game polygon dot # when not drawing that's as far as we can go on current line # when drawing, that's the closest border within step for speed in reversed(range(self.cube.speed)): game_x = x if direction in ("up", "down") else x + (speed + 1) * speed_direction game_y = y if direction in ("left", "right") else y + (speed + 1) * speed_direction if current_line: if not game_poly_dot and game_utils.on_line((game_x, game_y), current_line): # if we are on a line then we are looking for the max position at # which we still have a hit game_poly_dot = (game_x, game_y) else: # roaming around - checking if the next move is valid if game_utils.on_line((game_x, game_y), self.game_area): game_poly_dot = (game_x, game_y) # look for the furthest valid non-game poly # we stop when we find non-poly point and then bump into an on-line point for speed in range(self.cube.speed): game_x = x if direction in ("up", "down") else x + (speed + 1) * speed_direction game_y = y if direction in ("left", "right") else y + (speed + 1) * speed_direction on_line = game_utils.on_line((game_x, game_y), self.game_area) if not self.in_game_bounds((game_x, game_y)): break if not on_line: non_game_poly_dot = (game_x, game_y) elif on_line and non_game_poly_dot: break space_down = any([key in keys_down for key in (gdk.KEY_space, gdk.KEY_Shift_L, gdk.KEY_Shift_R)]) if space_down and non_game_poly_dot and not game.claiming: if game_utils.in_area(non_game_poly_dot, self.game_rects, on_line=True): game.claiming = True self.cube.set_drawing(True) self._current_direction = None if game.claiming and self._current_direction != direction: self._current_direction = direction if (self.cube.x, self.cube.y) not in self.current_polygon: self.current_polygon.append((self.cube.x, self.cube.y)) # when we are drawing, we can move outside the claimed poly's # when we are moving around, we can move only within the poly # check if the move is valid # we will go through all lines and check that our path is not # intersecting if game.claiming and game_poly_dot: self.close_claim(self.current_polygon + [game_poly_dot], self.cube.current_speed, game) game.claiming = False self.cube.set_drawing(False) self.current_polygon = [] self.current_polygon_path.points = [] self.cube.x, self.cube.y = game_poly_dot self.cube.current_line = game_utils.on_line(game_poly_dot, self.game_area) return on_current_poly = non_game_poly_dot and game_utils.on_line(non_game_poly_dot, self.current_polygon) is not None if game.claiming and not on_current_poly and non_game_poly_dot: if game_utils.in_area(non_game_poly_dot, self.game_rects, on_line=True): self.cube.x, self.cube.y = non_game_poly_dot self.current_polygon_path.points = self.current_polygon + [non_game_poly_dot] if not game.claiming and game_poly_dot: # legal move is one where the next dot is on the same line as the prev one line = game_utils.on_line([self.cube.x, self.cube.y], self.game_area) new_line, good_lines = None, [] if line: prev1, prev2 = line lines = [(dot1, dot2) for dot1, dot2 in zip(self.game_area, self.game_area[1:])] lines.append((self.game_area[-1], self.game_area[0])) good_lines = [line for line in lines if prev1 in line or prev2 in line] new_line = game_utils.on_line(game_poly_dot, self.game_area) if new_line in good_lines: self.cube.x, self.cube.y = game_poly_dot self.cube.current_line = new_line
def in_game_bounds(self, dot): return game_utils.in_area(dot, [self._start_game_area])