From 04a6703fd66a7d34b2556a9c203c4dada3baca38 Mon Sep 17 00:00:00 2001 From: scratko Date: Fri, 12 Apr 2024 03:17:46 +0300 Subject: Added behavior modes Reverse direction Random direction --- Makefile | 13 ++-- field.c | 20 +++--- field.h | 3 +- ghosts.c | 79 ++++++++++++++++++----- ghosts.h | 9 ++- pac.c | 19 +++++- pac.h | 1 + pacman.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 8 files changed, 308 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 796dbbb..aefc9fa 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ -CC=gcc -CFLAGS=-Wall -g -c +SRCMODULES = field.c ghosts.c pac.c queue.c pacman.c +OBJMODULES = $(SRCMODULES:.c=.o) +CC = gcc +CFLAGS = -Wall -g -c LIBS = -lncurses -lm @@ -8,7 +10,10 @@ all: pacman %.o: %.с %.h $(CC) $(CFLAGS) $< -o $@ -OBJMODULES=field.o ghosts.o pac.o queue.o pacman.o - pacman: $(OBJMODULES) $(CC) $(LIBS) $^ -o $@ + +-include deps.mk + +deps.mk: $(SRCMODULES) + $(CC) -MM $^ > $@ diff --git a/field.c b/field.c index add43d1..37a5be1 100644 --- a/field.c +++ b/field.c @@ -8,7 +8,7 @@ static const char field_sample[field_height][field_width] = { {"////////////////////////////"}, {"/1....2.....1//1.....2....1/"}, {"/.////./////.//./////.////./"}, - {"/./ /./ /.//./ /./ /./"}, + {"/*/ /./ /.//./ /./ /*/"}, {"/./ /./ /.//./ /./ /./"}, {"/.////./////.//./////.////./"}, {"/2....3..2..2..2..2..3....2/"}, @@ -26,7 +26,7 @@ static const char field_sample[field_height][field_width] = { {"//////.// //////// //.//////"}, {"/1....3..2..1//1..2..3....1/"}, {"/.////./////.//./////.////./"}, - {"/.////./////.//./////.////./"}, + {"/*////./////.//./////.////*/"}, {"/1.1//2..2..y..y..2..2//1.1/"}, {"///.//.//.////////.//.//.///"}, {"///.//.//.////////.//.//.///"}, @@ -70,21 +70,24 @@ void print_field(game_space field) symbol = field[i][j]; move(i, j); switch(symbol) { - case '1': - case '2': - case '3': + case one_path: + case two_paths: + case three_paths: if(field_has_coin(i, j)) addch('.'); else addch(' '); break; - case '/': + case block: addch('/'); break; - case '.': + case coin: addch('.'); break; - case '#': + case energizer: + addch('*'); + break; + case door: addch('#'); break; } @@ -138,6 +141,7 @@ void clear_or_revert_symbol(game_space field, struct coordinates position, case door: addch('#'); break; + case energizer: case coin: queue_consists_point(eaten_coins, position) ? addch(' ') : addch('.'); diff --git a/field.h b/field.h index 977a3d9..7eb4ba1 100644 --- a/field.h +++ b/field.h @@ -8,7 +8,8 @@ enum { right_outside_tunnel_x = field_width, door = '#', block = '/', - coin = '.' + coin = '.', + energizer = '*' }; enum intersection_type { diff --git a/ghosts.c b/ghosts.c index fe1a51f..ded74e7 100644 --- a/ghosts.c +++ b/ghosts.c @@ -17,7 +17,7 @@ void initialize_ghost(struct ghost_type *ghost, enum ghost_color color) ghost->home_position.y = red_home_y; ghost->home_position.x = red_home_x; ghost->color = red; - ghost->mode = scatter; + ghost->frightened_status = 0; ghost->direction = none; break; case pink: @@ -26,7 +26,7 @@ void initialize_ghost(struct ghost_type *ghost, enum ghost_color color) ghost->home_position.y = pink_home_y; ghost->home_position.x = pink_home_x; ghost->color = pink; - ghost->mode = scatter; + ghost->frightened_status = 0; ghost->direction = none; break; case blue: @@ -35,7 +35,7 @@ void initialize_ghost(struct ghost_type *ghost, enum ghost_color color) ghost->home_position.y = blue_home_y; ghost->home_position.x = blue_home_x; ghost->color = blue; - ghost->mode = scatter; + ghost->frightened_status = 0; ghost->direction = none; break; case orange: @@ -44,7 +44,7 @@ void initialize_ghost(struct ghost_type *ghost, enum ghost_color color) ghost->home_position.y = orange_home_y; ghost->home_position.x = orange_home_x; ghost->color = orange; - ghost->mode = scatter; + ghost->frightened_status = 0; ghost->direction = none; break; } @@ -56,18 +56,19 @@ void pull_out_ghosts(int *get_out_stage, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { - enum { final_stage = 1 }; - enum movement_direction red_moves[] = { none, right, up, up, left }; - enum movement_direction blue_moves[] = { none, left, up, up, left }; - enum movement_direction pink_moves[] = { right, up, up, up, right }; - enum movement_direction orange_moves[] = { left, up, up, up, right }; + 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 > final_stage) { + 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]; - orange_ghost->direction = orange_moves[index]; --*get_out_stage; } @@ -188,8 +189,9 @@ static struct coordinates get_near_point(struct coordinates consider_point, return found_point; } -static enum movement_direction find_direction(struct coordinates found_point, - struct coordinates ghost_position) +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; @@ -274,13 +276,12 @@ void breadth_first_search(game_space field, struct ghost_type *ghost, } } ghost->direction = - find_direction(consider_point, start_point); -#if 1 + find_direction_by_near_point(consider_point, + start_point); if(ghost->direction == reverse_direction) { queue_push(&reviewed_points, &consider_point); continue; } -#endif clear_both_queues(&next_points, &reviewed_points); return; } @@ -370,3 +371,49 @@ void compute_distance_between_points(game_space field, } 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; +} diff --git a/ghosts.h b/ghosts.h index f407839..d55da6a 100644 --- a/ghosts.h +++ b/ghosts.h @@ -38,7 +38,7 @@ struct ghost_type { struct coordinates position; struct coordinates home_position; enum ghost_color color; - enum behavior_mode mode; + int frightened_status; enum movement_direction direction; }; @@ -64,6 +64,8 @@ void redirect(game_space field, enum intersection_type paths, void (*pathfinder)(game_space, struct ghost_type*, struct coordinates target_point)); +void random_redirect(game_space field, struct ghost_type *ghost); + void breadth_first_search(game_space field, struct ghost_type *ghost, struct coordinates target_point); @@ -74,4 +76,9 @@ struct coordinates identify_target_in_front(struct pacman pac, int shift); struct coordinates identify_blue_target(struct pacman pac, const struct ghost_type *red_ghost); +void reverse_all_ghosts(struct ghost_type *red_ghost, + struct ghost_type *pink_ghost, + struct ghost_type *blue_ghost, + struct ghost_type *orange_ghost); + #endif diff --git a/pac.c b/pac.c index ed929ae..dcd3b40 100644 --- a/pac.c +++ b/pac.c @@ -9,6 +9,7 @@ void initialize_pac(struct pacman *pac) pac->position.y = pac_y; pac->position.x = pac_x; pac->direction = none; + pac->is_energizer_eaten = 0; } static enum movement_direction get_matching_for_directions(game_space field, @@ -124,8 +125,8 @@ void change_pac_direction(game_space field, struct pacman *pac, int key, static int is_coin_symbol(int symbol) { return - symbol == coin || symbol == one_path || symbol == two_paths || - symbol == three_paths; + symbol == coin || symbol == energizer || symbol == one_path || + symbol == two_paths || symbol == three_paths; } static int check_coin(game_space field, struct coordinates position, @@ -139,6 +140,15 @@ static int check_coin(game_space field, struct coordinates position, !queue_consists_point(eaten_coins, position); } +static void eat_energizer(game_space field, struct pacman *pac) +{ + int x, y; + x = pac->position.x; + y = pac->position.y; + if(field[y][x] == energizer) + pac->is_energizer_eaten = 1; +} + void make_pac_move(game_space field, struct pacman *pac, struct queue *eaten_coins) { @@ -159,7 +169,10 @@ void make_pac_move(game_space field, struct pacman *pac, default: return; } - if(check_coin(field, pac->position, eaten_coins)) + if(check_coin(field, pac->position, eaten_coins)) { queue_push(eaten_coins, &pac->position); + ++pac->coins_eaten; + } change_point_if_outside_tunnel(&pac->position); + eat_energizer(field, pac); } diff --git a/pac.h b/pac.h index dfa6a86..ccee0e3 100644 --- a/pac.h +++ b/pac.h @@ -14,6 +14,7 @@ struct pacman { unsigned char coins_eaten; struct coordinates position; enum movement_direction direction; + int is_energizer_eaten; }; void initialize_pac(struct pacman *pac); diff --git a/pacman.c b/pacman.c index 95d121d..f9b1278 100644 --- a/pacman.c +++ b/pacman.c @@ -5,14 +5,62 @@ #include #include #include +#include enum { - timeout_duration = 0, - sleep_duration = 190000, - key_escape = 27, - count_get_out_moves = 5 + timeout_duration = 0, + sleep_duration = 190000, + key_escape = 27, + count_get_out_moves = 6, + chase_move_limit = 100, + scatter_move_limit = 35, + frightened_move_limit = 30, + phase_limit = 4 }; +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; + ++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) { @@ -20,7 +68,9 @@ static int is_up_move_blocked(const struct ghost_type *ghost, ghost->direction == right); } -static void pathfinder_stage(game_space field, struct pacman pac, +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, @@ -30,39 +80,117 @@ static void pathfinder_stage(game_space field, struct pacman pac, enum intersection_type intersection; int color_priority; struct ghost_type *current_ghost; - struct coordinates target_point; + struct coordinates new_target_point; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: current_ghost = red_ghost; - target_point = pac.position; - search_method = breadth_first_search; + 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: current_ghost = pink_ghost; - target_point = identify_target_in_front(pac, pink_shift); + 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: current_ghost = blue_ghost; - target_point = identify_blue_target(pac, red_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: current_ghost = orange_ghost; - target_point = pac.position; - search_method = breadth_first_search; - break; + 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, target_point, + 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: + 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; + } + intersection = get_intersection(field, current_ghost); + if(intersection != direct_path) + random_redirect(field, current_ghost); + } +} + +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); +} + static void initialize_ghosts(struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, @@ -74,8 +202,20 @@ static void initialize_ghosts(struct ghost_type *red_ghost, initialize_ghost(orange_ghost, orange); } -static void ncurses_params() +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(); @@ -92,38 +232,74 @@ int main() 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; - get_out_stage = count_get_out_moves; - ncurses_params(); + 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 - pathfinder_stage(field, pac, &red_ghost, &pink_ghost, &blue_ghost, - &orange_ghost); - make_pac_move(field, &pac, &eaten_coins); + 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 + */ display_character(pac.position.y, pac.position.x, pac_char); display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); usleep(sleep_duration); +#if 1 + move(0, 50); + if(mode_params.current_mode == chase) + printw("CHASE"); + else if(mode_params.current_mode == scatter) + printw("SCATTER"); + else if(mode_params.current_mode == frightened) + printw("FRIGHTENED"); + refresh(); +#endif } queue_clear(&eaten_coins); endwin(); -- cgit v1.2.3