211 lines
No EOL
4.7 KiB
C
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;
|
|
} |