#include "ghosts.h" #include "field.h" #include "pac.h" #include "queue.h" #include #include #include enum search_flag { viewed, not_viewed }; void initialize_ghost(struct ghost_type *ghost, enum ghost_color color) { switch(color) { case red: ghost->position.y = red_y; ghost->position.x = red_x; ghost->home_position.y = red_home_y; ghost->home_position.x = red_home_x; ghost->color = red; ghost->frightened_status = 0; ghost->direction = none; break; case pink: ghost->position.y = pink_y; ghost->position.x = pink_x; ghost->home_position.y = pink_home_y; ghost->home_position.x = pink_home_x; ghost->color = pink; ghost->frightened_status = 0; ghost->direction = none; break; case blue: ghost->position.y = blue_y; ghost->position.x = blue_x; ghost->home_position.y = blue_home_y; ghost->home_position.x = blue_home_x; ghost->color = blue; ghost->frightened_status = 0; ghost->direction = none; break; case orange: ghost->position.y = orange_y; ghost->position.x = orange_x; ghost->home_position.y = orange_home_y; ghost->home_position.x = orange_home_x; ghost->color = orange; ghost->frightened_status = 0; ghost->direction = none; break; } } void pull_out_ghosts(int *get_out_stage, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { enum { prefinal_stage = 2, final_stage = 1 }; enum movement_direction red_moves[] = { none, none, right, up, up, left }; enum movement_direction blue_moves[] = { none, none, left, up, up, left }; enum movement_direction pink_moves[] = { up, right, up, up, up, right }; enum movement_direction orange_moves[] = { none, left, up, up, up, right }; int index = *get_out_stage - 1; if(*get_out_stage > prefinal_stage) { red_ghost->direction = red_moves[index]; blue_ghost->direction = blue_moves[index]; } if(*get_out_stage > final_stage) orange_ghost->direction = orange_moves[index]; pink_ghost->direction = pink_moves[index]; --*get_out_stage; } static void change_position(struct ghost_type *ghost, enum movement_direction direction) { switch(direction) { case left: --ghost->position.x; break; case right: ++ghost->position.x; break; case up: --ghost->position.y; break; case down: ++ghost->position.y; break; default: return; } change_point_if_outside_tunnel(&ghost->position); } void make_ghost_moves(game_space field, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost, struct queue *eaten_coins) { clear_or_revert_symbol(field, red_ghost->position, ghost_char, eaten_coins); clear_or_revert_symbol(field, pink_ghost->position, ghost_char, eaten_coins); clear_or_revert_symbol(field, blue_ghost->position, ghost_char, eaten_coins); clear_or_revert_symbol(field, orange_ghost->position, ghost_char, eaten_coins); change_position(red_ghost, red_ghost->direction); change_position(pink_ghost, pink_ghost->direction); change_position(blue_ghost, blue_ghost->direction); change_position(orange_ghost, orange_ghost->direction); } static void pave_only_way(game_space field, struct ghost_type *ghost) { struct free_directions path = find_free_directions(field, ghost->position.y, ghost->position.x); enum movement_direction reverse_direction = ghost->direction; reverse_direction ^= 1; if(path.left && left != reverse_direction) ghost->direction = left; else if(path.right && right != reverse_direction) ghost->direction = right; else if(path.up && up != reverse_direction) ghost->direction = up; else if(path.down && down != reverse_direction) ghost->direction = down; } struct coordinates identify_blue_target(struct pacman pac, const struct ghost_type *red_ghost) { struct coordinates difference, middle_point, result_point; middle_point = identify_target_in_front(pac, blue_shift); difference.x = middle_point.x - red_ghost->position.x; difference.y = middle_point.y - red_ghost->position.y; result_point.x = middle_point.x + difference.x; result_point.y = middle_point.y + difference.y; return result_point; } struct coordinates identify_target_in_front(struct pacman pac, int shift) { int x, y; struct coordinates target; x = pac.position.x; y = pac.position.y; switch(pac.direction) { case left: x -= shift; break; case right: x += shift; break; case up: y -= shift; break; case down: y += shift; break; default: ; } target.x = x; target.y = y; return target; } void redirect(game_space field, enum intersection_type paths, struct ghost_type *ghost, struct coordinates target_point, void (*pathfinder)(game_space, struct ghost_type*, struct coordinates target_point)) { if(paths == one_path) pave_only_way(field, ghost); else pathfinder(field, ghost, target_point); } static struct coordinates get_near_point(struct coordinates consider_point, int dx, int dy) { struct coordinates found_point; found_point.x = consider_point.x + dx; found_point.y = consider_point.y + dy; return found_point; } static enum movement_direction find_direction_by_near_point(struct coordinates found_point, struct coordinates ghost_position) { int dx, dy; enum movement_direction new_direction; dx = found_point.x - ghost_position.x; dy = found_point.y - ghost_position.y; switch(dx) { case 1: new_direction = dy == 0 ? right : none; break; case 0: new_direction = dy == -1 ? up : down; break; case -1: new_direction = dy == 0 ? left : none; break; } return new_direction; } static void clear_both_queues(struct queue *next_points, struct queue *reviewed_points) { queue_clear(next_points); queue_clear(reviewed_points); } static int is_bfs_search_for_orange(enum search_flag *current_width, int *move_count) { if(*current_width == not_viewed) { ++*move_count; *current_width = viewed; } return *move_count > orange_search_limit; } void breadth_first_search(game_space field, struct ghost_type *ghost, struct coordinates target_point) { int move_count; enum search_flag current_width = not_viewed; enum movement_direction reverse_direction; struct coordinates consider_point, near_point; struct coordinates start_point = { ghost->position.y, ghost->position.x }; struct queue next_points, reviewed_points; move_count = 0; reverse_direction = ghost->direction; reverse_direction ^= 1; queue_init(&next_points); queue_init(&reviewed_points); queue_push(&next_points, &target_point); queue_push(&reviewed_points, &target_point); while(!empty(&next_points)) { if(ghost->position.x == target_point.x && ghost->position.y == target_point.y) { ghost->direction=none; break; } consider_point = queue_front(&next_points); pop(&next_points); int dx; for(dx = -1; dx <= 1; ++dx) { int dy; for(dy = -1; dy <= 1; ++dy) { if(dx != 0 && dy != 0) continue; near_point = get_near_point(consider_point, dx, dy); change_point_if_outside_tunnel(&near_point); if(is_obstacle(field, near_point.x, near_point.y)) continue; if(queue_consists_point(&reviewed_points, near_point)) continue; if(equal_points(start_point, near_point)) { if(ghost->color == orange) { if(!is_bfs_search_for_orange(¤t_width, &move_count)) { redirect(field, two_paths, ghost, ghost->home_position, compute_distance_between_points); clear_both_queues(&next_points, &reviewed_points); return; } } ghost->direction = find_direction_by_near_point(consider_point, start_point); if(ghost->direction == reverse_direction) { queue_push(&reviewed_points, &consider_point); continue; } clear_both_queues(&next_points, &reviewed_points); return; } if(ghost->color == orange && current_width == not_viewed) { current_width = viewed; ++move_count; } queue_push(&next_points, &near_point); queue_push(&reviewed_points, &near_point); } } current_width = not_viewed; } } static int standard_distance(int x1, int y1, int x2, int y2) { int dx, dy; dx = abs(x1 - x2); dx = dx > field_width ? field_width - dx : dx; dy = abs(y1 - y2); return sqrt(dx*dx + dy*dy); } static int is_minimal_distance(int min_distance, int tmp_distance, enum movement_direction cur_direction) { return min_distance == 0 || tmp_distance < min_distance || (tmp_distance == min_distance && cur_direction != right); } static void set_final_direction(int *min_distance, enum movement_direction cur_direction, enum movement_direction *final_direction, struct coordinates initial_point, struct coordinates target_point) { int x1, y1, x2, y2; int tmp_distance; x1 = initial_point.x; y1 = initial_point.y; x2 = target_point.x; y2 = target_point.y; tmp_distance = standard_distance(x1, y1, x2, y2); if(is_minimal_distance(*min_distance, tmp_distance, cur_direction)) { *min_distance = tmp_distance; *final_direction = cur_direction; } } void compute_distance_between_points(game_space field, struct ghost_type *ghost, struct coordinates target_point) { enum movement_direction final_direction, ghost_direction; struct coordinates initial_point, changed_initial_point; int min_distance; final_direction = none; ghost_direction = ghost->direction; initial_point = ghost->position; min_distance = 0; struct free_directions consider_paths = find_free_directions(field, initial_point.y, initial_point.x); if(consider_paths.right && ghost_direction != left) { changed_initial_point.x = initial_point.x + 1; changed_initial_point.y = initial_point.y; set_final_direction(&min_distance, right, &final_direction, changed_initial_point, target_point); } if(consider_paths.down && ghost_direction != up) { changed_initial_point.x = initial_point.x; changed_initial_point.y = initial_point.y + 1; set_final_direction(&min_distance, down, &final_direction, changed_initial_point, target_point); } if(consider_paths.left && ghost_direction != right) { changed_initial_point.x = initial_point.x - 1; changed_initial_point.y = initial_point.y; set_final_direction(&min_distance, left, &final_direction, changed_initial_point, target_point); } if(consider_paths.up && ghost_direction != down) { changed_initial_point.x = initial_point.x; changed_initial_point.y = initial_point.y - 1; set_final_direction(&min_distance, up, &final_direction, changed_initial_point, target_point); } ghost->direction = final_direction; } static enum movement_direction get_random_direction() { return 0 + (int)(4.0*rand()/(RAND_MAX + 1.0)); } static int is_equal_directions(enum movement_direction random_direction, struct free_directions paths) { switch(random_direction) { case left: return paths.left; case right: return paths.right; case up: return paths.up; case down: return paths.down; default: ; } return 0; } void random_redirect(game_space field, struct ghost_type *ghost) { enum movement_direction random_direction; struct free_directions paths = find_free_directions(field, ghost->position.y, ghost->position.x); random_direction = get_random_direction(); while(!is_equal_directions(random_direction, paths)) random_direction = get_random_direction(); ghost->direction = random_direction; } void reverse_all_ghosts(struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { red_ghost->direction ^= 1; pink_ghost->direction ^= 1; blue_ghost->direction ^= 1; orange_ghost->direction ^= 1; }