s21_tetris/code-samples/frogger/src/fsm_matrix.c
2024-04-17 17:02:16 +00:00

211 lines
No EOL
4.7 KiB
C

#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)
{
action act = NULL;
params_t prms;
prms.stats = stats;
prms.state = state;
prms.map = map;
prms.frog_pos = frog_pos;
if (*state != FILE_ERROR_STATE)
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 = FILE_ERROR_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;
}