Init commit
This commit is contained in:
commit
83e6c9e1f0
41 changed files with 1455 additions and 0 deletions
0
code-samples/.gitkeep
Normal file
0
code-samples/.gitkeep
Normal file
11
code-samples/frogger/README.md
Normal file
11
code-samples/frogger/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Frogger
|
||||
## Controls
|
||||
### Movement
|
||||
Arrow keys (up, right, down, left)
|
||||
### Exit
|
||||
Esc key
|
||||
## Installation
|
||||
```git clone XXX && cd frogger```
|
||||
## Make
|
||||
```make frogger``` makes switch-case realisation of fsm which you can observe in file src/fsm.c \
|
||||
```make frogger_fsmtable``` makes fsm realisation based on matrix of pointers on state-control functions which you can observe in file src/fsm_matrix.c
|
||||
54
code-samples/frogger/inc/defines.h
Normal file
54
code-samples/frogger/inc/defines.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
#define WIN_INIT(time) {\
|
||||
initscr();\
|
||||
noecho();\
|
||||
curs_set(0);\
|
||||
keypad(stdscr, TRUE);\
|
||||
timeout(time);\
|
||||
}
|
||||
|
||||
#define GET_USER_INPUT getch()
|
||||
|
||||
#define PRINT_FROG(x, y) mvprintw(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), "@")
|
||||
#define MVPRINTW(y, x, ...) mvprintw(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), __VA_ARGS__)
|
||||
#define MVADDCH(y, x, c) mvaddch(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), c)
|
||||
#define CLEAR_BACKPOS(y, x) mvaddch(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), ' ')
|
||||
|
||||
#define YOU_WON "tests/game_progress/you_won.txt"
|
||||
#define YOU_LOSE "tests/game_progress/you_lose.txt"
|
||||
#define LEVEL_DIR "tests/levels/level_"
|
||||
#define INTRO_MESSAGE "Press ENTER to start!"
|
||||
#define INTRO_MESSAGE_LEN 21
|
||||
#define LEVEL_CNT 5
|
||||
#define LEVELNAME_MAX 25
|
||||
|
||||
#define MAX_WIN_COUNT 10
|
||||
|
||||
#define ROWS_MAP 21
|
||||
#define COLS_MAP 90
|
||||
|
||||
#define BOARDS_BEGIN 2
|
||||
|
||||
#define FROGSTART_X (BOARD_M / 2)
|
||||
#define FROGSTART_Y (BOARD_N)
|
||||
#define INITIAL_TIMEOUT 150
|
||||
|
||||
#define BOARD_N (ROWS_MAP + MAP_PADDING * 2)
|
||||
#define BOARD_M 30
|
||||
#define HUD_WIDTH 12
|
||||
#define MAP_PADDING 3
|
||||
|
||||
#define BANNER_N 10
|
||||
#define BANNER_M 100
|
||||
|
||||
#define SUCCESS 0
|
||||
#define ERROR 1
|
||||
|
||||
#define NO_INPUT -1
|
||||
|
||||
#define ESCAPE 27
|
||||
#define ENTER_KEY 10
|
||||
|
||||
#endif
|
||||
20
code-samples/frogger/inc/frog_backend.h
Normal file
20
code-samples/frogger/inc/frog_backend.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef FROGGER_BACKEND_H
|
||||
#define FROGGER_BACKEND_H
|
||||
|
||||
#include <ncurses.h>
|
||||
#include "defines.h"
|
||||
#include "objects.h"
|
||||
#include "string.h"
|
||||
|
||||
int lvlproc(board_t *map, game_stats_t *stats);
|
||||
void add_proggress(board_t *map);
|
||||
void stats_init(game_stats_t *stats);
|
||||
void frogpos_init(player_pos *frog);
|
||||
void fill_finish(char *finish_line);
|
||||
void shift_map(board_t *map);
|
||||
|
||||
bool check_collide(player_pos *frog, board_t *map);
|
||||
bool check_finish_state(player_pos *frog, board_t *map);
|
||||
bool check_level_compl(board_t *map);
|
||||
|
||||
#endif
|
||||
17
code-samples/frogger/inc/frog_frontend.h
Normal file
17
code-samples/frogger/inc/frog_frontend.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef FROGGER_FRONTEND_H
|
||||
#define FROGGER_FRONTEND_H
|
||||
|
||||
#include <string.h>
|
||||
#include "defines.h"
|
||||
#include "objects.h"
|
||||
|
||||
void print_overlay(void);
|
||||
void print_rectangle(int top_y, int bottom_y, int left_x, int right_x);
|
||||
void print_stats(game_stats_t *stats);
|
||||
void print_board(board_t *game, player_pos *frog);
|
||||
void print_cars(board_t *game);
|
||||
void print_finished(board_t *game);
|
||||
void print_banner(game_stats_t *stats);
|
||||
int read_banner(game_stats_t *stats, banner_t *banner);
|
||||
|
||||
#endif
|
||||
11
code-samples/frogger/inc/frogger.h
Normal file
11
code-samples/frogger/inc/frogger.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef FROGGER_H
|
||||
#define FROGGER_H
|
||||
|
||||
#include <locale.h>
|
||||
#include "fsm.h"
|
||||
#include "frog_backend.h"
|
||||
#include "frog_frontend.h"
|
||||
|
||||
void game_loop();
|
||||
|
||||
#endif
|
||||
35
code-samples/frogger/inc/fsm.h
Normal file
35
code-samples/frogger/inc/fsm.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef FSM_H
|
||||
#define FSM_H
|
||||
|
||||
#include "defines.h"
|
||||
#include "objects.h"
|
||||
#include "frog_backend.h"
|
||||
#include "frog_frontend.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
START = 0,
|
||||
SPAWN,
|
||||
MOVING,
|
||||
SHIFTING,
|
||||
REACH,
|
||||
COLLIDE,
|
||||
GAMEOVER,
|
||||
EXIT_STATE
|
||||
} frog_state;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MOVE_UP = 0,
|
||||
MOVE_DOWN,
|
||||
MOVE_RIGHT,
|
||||
MOVE_LEFT,
|
||||
ESCAPE_BTN,
|
||||
ENTER_BTN,
|
||||
NOSIG
|
||||
} signals;
|
||||
|
||||
signals get_signal(int user_input);
|
||||
void sigact(signals sig, frog_state *state, game_stats_t *stats, board_t *map, player_pos *frog_pos);
|
||||
|
||||
#endif
|
||||
33
code-samples/frogger/inc/objects.h
Normal file
33
code-samples/frogger/inc/objects.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef OBJECTS_H
|
||||
#define OBJECTS_H
|
||||
|
||||
#include <ncurses.h>
|
||||
#include "defines.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} player_pos;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char finish[BOARD_M + 2];
|
||||
char ways[ROWS_MAP + 2][COLS_MAP + 2];
|
||||
} board_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int score;
|
||||
int level;
|
||||
int speed;
|
||||
int lives;
|
||||
int won;
|
||||
} game_stats_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char matrix[BANNER_N + 1][BANNER_M + 1];
|
||||
} banner_t;
|
||||
|
||||
#endif
|
||||
16
code-samples/frogger/makefile
Normal file
16
code-samples/frogger/makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
CC := gcc
|
||||
CFLAGS := -I inc -std=c99 -Wall -Werror -Wpedantic
|
||||
OBJS_FSMSWITCHCASE := out/frogger.o out/fsm.o out/backend.o out/frontend.o
|
||||
OBJS_FSMTABLE := out/frogger.o out/fsm_matrix.o out/backend.o out/frontend.o
|
||||
|
||||
frogger: $(OBJS_FSMSWITCHCASE)
|
||||
$(CC) $(CFLAGS) $^ -o $@ -lncurses
|
||||
|
||||
frogger_fsmtable: $(OBJS_FSMTABLE)
|
||||
$(CC) $(CFLAGS) $^ -o $@ -lncurses
|
||||
|
||||
out/%.o: src/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
$(RM) out/*.o frogger frogger_fsmtable
|
||||
0
code-samples/frogger/out/.gitkeep
Normal file
0
code-samples/frogger/out/.gitkeep
Normal file
102
code-samples/frogger/src/backend.c
Normal file
102
code-samples/frogger/src/backend.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#include "frog_backend.h"
|
||||
|
||||
int lvlproc(board_t *map, game_stats_t *stats)
|
||||
{
|
||||
timeout(INITIAL_TIMEOUT - stats->speed * 15);
|
||||
|
||||
char levelname[LEVELNAME_MAX + 1] = { 0 };
|
||||
|
||||
sprintf(levelname, LEVEL_DIR"%d.txt", stats->level);
|
||||
|
||||
FILE *level = fopen(levelname, "r");
|
||||
|
||||
int rc = SUCCESS;
|
||||
|
||||
if (level)
|
||||
{
|
||||
for (int i = 0; i < ROWS_MAP && !rc; i++)
|
||||
{
|
||||
if (fgets(map->ways[i], COLS_MAP + 2, level) == NULL)
|
||||
rc = ERROR;
|
||||
else
|
||||
map->ways[i][strcspn(map->ways[i], "\n")] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
fclose(level);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void add_proggress(board_t *map)
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
for (; map->finish[position] == '0'; position++) ;
|
||||
|
||||
for (int progress_cnt = BOARD_M / 5; progress_cnt > 0; progress_cnt--)
|
||||
map->finish[position++] = '0';
|
||||
}
|
||||
|
||||
bool check_finish_state(player_pos *frog, board_t *map)
|
||||
{
|
||||
bool rc = FALSE;
|
||||
|
||||
if (frog->y == 1)
|
||||
rc = TRUE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool check_level_compl(board_t *map)
|
||||
{
|
||||
bool rc = TRUE;
|
||||
for (int i = 0; i < BOARD_M && rc; i++)
|
||||
if (map->finish[i] != '0')
|
||||
rc = FALSE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool check_collide(player_pos *frog, board_t *map)
|
||||
{
|
||||
bool rc = FALSE;
|
||||
|
||||
if (frog->y > MAP_PADDING && frog->y < ROWS_MAP + MAP_PADDING + 1 && \
|
||||
map->ways[frog->y - MAP_PADDING - 1][frog->x - 1] == ']')
|
||||
rc = TRUE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void frogpos_init(player_pos *frog)
|
||||
{
|
||||
frog->x = FROGSTART_X;
|
||||
frog->y = FROGSTART_Y;
|
||||
}
|
||||
|
||||
void fill_finish(char *finish_line)
|
||||
{
|
||||
for (int i = 0; i < BOARD_M; i++)
|
||||
finish_line[i] = ' ';
|
||||
|
||||
finish_line[BOARD_M] = '\0';
|
||||
}
|
||||
|
||||
void stats_init(game_stats_t *stats)
|
||||
{
|
||||
stats->level = 1;
|
||||
stats->score = 0;
|
||||
stats->speed = 1;
|
||||
stats->lives = 9;
|
||||
stats->won = FALSE;
|
||||
}
|
||||
|
||||
void shift_map(board_t *map)
|
||||
{
|
||||
for (int i = 1; i < ROWS_MAP; i += 2)
|
||||
{
|
||||
memmove(&map->ways[i][1], &map->ways[i][0], COLS_MAP * sizeof(char));
|
||||
map->ways[i][0] = map->ways[i][COLS_MAP];
|
||||
}
|
||||
}
|
||||
36
code-samples/frogger/src/frogger.c
Normal file
36
code-samples/frogger/src/frogger.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "frogger.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
WIN_INIT(50);
|
||||
setlocale(LC_ALL, "");
|
||||
print_overlay();
|
||||
game_loop();
|
||||
endwin();
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void game_loop()
|
||||
{
|
||||
board_t map;
|
||||
game_stats_t stats;
|
||||
player_pos frog;
|
||||
|
||||
bool break_flag = TRUE;
|
||||
int signal = 0;
|
||||
frog_state state = START;
|
||||
|
||||
stats_init(&stats);
|
||||
|
||||
while (break_flag)
|
||||
{
|
||||
if (state == GAMEOVER || state == EXIT_STATE)
|
||||
break_flag = FALSE;
|
||||
|
||||
sigact(get_signal(signal), &state, &stats, &map, &frog);
|
||||
|
||||
if (state == MOVING || state == START)
|
||||
signal = GET_USER_INPUT;
|
||||
}
|
||||
}
|
||||
137
code-samples/frogger/src/frontend.c
Normal file
137
code-samples/frogger/src/frontend.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#include "frog_frontend.h"
|
||||
|
||||
void print_overlay(void)
|
||||
{
|
||||
print_rectangle(0, BOARD_N + 1, 0, BOARD_M + 1);
|
||||
print_rectangle(0, BOARD_N + 1, BOARD_M + 2, BOARD_M + HUD_WIDTH + 3);
|
||||
|
||||
print_rectangle(1, 3, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
print_rectangle(4, 6, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
print_rectangle(7, 9, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
print_rectangle(10, 12, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
|
||||
MVPRINTW(2, BOARD_M + 5, "LEVEL");
|
||||
MVPRINTW(5, BOARD_M + 5, "SCORE");
|
||||
MVPRINTW(8, BOARD_M + 5, "SPEED");
|
||||
MVPRINTW(11, BOARD_M + 5, "LIVES");
|
||||
|
||||
MVPRINTW(BOARD_N / 2, (BOARD_M - INTRO_MESSAGE_LEN) / 2 + 1, INTRO_MESSAGE);
|
||||
}
|
||||
|
||||
void print_rectangle(int top_y, int bottom_y, int left_x, int right_x)
|
||||
{
|
||||
MVADDCH(top_y, left_x, ACS_ULCORNER);
|
||||
|
||||
int i = left_x + 1;
|
||||
|
||||
for (;i < right_x; i++)
|
||||
MVADDCH(top_y, i, ACS_HLINE);
|
||||
MVADDCH(top_y, i, ACS_URCORNER);
|
||||
|
||||
for (int i = top_y + 1; i < bottom_y; i++)
|
||||
{
|
||||
MVADDCH(i, left_x, ACS_VLINE);
|
||||
MVADDCH(i, right_x, ACS_VLINE);
|
||||
}
|
||||
|
||||
MVADDCH(bottom_y, left_x, ACS_LLCORNER);
|
||||
i = left_x + 1;
|
||||
for (;i < right_x; i++)
|
||||
MVADDCH(bottom_y, i, ACS_HLINE);
|
||||
MVADDCH(bottom_y, i, ACS_LRCORNER);
|
||||
}
|
||||
|
||||
void print_stats(game_stats_t *stats)
|
||||
{
|
||||
MVPRINTW(2, BOARD_M + 12, "%d", stats->level);
|
||||
MVPRINTW(5, BOARD_M + 12, "%d", stats->score);
|
||||
MVPRINTW(8, BOARD_M + 12, "%d", stats->speed);
|
||||
MVPRINTW(11, BOARD_M + 12, "%d", stats->lives);
|
||||
}
|
||||
|
||||
void print_board(board_t *game, player_pos *frog)
|
||||
{
|
||||
print_cars(game);
|
||||
PRINT_FROG(frog->x, frog->y);
|
||||
}
|
||||
|
||||
void print_cars(board_t *game)
|
||||
{
|
||||
for(int i = MAP_PADDING + 1; i < BOARD_N - MAP_PADDING + 1; i++)
|
||||
{
|
||||
if (i % 2 == (MAP_PADDING + 1) % 2)
|
||||
{
|
||||
for (int j = 1; j < BOARD_M + 1; j++)
|
||||
MVADDCH(i, j, ACS_BLOCK);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 1; j < BOARD_M + 1; j++)
|
||||
{
|
||||
if (game->ways[i - MAP_PADDING - 1][j - 1] == '0')
|
||||
MVADDCH(i, j, ' ');
|
||||
else
|
||||
MVADDCH(i, j, ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_finished(board_t *game)
|
||||
{
|
||||
for (int i = 0; i < BOARD_M; i++)
|
||||
{
|
||||
if (game->finish[i] == '0')
|
||||
MVADDCH(1, i + 1, ACS_BLOCK);
|
||||
else
|
||||
MVADDCH(1, i + 1, ' ');
|
||||
}
|
||||
}
|
||||
void print_banner(game_stats_t *stats)
|
||||
{
|
||||
banner_t banner;
|
||||
|
||||
memset(banner.matrix, 0, (BANNER_N + 1) * (BANNER_M + 1));
|
||||
|
||||
clear();
|
||||
|
||||
if (!(read_banner(stats, &banner)))
|
||||
{
|
||||
for (int i = 0; i < BANNER_N; i++)
|
||||
for (int j = 0; j < BANNER_M; j++)
|
||||
if (banner.matrix[i][j] == '#')
|
||||
MVADDCH(i, j, ACS_BLOCK);
|
||||
else
|
||||
MVADDCH(i, j, ' ');
|
||||
refresh();
|
||||
napms(2000);
|
||||
}
|
||||
}
|
||||
|
||||
int read_banner(game_stats_t *stats, banner_t *banner)
|
||||
{
|
||||
int rc = SUCCESS;
|
||||
FILE *file = NULL;
|
||||
|
||||
if (stats->lives)
|
||||
file = fopen(YOU_WON, "r");
|
||||
else
|
||||
file = fopen(YOU_LOSE, "r");
|
||||
|
||||
if (file)
|
||||
{
|
||||
for (int i = 0; i < BANNER_N - 1 && !rc; i++)
|
||||
{
|
||||
if (fgets(banner->matrix[i], BANNER_M + 2, file) == NULL)
|
||||
rc = ERROR;
|
||||
else
|
||||
banner->matrix[i][strcspn(banner->matrix[i], "\n")] = '\0';
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
rc = ERROR;
|
||||
|
||||
return rc;
|
||||
}
|
||||
186
code-samples/frogger/src/fsm.c
Normal file
186
code-samples/frogger/src/fsm.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
#include "fsm.h"
|
||||
|
||||
// This is a finite state machine realisation based on switch-case statement.
|
||||
/*
|
||||
Function sigact() describes state switching logic.
|
||||
States are checked in order specified in function sigact().
|
||||
It enters a state-case which it corresponds to, where begins another switch-case statement.
|
||||
Inner switch-case statement is looking for a signal given by get_signal().
|
||||
After finding it makes some action and switches state to the next one.
|
||||
|
||||
Pros:
|
||||
1) Less memory usage.
|
||||
Cons:
|
||||
1) A lot of codelines.
|
||||
*/
|
||||
|
||||
signals get_signal(int user_input)
|
||||
{
|
||||
signals rc = NOSIG;
|
||||
|
||||
if (user_input == KEY_UP)
|
||||
rc = MOVE_UP;
|
||||
else if (user_input == KEY_DOWN)
|
||||
rc = MOVE_DOWN;
|
||||
else if (user_input == KEY_LEFT)
|
||||
rc = MOVE_LEFT;
|
||||
else if (user_input == KEY_RIGHT)
|
||||
rc = MOVE_RIGHT;
|
||||
else if (user_input == ESCAPE)
|
||||
rc = ESCAPE_BTN;
|
||||
else if (user_input == ENTER_KEY)
|
||||
rc = ENTER_BTN;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void moveup(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->y != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->y -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void movedown(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->y != BOARD_N)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->y += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void moveright(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->x != BOARD_M)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->x++;
|
||||
}
|
||||
}
|
||||
|
||||
void moveleft(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->x != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->x--;
|
||||
}
|
||||
}
|
||||
|
||||
void sigact(signals sig, frog_state *state, game_stats_t *stats, board_t *map, player_pos *frog_pos)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case START:
|
||||
switch (sig)
|
||||
{
|
||||
case ENTER_BTN:
|
||||
*state = SPAWN;
|
||||
break;
|
||||
case ESCAPE_BTN:
|
||||
*state = EXIT_STATE;
|
||||
break;
|
||||
default:
|
||||
*state = START;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case SPAWN:
|
||||
if (stats->level > LEVEL_CNT)
|
||||
*state = GAMEOVER;
|
||||
else
|
||||
if (!lvlproc(map, stats))
|
||||
{
|
||||
fill_finish(map->finish);
|
||||
print_finished(map);
|
||||
frogpos_init(frog_pos);
|
||||
*state = MOVING;
|
||||
}
|
||||
else
|
||||
*state = EXIT_STATE;
|
||||
|
||||
break;
|
||||
case MOVING:
|
||||
switch (sig)
|
||||
{
|
||||
case MOVE_UP:
|
||||
moveup(frog_pos);
|
||||
break;
|
||||
case MOVE_DOWN:
|
||||
movedown(frog_pos);
|
||||
break;
|
||||
case MOVE_RIGHT:
|
||||
moveright(frog_pos);
|
||||
break;
|
||||
case MOVE_LEFT:
|
||||
moveleft(frog_pos);
|
||||
break;
|
||||
case ESCAPE_BTN:
|
||||
*state = EXIT_STATE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (*state != EXIT_STATE)
|
||||
{
|
||||
if (check_collide(frog_pos, map))
|
||||
*state = COLLIDE;
|
||||
else if (check_finish_state(frog_pos, map))
|
||||
*state = REACH;
|
||||
else
|
||||
*state = SHIFTING;
|
||||
}
|
||||
|
||||
break;
|
||||
case SHIFTING:
|
||||
shift_map(map);
|
||||
|
||||
if (check_collide(frog_pos, map))
|
||||
*state = COLLIDE;
|
||||
else
|
||||
{
|
||||
*state = MOVING;
|
||||
print_board(map, frog_pos);
|
||||
print_stats(stats);
|
||||
}
|
||||
|
||||
break;
|
||||
case REACH:
|
||||
stats->score += 1;
|
||||
add_proggress(map);
|
||||
if (check_level_compl(map))
|
||||
{
|
||||
stats->level++;
|
||||
stats->speed++;
|
||||
*state = SPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
frogpos_init(frog_pos);
|
||||
print_finished(map);
|
||||
*state = MOVING;
|
||||
}
|
||||
|
||||
break;
|
||||
case COLLIDE:
|
||||
if (stats->lives)
|
||||
{
|
||||
stats->lives--;
|
||||
frogpos_init(frog_pos);
|
||||
*state = MOVING;
|
||||
}
|
||||
else
|
||||
*state = GAMEOVER;
|
||||
break;
|
||||
case GAMEOVER:
|
||||
print_banner(stats);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
209
code-samples/frogger/src/fsm_matrix.c
Normal file
209
code-samples/frogger/src/fsm_matrix.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
#include "fsm.h"
|
||||
|
||||
// This is a finite state machine realisation based on matrix of "actions".
|
||||
/*
|
||||
Function sigact() takes an action function from fsm_table.
|
||||
Game state defines an index of line in matrix (where to get).
|
||||
User signal defines an index of column in matrix (what to get).
|
||||
|
||||
Pros:
|
||||
1) By instantly taking needed action, speed of processing is higher than switch-case realisation.
|
||||
2) Code is easy to read.
|
||||
3) Flexible (easy to add new state)
|
||||
Cons:
|
||||
1) More memory usage.
|
||||
*/
|
||||
|
||||
typedef struct game_params
|
||||
{
|
||||
game_stats_t *stats;
|
||||
frog_state *state;
|
||||
board_t *map;
|
||||
player_pos *frog_pos;
|
||||
bool *break_flag;
|
||||
} params_t;
|
||||
|
||||
typedef void (*action)(params_t *prms);
|
||||
|
||||
void spawn(params_t *prms);
|
||||
void moveup(params_t *prms);
|
||||
void movedown(params_t *prms);
|
||||
void moveright(params_t *prms);
|
||||
void moveleft(params_t *prms);
|
||||
void shifting(params_t *prms);
|
||||
void reach(params_t *prms);
|
||||
void collide(params_t *prms);
|
||||
void gameover(params_t *prms);
|
||||
void exitstate(params_t *prms);
|
||||
void check(params_t *prms);
|
||||
|
||||
action fsm_table[8][7] = {
|
||||
{NULL, NULL, NULL, NULL, exitstate, spawn, NULL},
|
||||
{spawn, spawn, spawn, spawn, spawn, spawn, spawn},
|
||||
{moveup, movedown, moveright, moveleft, exitstate, check, check},
|
||||
{shifting, shifting, shifting, shifting, shifting, shifting, shifting},
|
||||
{reach, reach, reach, reach, reach, reach, reach},
|
||||
{collide, collide, collide, collide, collide, collide, collide},
|
||||
{gameover, gameover, gameover, gameover, gameover, gameover, gameover},
|
||||
{exitstate, exitstate, exitstate, exitstate, exitstate, exitstate, exitstate}
|
||||
};
|
||||
|
||||
void sigact(signals sig, frog_state *state, game_stats_t *stats, board_t *map, player_pos *frog_pos)
|
||||
{
|
||||
params_t prms;
|
||||
prms.stats = stats;
|
||||
prms.state = state;
|
||||
prms.map = map;
|
||||
prms.frog_pos = frog_pos;
|
||||
|
||||
action act = fsm_table[*state][sig];
|
||||
|
||||
if (act)
|
||||
act(&prms);
|
||||
}
|
||||
|
||||
signals get_signal(int user_input)
|
||||
{
|
||||
signals rc = NOSIG;
|
||||
|
||||
if (user_input == KEY_UP)
|
||||
rc = MOVE_UP;
|
||||
else if (user_input == KEY_DOWN)
|
||||
rc = MOVE_DOWN;
|
||||
else if (user_input == KEY_LEFT)
|
||||
rc = MOVE_LEFT;
|
||||
else if (user_input == KEY_RIGHT)
|
||||
rc = MOVE_RIGHT;
|
||||
else if (user_input == ESCAPE)
|
||||
rc = ESCAPE_BTN;
|
||||
else if (user_input == ENTER_KEY)
|
||||
rc = ENTER_BTN;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void shifting(params_t *prms)
|
||||
{
|
||||
shift_map(prms->map);
|
||||
|
||||
if (check_collide(prms->frog_pos, prms->map))
|
||||
*prms->state = COLLIDE;
|
||||
else
|
||||
{
|
||||
*prms->state = MOVING;
|
||||
print_board(prms->map, prms->frog_pos);
|
||||
print_stats(prms->stats);
|
||||
}
|
||||
}
|
||||
|
||||
void check(params_t *prms)
|
||||
{
|
||||
if (check_collide(prms->frog_pos, prms->map))
|
||||
*prms->state = COLLIDE;
|
||||
else if (check_finish_state(prms->frog_pos, prms->map))
|
||||
*prms->state = REACH;
|
||||
else
|
||||
*prms->state = SHIFTING;
|
||||
}
|
||||
|
||||
void spawn(params_t *prms)
|
||||
{
|
||||
if (prms->stats->level > LEVEL_CNT)
|
||||
*prms->state = GAMEOVER;
|
||||
else
|
||||
{
|
||||
if (!lvlproc(prms->map, prms->stats))
|
||||
{
|
||||
fill_finish(prms->map->finish);
|
||||
print_finished(prms->map);
|
||||
frogpos_init(prms->frog_pos);
|
||||
*prms->state = MOVING;
|
||||
}
|
||||
else
|
||||
*prms->state = EXIT_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
void moveup(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->y != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->y -= 2;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void movedown(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->y != BOARD_N)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->y += 2;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void moveright(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->x != BOARD_M)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->x++;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void moveleft(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->x != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->x--;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void reach(params_t *prms)
|
||||
{
|
||||
prms->stats->score += 1;
|
||||
add_proggress(prms->map);
|
||||
if (check_level_compl(prms->map))
|
||||
{
|
||||
prms->stats->level++;
|
||||
prms->stats->speed++;
|
||||
*prms->state = SPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
frogpos_init(prms->frog_pos);
|
||||
print_finished(prms->map);
|
||||
*prms->state = MOVING;
|
||||
}
|
||||
}
|
||||
|
||||
void collide(params_t *prms)
|
||||
{
|
||||
if (prms->stats->lives)
|
||||
{
|
||||
prms->stats->lives--;
|
||||
frogpos_init(prms->frog_pos);
|
||||
*prms->state = MOVING;
|
||||
}
|
||||
else
|
||||
*prms->state = GAMEOVER;
|
||||
}
|
||||
|
||||
void gameover(params_t *prms)
|
||||
{
|
||||
print_banner(prms->stats);
|
||||
}
|
||||
|
||||
void exitstate(params_t *prms)
|
||||
{
|
||||
*prms->state = EXIT_STATE;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue