snake/world.c
2020-04-23 17:39:46 +02:00

139 lines
4.1 KiB
C

#include "world.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <execinfo.h>
void print_backtrace() {
//https://linux.die.net/man/3/backtrace_symbols
int j, nptrs;
void *buffer[100];
char **strings;
nptrs = backtrace(buffer, 100);
printf("backtrace() returned %d addresses\n", nptrs);
/* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
would produce similar output to the following: */
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);
}
void abort_game(const char* message){
endwin();
print_backtrace();
puts(message);
exit(1);
}
void assert_message(int event,const char* message){
if (event == 0){
abort_game(message);
}
}
void stamp_cell(struct world* w,int character,enum color_stamp pen, int x,int y) {
assert_message(w != NULL,"stamp_cell:: world is NULL");
if (x < 0 || x >= w->width){
char msg[100];
sprintf(msg,"stamp_cell:: width %d is out of bounds (0,%d)",x,w->width);
abort_game(msg);
}
if (y < 0 || y >= w->height){
char msg[100];
sprintf(msg,"stamp_cell:: height %d is out of bounds (0,%d)",y,w->height);
abort_game(msg);
}
attron(pen);
mvaddch(y,x,character);
attroff(pen);
}
void set_cell(struct world* w,int character,int x,int y) {
stamp_cell(w,character,0,x,y);
}
int start_world(int (*world_event)(struct world* world,void* game),void* (*init_game)(struct world*),void (*destroy_game)(void*)){
srand(time(NULL));
int r = 1;
if (initscr() == NULL){
// TODO Which Error?
puts("Curses Error.");
return -1;
}
noecho(); // Nevypisuj vstup na obrazovku
cbreak(); // Zabudni starý vstup
nodelay(stdscr,TRUE); // Nečakaj na stlačenie
keypad(stdscr,TRUE); // Aktivuje šípky
curs_set(FALSE); // Neviditeľný kurzor
if (has_colors()){ // Zistenie či terminál podporuje farby
start_color();
// Pera na ciernom podklade
init_pair(BLACK_FRONT, COLOR_BLACK, COLOR_BLACK);
init_pair(WHITE_FRONT, COLOR_WHITE, COLOR_BLACK);
init_pair(RED_FRONT, COLOR_RED, COLOR_BLACK);
init_pair(GREEN_FRONT, COLOR_GREEN, COLOR_BLACK);
init_pair(BLUE_FRONT, COLOR_BLUE, COLOR_BLACK);
init_pair(CYAN_FRONT, COLOR_CYAN, COLOR_BLACK);
init_pair(MAGENTA_FRONT,COLOR_MAGENTA, COLOR_BLACK);
init_pair(YELLOW_FRONT, COLOR_YELLOW, COLOR_BLACK);
init_pair(BLACK_BACK, COLOR_BLACK, COLOR_BLACK);
init_pair(WHITE_BACK, COLOR_BLACK, COLOR_WHITE);
init_pair(RED_BACK, COLOR_BLACK, COLOR_RED);
init_pair(GREEN_BACK, COLOR_BLACK, COLOR_GREEN);
init_pair(BLUE_BACK, COLOR_BLACK, COLOR_BLUE);
init_pair(CYAN_BACK, COLOR_BLACK, COLOR_CYAN);
init_pair(MAGENTA_BACK, COLOR_BLACK, COLOR_MAGENTA);
init_pair(YELLOW_BACK, COLOR_BLACK, COLOR_YELLOW);
}
else {
puts("No colors!\n");
}
struct world world;
world.height = LINES;
world.width = COLS;
world.interval = 100;
world.key = ERR;
void* game = NULL;
if (init_game != NULL){
game = init_game(&world);
assert_message(game != NULL,"init_game should return non null pointer");
}
timeout(world.interval);
// Initial step
r = world_event(&world,game);
refresh();
while (!r) {
world.height = LINES;
world.width = COLS;
world.key = getch();
// Clear screen
mvaddch(0,0,' ');
int screenchars = LINES*COLS;
for (int j = 1; j < screenchars;j++ ){
addch(' ');
}
// Draw new world
r = world_event(&world,game);
refresh();
// set new timeout
timeout(world.interval);
}
if (destroy_game != NULL){
destroy_game(game);
}
endwin();
return r;
};