#include "field.h" #include "ghosts.h" #include "pac.h" #include "queue.h" #include #include #include #include enum { timeout_duration = 0, sleep_duration = 190000, key_escape = 27, count_get_out_moves = 6, chase_move_limit = 70, scatter_move_limit = 35, frightened_move_limit = 30, phase_limit = 4, prison_limit = 30 }; struct mode_type { enum behavior_mode current_mode; int chase_count; int scatter_count; int frightened_count; int phase_number; int reverse_direction; }; static void change_mode(struct mode_type *mode_params) { if(!(mode_params->current_mode == frightened) && mode_params->phase_number == phase_limit) return; switch(mode_params->current_mode) { case chase: if(mode_params->chase_count > chase_move_limit) { mode_params->current_mode = scatter; mode_params->chase_count = 0; ++mode_params->phase_number; if(mode_params->phase_number == phase_limit) mode_params->current_mode = chase; if(mode_params->phase_number != phase_limit) ++mode_params->reverse_direction; } break; case scatter: if(mode_params->scatter_count > scatter_move_limit) { mode_params->current_mode = chase; mode_params->scatter_count = 0; ++mode_params->reverse_direction; } break; case frightened: if(mode_params->frightened_count > frightened_move_limit) { mode_params->current_mode = mode_params->chase_count || mode_params->phase_number == phase_limit ? chase : scatter; mode_params->frightened_count = 0; ++mode_params->reverse_direction; } } } static int is_up_move_blocked(const struct ghost_type *ghost, enum intersection_type intersection) { return intersection == yellow_block && (ghost->direction == left || ghost->direction == right); } static void pathfinder_stage(game_space field, struct mode_type *mode_params, const struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { void (*search_method)(game_space, struct ghost_type*, struct coordinates); enum intersection_type intersection; int color_priority; struct ghost_type *current_ghost; struct coordinates new_target_point; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: if(red_ghost->prison_params.active) continue; current_ghost = red_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : pac->position; search_method = mode_params->current_mode == scatter ? compute_distance_between_points : breadth_first_search; break; case pink: if(pink_ghost->prison_params.active) continue; current_ghost = pink_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : identify_target_in_front(*pac, pink_shift); search_method = compute_distance_between_points; break; case blue: if(blue_ghost->prison_params.active) continue; current_ghost = blue_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : identify_blue_target(*pac, red_ghost); search_method = compute_distance_between_points; break; case orange: if(orange_ghost->prison_params.active) continue; current_ghost = orange_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : pac->position; search_method = mode_params->current_mode == scatter ? compute_distance_between_points : breadth_first_search; } intersection = get_intersection(field, current_ghost); if(is_up_move_blocked(current_ghost, intersection)) continue; if(intersection != direct_path) redirect(field, intersection, current_ghost, new_target_point, search_method); } } static void random_pathfinder_stage(game_space field, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { enum intersection_type intersection; int color_priority; struct ghost_type *current_ghost; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: if(red_ghost->prison_params.active) continue; current_ghost = red_ghost; break; case pink: if(pink_ghost->prison_params.active) continue; current_ghost = pink_ghost; break; case blue: if(blue_ghost->prison_params.active) continue; current_ghost = blue_ghost; break; case orange: if(orange_ghost->prison_params.active) continue; current_ghost = orange_ghost; break; } intersection = get_intersection(field, current_ghost); if(intersection != direct_path) random_redirect(field, current_ghost); } } static int is_outside_prison(struct ghost_type ghost) { return ghost.prison_params.active && ghost.direction == up; } static int is_ghost_prisoner(struct ghost_type ghost) { return ghost.prison_params.active && ghost.direction == none; } static void prison_leaving_stage(game_space field, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { struct ghost_type *current_ghost; int color_priority; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: current_ghost = red_ghost; break; case pink: current_ghost = pink_ghost; break; case blue: current_ghost = blue_ghost; break; case orange: current_ghost = orange_ghost; break; } if(is_ghost_prisoner(*current_ghost)) { ++current_ghost->prison_params.prison_counter; /* * liberation */ if(current_ghost->prison_params.prison_counter == prison_limit) { current_ghost->prison_params.prison_counter = 0; current_ghost->direction = up; } } else if(is_outside_prison(*current_ghost)) current_ghost->prison_params.active = current_ghost->position.y == liberation_y ? 0 : 1; } } static int is_castling(struct pacman pac, struct ghost_type ghost) { return ghost.capture_info.status && pac.position.x == ghost.capture_info.previous_ghost_position.x && pac.position.y == ghost.capture_info.previous_ghost_position.y && ghost.position.x == ghost.capture_info.previous_pac_position.x && ghost.position.y == ghost.capture_info.previous_pac_position.y; } static void caughting_stage(game_space field, const struct mode_type *mode_params, struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { struct ghost_type *current_ghost; current_ghost = red_ghost; int color_priority; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: if(is_pac_nearby(*pac, *red_ghost)) { set_capture_info(red_ghost, pac); continue; } current_ghost = red_ghost; break; case pink: if(is_pac_nearby(*pac, *pink_ghost)) { set_capture_info(pink_ghost, pac); continue; } current_ghost = pink_ghost; break; case blue: if(is_pac_nearby(*pac, *blue_ghost)) { set_capture_info(blue_ghost, pac); continue; } current_ghost = blue_ghost; break; case orange: if(is_pac_nearby(*pac, *orange_ghost)) { set_capture_info(orange_ghost, pac); continue; } current_ghost = orange_ghost; break; } if(is_equal_points(pac->position, current_ghost->position) || is_castling(*pac, *current_ghost)) { if(mode_params->current_mode == frightened) catch_ghost(field, current_ghost); else --pac->lives; } current_ghost->capture_info.status = 0; } } static void chase_mode(game_space field, struct mode_type *mode_params, const struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { pathfinder_stage(field, mode_params, pac, red_ghost, pink_ghost, blue_ghost, orange_ghost); if(mode_params->phase_number < phase_limit) { ++mode_params->chase_count; change_mode(mode_params); } } static void scatter_mode(game_space field, struct mode_type *mode_params, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { pathfinder_stage(field, mode_params, NULL, red_ghost, pink_ghost, blue_ghost, orange_ghost); if(mode_params->phase_number < phase_limit) { ++mode_params->scatter_count; change_mode(mode_params); } } static void frightened_mode(game_space field, struct mode_type *mode_params, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { random_pathfinder_stage(field, red_ghost, pink_ghost, blue_ghost, orange_ghost); ++mode_params->frightened_count; change_mode(mode_params); set_frightened_status(mode_params->current_mode == frightened ? 1 : 0, red_ghost, pink_ghost, blue_ghost, orange_ghost); } static void initialize_ghosts(struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { initialize_ghost(red_ghost, red); initialize_ghost(pink_ghost, pink); initialize_ghost(blue_ghost, blue); initialize_ghost(orange_ghost, orange); } static void initialize_modes(struct mode_type *mode_params, int *get_out_stage) { mode_params->current_mode = scatter; mode_params->chase_count = 0; mode_params->scatter_count = 0; mode_params->frightened_count = 0; mode_params->phase_number = 0; mode_params->reverse_direction = 0; *get_out_stage = count_get_out_moves; } static void initialize_params() { srand(time(NULL)); initscr(); start_color(); cbreak(); noecho(); curs_set(0); keypad(stdscr, 1); timeout(timeout_duration); start_color(); } int main() { game_space field = NULL; struct ghost_type red_ghost, pink_ghost, blue_ghost, orange_ghost; struct pacman pac; struct queue eaten_coins; struct mode_type mode_params; int key, get_out_stage; enum movement_direction stored_direction; stored_direction = none; initialize_params(); field = get_new_field(); print_field(field); initialize_ghosts(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); initialize_pac(&pac); initialize_modes(&mode_params, &get_out_stage); queue_init(&eaten_coins); display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); display_character(pac.position.y, pac.position.x, pac_char); usleep(sleep_duration); while((key = getch()) != key_escape) { /* * pacman */ if(key != ERR) change_pac_direction(field, &pac, key, &stored_direction); else check_remaining_direction(field, &pac, &stored_direction); make_pac_move(field, &pac, &eaten_coins); if(pac.is_energizer_eaten) { mode_params.current_mode = frightened; mode_params.reverse_direction = 1; pac.is_energizer_eaten = 0; } /* * ghosts */ if(get_out_stage) pull_out_ghosts(&get_out_stage, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); else if(mode_params.reverse_direction) { reverse_all_ghosts(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); mode_params.reverse_direction = 0; } else if(mode_params.current_mode == chase) chase_mode(field, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); else if(mode_params.current_mode == scatter) scatter_mode(field, &mode_params, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); else if(mode_params.current_mode == frightened) frightened_mode(field, &mode_params, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); make_ghost_moves(field, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost, &eaten_coins); /* * displaying characters */ caughting_stage(field, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); display_character(pac.position.y, pac.position.x, pac_char); usleep(sleep_duration); prison_leaving_stage(field, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); #ifdef DEBUG move(0, 50); if(mode_params.current_mode == chase) printw("CHASE %d ", mode_params.chase_count); else if(mode_params.current_mode == scatter) printw("SCATTER %d ", mode_params.scatter_count); else if(mode_params.current_mode == frightened) printw("FRIGHTENED %d ", mode_params.frightened_count); refresh(); #endif } queue_clear(&eaten_coins); endwin(); return 0; }