back to scratko.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2024-04-12 03:17:46 +0300
committerscratko <m@scratko.xyz>2024-04-12 03:17:46 +0300
commit04a6703fd66a7d34b2556a9c203c4dada3baca38 (patch)
tree3d2cbdaae515d90747e507ba8a8ebfd7bdc44fed
parent235f8481502263fcdb4823ff0bc4e8f831bc934d (diff)
downloadpacman-04a6703fd66a7d34b2556a9c203c4dada3baca38.tar.gz
pacman-04a6703fd66a7d34b2556a9c203c4dada3baca38.tar.bz2
pacman-04a6703fd66a7d34b2556a9c203c4dada3baca38.zip
Added behavior modes
Reverse direction Random direction
-rw-r--r--Makefile13
-rw-r--r--field.c20
-rw-r--r--field.h3
-rw-r--r--ghosts.c79
-rw-r--r--ghosts.h9
-rw-r--r--pac.c19
-rw-r--r--pac.h1
-rw-r--r--pacman.c218
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 <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
+#include <time.h>
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();