From bdee2852c13f6b02ec5207ded584839a3118233e Mon Sep 17 00:00:00 2001 From: scratko Date: Tue, 2 Apr 2024 17:43:35 +0300 Subject: Initial commit --- Makefile | 19 ++++++++ field.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ field.h | 46 ++++++++++++++++++ ghosts.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ghosts.h | 65 +++++++++++++++++++++++++ pac.c | 113 +++++++++++++++++++++++++++++++++++++++++++ pac.h | 29 ++++++++++++ pacman.c | 78 ++++++++++++++++++++++++++++++ 8 files changed, 653 insertions(+) create mode 100644 Makefile create mode 100644 field.c create mode 100644 field.h create mode 100644 ghosts.c create mode 100644 ghosts.h create mode 100644 pac.c create mode 100644 pac.h create mode 100644 pacman.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8754c3c --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +CC=gcc +CFLAGS=-Wall -g -c + +all: pacman + +pacman: ghosts.o field.o pac.o pacman.o + $(CC) ghosts.o field.o pac.o pacman.o -lncurses -o pacman + +field.o: field.c + $(CC) $(CFLAGS) field.c + +ghosts.o: ghosts.c + $(CC) $(CFLAGS) ghosts.c + +pacman.o: pacman.c + $(CC) $(CFLAGS) pacman.c + +pac.o: pac.c + $(CC) $(CFLAGS) pac.c diff --git a/field.c b/field.c new file mode 100644 index 0000000..df61097 --- /dev/null +++ b/field.c @@ -0,0 +1,163 @@ +#include "field.h" +#include "ghosts.h" +#include +#include + +static const char field_sample[field_height][field_width] = { + {"////////////////////////////"}, + {"/1....2.....1//1.....2....1/"}, + {"/.////./////.//./////.////./"}, + {"/./ /./ /.//./ /./ /./"}, + {"/./ /./ /.//./ /./ /./"}, + {"/.////./////.//./////.////./"}, + {"/2....3..2..2..2..2..3....2/"}, + {"/.////.//.////////.//.////./"}, + {"/.////.//.////////.//.////./"}, + {"/1....2//1..1//1..1//2....1/"}, + {"//////.///// // /////.//////"}, + {" /.///// // /////./ "}, + {" /.//1 1//./ "}, + {" /.// ///##/// //./ "}, + {"//////.// / /2 2//////"}, + {" 3 2/ / //2 "}, + {"//////.// //////// //.//////"}, + {" /.//2 2//./ "}, + {"//////.// //////// //.//////"}, + {"/1....3..2..1//1..2..3....1/"}, + {"/.////./////.//./////.////./"}, + {"/.////./////.//./////.////./"}, + {"/1.1//2..2..2..2..2..2//1.1/"}, + {"///.//.//.////////.//.//.///"}, + {"///.//.//.////////.//.//.///"}, + {"/1.2..1//1..1//1..1//1..2.1/"}, + {"/.//////////.//.//////////./"}, + {"/1..........2..2..........1/"}, + {"////////////////////////////"}, +}; + +static void copy_field(game_space field) +{ + int i; + for(i = 0; i < field_height; ++i) { + int j; + for(j = 0; j < field_width; ++j) + field[i][j] = field_sample[i][j]; + } +} + +game_space get_new_field() +{ + game_space field = malloc(field_width * field_height); + copy_field(field); + return field; +} + +static int is_has_point(int i, int j) +{ + return !((i == 12 && j == 9) || (i == 12 && j == 18) || + (i == 14 && j == 18) || (i == 15 && j == 9) || + (i == 17 && j == 9) || (i == 17 && j == 18)); +} + +void print_field(game_space field) +{ + int i; + char symbol; + for(i = 0; i < field_height; ++i) { + int j; + for(j = 0; j < field_width; ++j) { + symbol = field[i][j]; + move(i, j); + switch(symbol) { + case '1': + case '2': + case '3': + if(is_has_point(i, j)) + addch('.'); + else + addch(' '); + break; + case '/': + addch('/'); + break; + case '.': + addch('.'); + break; + case '#': + addch('#'); + break; + } + refresh(); + } + } +} + +void display_character(int y, int x, int symbol) +{ + move(y, x); + addch(symbol); + refresh(); +} + +void display_ghosts_on_field(struct ghost_type *red_ghost, + struct ghost_type *pink_ghost, + struct ghost_type *blue_ghost, + struct ghost_type *orange_ghost) +{ + display_character(red_ghost->position.y, red_ghost->position.x, '&'); + display_character(pink_ghost->position.y, pink_ghost->position.x, '&'); + display_character(blue_ghost->position.y, blue_ghost->position.x, '&'); + display_character(orange_ghost->position.y, orange_ghost->position.x, '&'); +} + +void clear_symbol(game_space field, int y, int x, + enum select_character character) +{ + int symbol = field[y][x]; + move(y, x); + if(character == ghost_char) { + switch(symbol) { + case '#': + addch('#'); + break; + case '.': + addch('.'); + break; + case ' ': + addch(' '); + break; + } + } + else if(character == pac_char) + addch(' '); + refresh(); +} + +enum intersection_type get_intersection(const game_space field, + struct ghost_type *ghost) +{ + int y, x, symbol; + y = ghost->position.y; + x = ghost->position.x; + symbol = field[y][x]; + switch(symbol) { + case one_path: + return one_path; + case two_paths: + return two_paths; + case three_paths: + return three_paths; + default: + return direct_path; + } +} + +struct free_directions find_free_directions(game_space field, int y, int x) +{ + struct free_directions found_paths; + found_paths.left = field[y][x-1] != '/' && field[y][x-1] != '#' ? 1 : 0; + found_paths.right = field[y][x+1] != '/' && field[y][x+1] != '#' ? 1 : 0; + found_paths.up = field[y-1][x] != '/' && field[y-1][x] != '#' ? 1 : 0; + found_paths.down = field[y+1][x] != '/' && field[y+1][x] != '#' ? 1 : 0; + return found_paths; +} diff --git a/field.h b/field.h new file mode 100644 index 0000000..42992aa --- /dev/null +++ b/field.h @@ -0,0 +1,46 @@ +#ifndef FIELD_H_SENTRY +#define FIELD_H_SENTRY + +enum intersection_type { + one_path = '1', + two_paths = '2', + three_paths = '3', + direct_path +}; + +enum { + field_width = 29, + field_height = 29 +}; + +enum select_character { ghost_char, pac_char }; + +typedef char (*game_space)[field_width]; +game_space get_new_field(); + +struct free_directions { + int left; + int right; + int up; + int down; +}; + +void print_field(game_space field); + +void display_character(int y, int x, int symbol); + +struct ghost_type; +void display_ghosts_on_field(struct ghost_type *red_ghost, + struct ghost_type *pink_ghost, + struct ghost_type *blue_ghost, + struct ghost_type *orange_ghost); + +void clear_symbol(game_space field, int y, int x, + enum select_character character); + +enum intersection_type get_intersection(const game_space field, + struct ghost_type *ghost); + +struct free_directions find_free_directions(game_space field, int y, int x); + +#endif diff --git a/ghosts.c b/ghosts.c new file mode 100644 index 0000000..2559740 --- /dev/null +++ b/ghosts.c @@ -0,0 +1,140 @@ +#include "ghosts.h" +#include "field.h" + +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->mode = scatter; + 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->mode = scatter; + 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->mode = scatter; + 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->mode = scatter; + 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 { 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 }; + int index = *get_out_stage - 1; + if(*get_out_stage > final_stage) { + red_ghost->direction = red_moves[index]; + blue_ghost->direction = blue_moves[index]; + } + pink_ghost->direction = pink_moves[index]; + orange_ghost->direction = orange_moves[index]; + --*get_out_stage; +} + +static void change_position(struct ghost_type *ghost, + enum movement_direction direction) +{ + switch(direction) { + case left: + --ghost->position.x; + return; + case right: + ++ghost->position.x; + return; + case up: + --ghost->position.y; + return; + case down: + ++ghost->position.y; + return; + default: + return; + } +} + +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) +{ + clear_symbol(field, red_ghost->position.y, red_ghost->position.x, + ghost_char); + clear_symbol(field, pink_ghost->position.y, pink_ghost->position.x, + ghost_char); + clear_symbol(field, blue_ghost->position.y, blue_ghost->position.x, + ghost_char); + clear_symbol(field, orange_ghost->position.y, orange_ghost->position.x, + ghost_char); + 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; +} + +void redirect(game_space field, enum intersection_type paths, + struct ghost_type *ghost, + void (*pathfinder)(game_space field, enum intersection_type paths, + struct ghost_type *ghost)) +{ + if(paths == one_path) + pave_only_way(field, ghost); + else if(paths == two_paths || paths == three_paths) + pathfinder(field, paths, ghost); +} + + +void breadth_first_search(game_space field, enum intersection_type paths, + struct ghost_type *ghost) +{ + +} diff --git a/ghosts.h b/ghosts.h new file mode 100644 index 0000000..405a5e2 --- /dev/null +++ b/ghosts.h @@ -0,0 +1,65 @@ +#ifndef GHOSTS_H_SENTRY +#define GHOSTS_H_SENTRY + +#include "field.h" + +enum { + red_y = 14, + red_x = 15, + red_home_y = -1, + red_home_x = 25, + pink_y = red_y + 1, + pink_x = red_x - 2, + pink_home_y = red_home_y, + pink_home_x = 1, + blue_y = red_y, + blue_x = red_x-1, + blue_home_y = 29, + blue_home_x = 27, + orange_y = red_y + 1, + orange_x = red_x - 3, + orange_home_y = blue_home_y, + orange_home_x = 0, + field_size = 29 +}; + +enum ghost_color { red, pink, blue, orange }; +enum behavior_mode { chase, scatter, frightened }; +enum movement_direction { left, right, up, down, none }; + +struct coordinates { + int y; + int x; +}; + +struct ghost_type { + struct coordinates position; + struct coordinates home_position; + enum ghost_color color; + enum behavior_mode mode; + enum movement_direction direction; +}; + +void initialize_ghost(struct ghost_type *ghost, enum ghost_color color); + +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); + +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); + +void redirect(game_space field, enum intersection_type paths, + struct ghost_type *ghost, + void (*pathfinder)(game_space field, enum intersection_type paths, + struct ghost_type *ghost)); + +void breadth_first_search(game_space field, enum intersection_type paths, + struct ghost_type *ghost); + +#endif diff --git a/pac.c b/pac.c new file mode 100644 index 0000000..50256d8 --- /dev/null +++ b/pac.c @@ -0,0 +1,113 @@ +#include "pac.h" +#include "ncurses.h" + +void initialize_pac(struct pacman *pac) +{ + pac->lives = max_live; + pac->points_eaten = 0; + pac->position.y = pac_y; + pac->position.x = pac_x; + pac->direction = none; +} + +static enum movement_direction get_correct_path(struct pacman *pac, + struct free_directions + free_path, + enum movement_direction + direction) +{ + switch(direction) { + case left: + return free_path.left ? left : none; + case right: + return free_path.right ? right : none; + case up: + return free_path.up ? up : none; + case down: + return free_path.down ? down : none; + default: + return none; + } + +} + +void check_remaining_direction(game_space field, struct pacman *pac, + enum movement_direction *stored_direction) +{ + enum movement_direction temp_direction; + struct free_directions free_path = + find_free_directions(field, pac->position.y, pac->position.x); + enum movement_direction current_direction = + stored_direction ? *stored_direction : pac->direction; + temp_direction = get_correct_path(pac, free_path, current_direction); + if(temp_direction != none) + pac->direction = temp_direction; + else { + current_direction = pac->direction; + pac->direction = get_correct_path(pac, free_path, current_direction); + } + if(stored_direction) + *stored_direction = none; +} + +void change_pac_direction(game_space field, struct pacman *pac, int key, + enum movement_direction *stored_direction) +{ + enum state { no, yes } is_changed_direction; + is_changed_direction = no; + struct free_directions path = find_free_directions(field, pac->position.y, + pac->position.x); + switch(key) { + case KEY_LEFT: + if(path.left) { + pac->direction = left; + is_changed_direction = yes; + } else + *stored_direction = left; + break; + case KEY_RIGHT: + if(key == KEY_RIGHT && path.right) { + pac->direction = right; + is_changed_direction = yes; + } else + *stored_direction = right; + break; + case KEY_UP: + if(key == KEY_UP && path.up) { + pac->direction = up; + is_changed_direction = yes; + } else + *stored_direction = up; + break; + case KEY_DOWN: + if(key == KEY_DOWN && path.down) { + pac->direction = down; + is_changed_direction = yes; + } else + *stored_direction = down; + break; + } + if(is_changed_direction == no) + check_remaining_direction(field, pac, NULL); +} + +void make_pac_move(game_space field, struct pacman *pac) +{ + clear_symbol(field, pac->position.y, pac->position.x, pac_char); + switch(pac->direction) { + case left: + --pac->position.x; + return; + case right: + ++pac->position.x; + return; + case up: + --pac->position.y; + return; + case down: + ++pac->position.y; + return; + default: + return; + } +} diff --git a/pac.h b/pac.h new file mode 100644 index 0000000..1125694 --- /dev/null +++ b/pac.h @@ -0,0 +1,29 @@ +#ifndef PAC_H_SENTRY +#define PAC_H_SENTRY + +#include "ghosts.h" + +enum { + max_live = 3, + pac_y = 22, + pac_x = 14 +}; + +struct pacman { + char lives; + unsigned char points_eaten; + struct coordinates position; + enum movement_direction direction; +}; + +void initialize_pac(struct pacman *pac); + +void change_pac_direction(game_space field, struct pacman *pac, int key, + enum movement_direction *stored_direction); + +void check_remaining_direction(game_space field, struct pacman *pac, + enum movement_direction *stored_direction); + +void make_pac_move(game_space field, struct pacman *pac); + +#endif diff --git a/pacman.c b/pacman.c new file mode 100644 index 0000000..c3225b2 --- /dev/null +++ b/pacman.c @@ -0,0 +1,78 @@ +#include "field.h" +#include "ghosts.h" +#include "pac.h" +#include +#include +#include + +enum { + timeout_duration = 0, + sleep_duration = 190000, + key_escape = 27, + count_get_out_moves = 5 +}; + +static void 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; + intersection = get_intersection(field, red_ghost); + if(intersection != direct_path) + redirect(field, intersection, red_ghost, breadth_first_search); +} + +int main() +{ + game_space field = NULL; + struct ghost_type red_ghost, pink_ghost, blue_ghost, orange_ghost; + struct pacman pac; + int key, get_out_stage; + enum movement_direction stored_direction; + stored_direction = none; + get_out_stage = count_get_out_moves; + initscr(); + cbreak(); + noecho(); + curs_set(0); + keypad(stdscr, 1); + timeout(timeout_duration); + start_color(); + field = get_new_field(); + print_field(field); + initialize_ghost(&red_ghost, red); + initialize_ghost(&pink_ghost, pink); + initialize_ghost(&blue_ghost, blue); + initialize_ghost(&orange_ghost, orange); + initialize_pac(&pac); + display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, + &orange_ghost); + display_character(pac.position.y, pac.position.x, 'C'); + usleep(sleep_duration); + while((key = getch()) != key_escape) { + if(get_out_stage) + pull_out_ghosts(&get_out_stage, &red_ghost, &pink_ghost, + &blue_ghost, &orange_ghost); + else + pathfinder_stage(field, &red_ghost, &pink_ghost, &blue_ghost, + &orange_ghost); + if(key != ERR) + change_pac_direction(field, &pac, key, &stored_direction); + else { + if(stored_direction != none) + check_remaining_direction(field, &pac, &stored_direction); + else + check_remaining_direction(field, &pac, NULL); + } + make_ghost_moves(field, &red_ghost, &pink_ghost, &blue_ghost, + &orange_ghost); + make_pac_move(field, &pac); + display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, + &orange_ghost); + display_character(pac.position.y, pac.position.x, 'C'); + usleep(sleep_duration); + } + endwin(); + return 0; +} -- cgit v1.2.3