diff options
author | scratko <m@scratko.xyz> | 2024-04-02 17:43:35 +0300 |
---|---|---|
committer | scratko <m@scratko.xyz> | 2024-04-02 17:43:35 +0300 |
commit | bdee2852c13f6b02ec5207ded584839a3118233e (patch) | |
tree | 39f1c14be91fb848ce0f94a64532e48a7667e5de | |
download | pacman-bdee2852c13f6b02ec5207ded584839a3118233e.tar.gz pacman-bdee2852c13f6b02ec5207ded584839a3118233e.tar.bz2 pacman-bdee2852c13f6b02ec5207ded584839a3118233e.zip |
Initial commit
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | field.c | 163 | ||||
-rw-r--r-- | field.h | 46 | ||||
-rw-r--r-- | ghosts.c | 140 | ||||
-rw-r--r-- | ghosts.h | 65 | ||||
-rw-r--r-- | pac.c | 113 | ||||
-rw-r--r-- | pac.h | 29 | ||||
-rw-r--r-- | pacman.c | 78 |
8 files changed, 653 insertions, 0 deletions
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 @@ -0,0 +1,163 @@ +#include "field.h" +#include "ghosts.h" +#include <ncurses.h> +#include <stdlib.h> + +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; +} @@ -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 @@ -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; + } +} @@ -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 <ncurses.h> +#include <stdlib.h> +#include <unistd.h> + +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; +} |