#include // bool #include // atoi() #include // EXIT_{FAILURE,SUCCESS} #include #include "../core/sok.h" #include "util.h" #include "draw.h" static char buf[(SOK_LEVEL_MAX_WIDTH + 1) * SOK_LEVEL_MAX_HEIGHT + 1]; #define SET_TILE(ctx, pos, c) \ buf[(pos).y * ((ctx)->level.size.x + 1) + (pos).x] = (c) static bool draw_on_size( const sok_ctx_t * const ctx, const sok_pos_t size, void * const data ) { UNUSED(ctx); UNUSED(data); memset(buf, ' ', sizeof(buf)); buf[(size.x + 1) * size.y + 1] = '\0'; for (size_t i = 0; i < size.y; i++) { buf[(i + 1) * (size.x + 1) - 1] = '\n'; } return true; } static bool draw_on_home( const sok_ctx_t * const ctx, const sok_pos_t pos, const bool has_goal, void * const data ) { UNUSED(data); SET_TILE(ctx, pos, has_goal ? '+' : '@'); return true; } static bool draw_on_wall( const sok_ctx_t * const ctx, const sok_pos_t pos, void * const data ) { UNUSED(data); SET_TILE(ctx, pos, '#'); return true; } static bool draw_on_goal( const sok_ctx_t * const ctx, const sok_pos_t pos, const bool has_player, const bool has_box, void * const data ) { UNUSED(data); const char c = has_player ? '+' : (has_box ? '*' : '.'); SET_TILE(ctx, pos, c); return true; } static bool draw_on_box( const sok_ctx_t * const ctx, const sok_pos_t pos, const bool has_goal, void * const data ) { UNUSED(data); SET_TILE(ctx, pos, has_goal ? '*' : '$'); return true; } static sok_ctx_walk_cbs_t DRAW_CBS = { .on_size = draw_on_size, .on_home = draw_on_home, .on_wall = draw_on_wall, .on_goal = draw_on_goal, .on_box = draw_on_box, }; void draw( const sok_ctx_t * const ctx, const size_t level_num, const level_t * const level ) { // fill print buffer if (!sok_ctx_walk(ctx, &DRAW_CBS, NULL)) { die("Couldn't print level %d", (int) level_num); } // print title, level, and console printf( "%s: %s (#%d)\n" // set name, level name, and level number "%s\n" // level "%d%s> ", // console level->pack, level->name, (int) level_num, buf, (int) ctx->num_moves, sok_ctx_is_done(ctx) ? " (won!)" : "" ); }