Newer
Older
//There are lots of hints on https://infoc.eet.bme.hu/
/**
* @param set set the unicode encoding
* @return is the program in unicode mode
*/
int isUnicodeEncoding(int set){
static int bl = 0;
if(set){
bl = 1;
}
return bl;
}
* @param c first byte of the unicode char
* @return How long is this utf-8 character (in bytes)
return 1; //int windows-xyzw every char has 1 len;
}
if(!(c & 0x80)){
return 1;
}
while(c & 0x80){
i++;
c = c << 1;
if(i > 8){
return EOF;
}
}
return i;
}
void printChar(unichar c){
int len;
len = checkUnicharLen(c.bytes.c[0]);
for(int i = 0; i < len; i++){
printf("%c", c.bytes.c[i]);
}
}
/**
* read file into the map matrix
* @param file the map file "object"
* @param matrix the pointer of the matrix to return
* @return was the read successful
*/
int c, len, maxLineLen = 0, lineCount = 1, lineLen = 0; //lineCount = (3,1) ??? why?... i was just bored
struct Vec2i pos;
pos.x = 0;
pos.y = 0;
linkedString *linkedStr = 0, *current = 0, *next;
//linkedStr = malloc(sizeof(linkedString));
#ifdef DEBUG
memset(next, 0, sizeof(linkedString)); //fill it with zeros. only in debug mode
#endif
next->next = 0;
while (c == '\r')
{
c = fgetc(file);
if(c == -1){
break;
}
}
next->value.bytes.c[0] = c;
len = checkUnicharLen(c);
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
for (int i = 1; i < len; i++){
c = fgetc(file);
if(c == -1){
return EOF;
}
next->value.bytes.c[i] = c;
}
}
else if(c == '\n'){ //checking newline (unichar can't be a newline char (\n))
lineCount++;
if(lineLen > maxLineLen){
maxLineLen = lineLen;
}
lineLen = -1;
}
lineLen++;
//next.value = chars;
if(current != 0){
current->next = next;
}
else
{
linkedStr = next;
//current = next;
}
current = next;
}
maxLineLen = maxLineLen / 2 + maxLineLen % 2;
matrix->height = lineCount;
matrix->width = maxLineLen;
matrix->matrix = calloc(maxLineLen, sizeof(chunk*));
if(matrix->matrix == NULL){
printf("failed to allocate memory for the matrix");
return EOF-1;
}
for (int i = 0; i < maxLineLen; i++){
matrix->matrix[i] = calloc(lineCount, sizeof(chunk));
if(matrix->matrix[i] == NULL){
printf("failed to allocate memory for the matrix");
return EOF-1;
}
for(int n = 0; n < lineCount; n++){
}
}
}
current = linkedStr;
while(current != 0){
//tmp = current;
//current = current->next;
//free(tmp);
if(current->value.bytes.c[0] == '\n'){
pos.x = 0;
pos.y++;
//break;
}
else{
for(int charPos = 0; charPos < 4; charPos++){
matrix->matrix[pos.x/2][pos.y].data.chars[pos.x%2].bytes.c[charPos] = current->value.bytes.c[charPos];
}
pos.x++;
}
next = current;
current = current->next;
free(next);
}
return 0;
}
void rmMatrix(Matrix *map){
for(int i = 0; i < map->width; i++){
free(map->matrix[i]);
}
free(map->matrix);
}
//Use what chunk,
//witch screen coordinates?
//just the screen data
/**
* prints a chunk into the screen, if the input position is relative
* @param ch chunk to print
* @param pos position relative to the screen
* @param scrDat standard screen infos
*/
//pos.x -= scrDat->pos.x;
//pos.y -= scrDat->pos.y;
if(pos.x < 0 || pos.y < 0 || pos.x >= scrDat->size.x || pos.y >= scrDat->size.y){
if(ch.isFood){
chunk ch = scrDat->foodTexture.text[ch.data.FRand%scrDat->foodTexture.len];
}
#ifdef DEBUG
printf("\e[0;0H\n"); //to update terminal after EVERY print but drasticlally slowing it down
#endif
* @param ch chunk to print
* @param pos absolute position
* @param scrDat standard screen data
* @param width map width
* @param height map height
void print(chunk ch, Pos pos, screenData *scrDat, int width, int height){
pos.x = pos.x - scrDat->pos.x;
if(pos.x < 0){
if(scrDat->isXRepeat){
pos.x += width;
}
else{
return;
}
}
pos.y = pos.y - scrDat->pos.y;
if(pos.y < 0){
if(scrDat->isYRepeat){
pos.y += height;
}
else{
return;
}
}
printChunk(ch, pos, scrDat);
/** prints snake chain onto the map, listening to directions
*/
//TODO
void printSnakeChunk(snakeChain *snake, Direction prevDir, screenData *scrDat){
/**
* update the windows size if resized
* @param map map for width and height
* @param scrDat standard screen data. changes will apply
* @return did the screen size changed
*/
int updateScreenSize(Matrix *map, screenData *scrDat){
struct Vec2i size = getWindowSize();
if(size.x == scrDat->size.x && size.y == scrDat->size.y){
return 0; //no change happened
}
scrDat->size.x = size.x;
scrDat->size.y = size.y;
if(scrDat->repeatMap){
scrDat->isXRepeat = size.x < map->width;
scrDat->isYRepeat = size.y < map->height;
}
return 1;
}
/**
* Update the screen if it changed size of snek is near to the screen border
* The game doesn't update every character in every round to be more efficient
*
* @param map map
* @param scrDat screenData
* @param head the head of the snake
* @param d snek's current moving direction
*/
void updateScreen(Matrix *map, screenData *scrDat, snakeChain *head, Direction d){
scrDat->pos.x = mod(head->pos.x - scrDat->size.x / 2 ,map->width, scrDat->repeatMap);
}else{
scrDat->pos.x = 0;
}
if(scrDat->size.y < map->height){
scrDat->pos.y = mod(head->pos.y - scrDat->size.y / 2 ,map->height, scrDat->repeatMap);
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
int min_x = scrDat->pos.x;
int max_x = scrDat->pos.x + scrDat->size.x;
int min_y = scrDat->pos.y;
int max_y = scrDat->pos.y + scrDat->size.y;
switch (d)
{
case LEFT:
if(scrDat->size.x < map->width && mod(head->pos.x - min_x, map->width, 1) < 6){
scrDat->pos.x = mod(min_x - 1, map->width, scrDat->isXRepeat);
do_update = 1;
}
break;
case RIGHT:
if(scrDat->size.x < map->width && mod(max_x - head->pos.x, map->width, 1) < 6){
scrDat->pos.x = mod(mod(max_x + 1, map->width, scrDat->isXRepeat) - scrDat->size.x, map->width, true);
do_update = 1; //1 equal true :D
}
break;
case UP:
if(scrDat->size.y < map->height && mod(head->pos.y - min_y, map->height, 1) < 6){
scrDat->pos.y = mod(min_y - 1, map->height, scrDat->isYRepeat);
do_update = 1;
}
break;
case DOWN:
if(scrDat->size.y < map->height && mod(max_y - head->pos.y, map->height, 1) < 6){
scrDat->pos.y = mod(mod(max_y + 1, map->height, scrDat->isYRepeat) - scrDat->size.y, map->height, true);
do_update = 1; //1 equal true :D
}
break;
default:
//printf("Something went wrong. Direction value is %d.\n", d);
break;
}
}
if(do_update){
Pos pos;
for (pos.y = scrDat->pos.y; pos.y < scrDat->pos.y + scrDat->size.y; pos.y++){
printf("\e[%d;0H\e[K", pos.y - scrDat->pos.y + 1); //Clear the screen line
if(pos.y >= map->height && !scrDat->isYRepeat){
break;
}
for (pos.x = scrDat->pos.x; pos.x < scrDat->pos.x + scrDat->size.x; pos.x++){
if(pos.x < map->width || scrDat->isXRepeat){
print(map->matrix[pos.x%map->width][pos.y%map->height], pos, scrDat, map->width, map->height);
/**
* reads the stdin for new control commands (wasd), apply them to the scrDat commands standardDat
* and dooesn't start to wait for user input if not available.
*
* @param scrDat standard game data
* @param direction current direction
*/
void getControl(screenData *scrDat, Direction *direction){
int i;
while(i = getNextChar(), i != EOF){
Direction next = NONE;
switch (i)
{
case 'a':
next = LEFT;
break;
case 's':
next = DOWN;
break;
case 'w':
next = UP;
break;
case 'd':
next = RIGHT;
break;
default:
next = NONE;
continue; //we don't have to registrate a non command...
}
if(*direction == NONE){
*direction = next;
continue;
}
if(next == *direction){
scrDat->commands[0] = NONE;
scrDat->commands[1] = NONE;
continue;
}
// [a && b || c] = [c || a && b] = [(a && b) || c]
if(((*direction == UP || *direction == DOWN) && (next == RIGHT || next == LEFT))
|| ((*direction == RIGHT || *direction == LEFT) && (next == UP || next == DOWN))){
scrDat->commands[0] = next;
}
else
{
if(scrDat->commands[0] != NONE){
scrDat->commands[1] = next;
}
}
}
}
/**
* @param c input chunk
* @return false if the input chunk is a wall
*/
int isNotWall(chunk c){
return c.isFood || (c.data.chars[0].bytes.c[0] == ' ' && c.data.chars[1].bytes.c[0] == ' ');
}
/**
* @param c input chunk
* @return is the chunk air (not wall and not food)
*/
/**
* after some round it will place a new food onto the map randomly.
*
* @param map map
* @param foodTick how long ago was the last food placed (pointer)
* @param feedAmount how often (in ticks) sould be a new food placed
* @param firstSnake snake, to avoid placing food into snake
* @param scrDat food will be printed, screed data is needed for this
*/
void updateFood(Matrix *map, int *foodTick, int feedAmount, snakeChain *firstSnake, screenData *scrDat){
if((*foodTick)++ > feedAmount){
for(int i = 0; i < 128; i++){
Pos pos;
int isFree = 1;
snakeChain *snake = firstSnake;
pos.x = rand()%map->width;
pos.y = rand()%map->height;
if(isAir(map->matrix[pos.x][pos.y])){
while(snake != NULL){
if(snake->pos.x == pos.x && snake->pos.y == pos.y){
isFree = false;
break;
}
snake = snake->next;
map->matrix[pos.x][pos.y].isFood = 1;
map->matrix[pos.x][pos.y].data.FRand = rand();
c.data.chars[0].bytes.c[0] = 'X';
printf(green);
print(c, pos, scrDat, map->width, map->height);
printf("\e[0m");
/**
* step and check snake
*
*
* @param map map
* @param scrDat screenData
* @param d current direction
* @param head head of snek
* @param canBite can sneak bite itself (boolean)
* @return EOF if fatal error happened, 1 if the game is over, 0 instead.
*/
int updateSnake(Matrix *map, screenData *scrDat, Direction d, snakeChain *head, int canBite){
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
break;
case LEFT:
pos.x--;
break;
case RIGHT:
pos.x++;
break;
default:
return EOF;
break;
}
if(pos.x < 0 || pos.x >= map->width){
if(scrDat->repeatMap){
pos.x = mod(pos.x, map->width, true);
}
else
{
return 1; //GAME OVER reached map end;
}
}
if(pos.y < 0 || pos.y >= map->height){
if(scrDat->repeatMap){
pos.y = mod(pos.y, map->height, true);
}
else
{
return 1; //GAME OVER reached map end;
}
}
if(isNotWall(map->matrix[pos.x][pos.y])){
int isFood = map->matrix[pos.x][pos.y].isFood;
if(isFood){
map->matrix[pos.x][pos.y].isFood = false;
map->matrix[pos.x][pos.y].data.chars[0].bytes.c[0] = ' ';
map->matrix[pos.x][pos.y].data.chars[1].bytes.c[0] = ' ';
}
if(snake != head && snake->pos.x == head->pos.x && snake->pos.y == head->pos.y){
if(snake->next != NULL){
if(canBite){
//if snek can bite its own tail, free that space and fill these places with .
current = tmp_snek;
tmp_snek = tmp_snek->next;
c.data.chars[0].bytes.c[0] = ' ';
c.data.chars[1].bytes.c[0] = ' ';
print(c, current->pos, scrDat, map->width, map->height);
free(current);
}
}
else
{
return 1; //GAME OVER snake hit itself;
}
}else
{
isFood = false;
}
}
tmp_pos2 = snake->pos;
snake->pos = tmp_pos1;
tmp_pos1 = tmp_pos2;
//step direction
dir_tmp2 = snake->dir;
snake->dir = dir_tmp;
//render snek
/*
*/
if(snake->pos.x != -1){
//TODO call render
}
//create a new segment
if(snake->next == NULL){
return EOF;
}
snake->next->next = NULL;
//printf(blue);
//print(c, snake->pos, scrDat, map->width, map->height); //TODO direction snake
#ifdef DEBUG
printf("\e[0m"); //if debug active, update display after every segments
#endif
print(c, tmp_pos2, scrDat, map->width, map->height); //set this to air.
}
chunk c;
printf(blue);
print(c, head->pos, scrDat, map->width, map->height); //TODO direction snake
}
else
{
return 1; //GAME OVER hit the wall;
}
return 0;
/**
* Loads game config file
*
* @param tickSpeed game tickSpeed in miliseconds
* @param repeatMap is the map repeated
* @param feedAmount food spawn rate
* @param canBite can snek bite itself
*
* @return EOF if error 0 instead
*/
int loadConfig(int *tickSpeed, int *repeatMap, int *feedAmount, int *canBite){
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
FILE *config;
config = fopen("config.cfg", "r");
//int stillFile = 1; //boolean to show file is ended...
if(config == NULL){
return -1;
}
while(1){
char name[32] = {0}, c; //it have to be enough;
while(c = fgetc(config), c != -1 && isspace(c));
if(c == -1){
break;
}
//name[0] = c;
for(int i = 0; i < 32 && !isspace(c) && c != '='; i++, c = fgetc(config)){
name[i] = c;
}
//c = fgetc(config);
while(c != '='){
c = fgetc(config);
if(c == -1){
printf("I can't understand the config file: %s", name);
return EOF;
}
}
if(strncmp(name, "use_utf8", 9) == 0){
int bl;
fscanf(config, " %d", &bl);
isUnicodeEncoding(bl);
}
else if(strncmp(name, "tickspeed", 10) == 0){
fscanf(config, " %d", tickSpeed);
}
else if(strncmp(name, "feed_amount", 12) == 0){
fscanf(config, " %d", feedAmount);
}
else if(strncmp(name, "can_bite", 9) == 0){
fscanf(config, " %d", canBite);
}
else{
printf("Unknown keyword: %s", name);
}
}
return 0;
}
//------------LOOP METHODs--------------
//Tick the game, step the snake, collect and place food.
//check new direction
//update display
//update food state
//step snake
/**
* ticks the game including everything
* updates the control
* updates the screen
* updates the foods
* steps snek
*
* @param map map
* @param scrDat screenData
* @param snake snake's head
* @param d direction
* @param feedAmount food spawn rate
* @param canBite can snake bite its own tail
* @return 1 if game over
*/
int tick(Matrix *map, screenData *scrDat, snakeChain *snake, Direction *d, int feedAmount, int canBite){
static int foodTick = 0;
getControl(scrDat, d);
if(scrDat->commands[0] != NONE){
*d = scrDat->commands[0];
}
scrDat->commands[0] = scrDat->commands[1];
scrDat->commands[1] = NONE;
printf(blue);
print(c, snake->pos, scrDat, map->width, map->height);
printf("\e[0m");
return 0; // waiting for user input.
}
if(updateSnake(map, scrDat, *d, snake, canBite)){
*d = NONE;
//TODO Game over or remove 1 hp or ...
}
//printf("\e[0;0H\n"); //Update the terminal (mostly on Unix based systems)
fflush(stdout);
/**
* prepares the game for loop and then starts the infinite loop
*
* @param matrix map
* @param tickspeed game tickspeed in milis
* @param repeatMap does the map repeat itself
* @param feedAmount food spawn rate
* @param canBite can snake bite itself
* @return 0
*/
int loop(Matrix *matrix, int tickspeed, int repeatMap, int feedAmount, int canBite){
snakeChain snake, *chain;
while(true){
Pos p;
p.x = rand()%matrix->width;
p.y = rand()&matrix->height;
snake.pos = p;
break;
}
}
chain = &snake;
for(int i = 1; i < 3; i++){
Pos p;
p.x = -1;
p.y = -1;
chain->next = malloc(sizeof(snakeChain));
if(chain->next == NULL){
return -1;
}
chain = chain->next;
chain->pos = p;
unisleep(tickspeed); //Special sleep to work both in windows and unix environment
}
/**
* ONLY FOR DEBUG
* print the map for debug
*
* @param map map
*/
void _testprint(Matrix *map){
for (int y = 0; y < map->height; y++){
for(int x = 0; x < map->width; x++){
for(int i = 0; i < 2; i++){
//printf("%c", map->matrix[x][y].chars->bytes.c[i * 4]); //WTF... I didn't indexed correctly, but accidentaly I've got the right value...
/**
* ONLY FOR DEBUG
* reads coordinates from stdin and print this pos to the stdout
*
* @param map map
*/
void _print1char(Matrix *map){
int x, y;
while(scanf(" %d%d", &x, &y) == 2){
if(x >= 0 && y >= 0 && x < map->width && y < map->height){
for(int i = 0;i < 2; i++){
(unsigned)map->matrix[x][y].data.chars[i].bytes.c[0],
(unsigned)map->matrix[x][y].data.chars[i].bytes.c[1],
(unsigned)map->matrix[x][y].data.chars[i].bytes.c[2],
(unsigned)map->matrix[x][y].data.chars[i].bytes.c[3]);
printf("\"\n");
}
}
}
}
//-------------CORE METHOD----------------
/**
* The main method is respinsible for the debug or release mode start, technically the main is redirected here
* initialize the game then start tle game
*
* @param argc redirected argc
* @param argv redirected argv
*/
int tickspeed = 100, repeatMap = 0, feedAmount = 20, canBite = true; // if no config, default value
return 0;
}
else{
f = fopen(argv[1], "rb");
if(f == NULL){
printf("Map file not found: %s", argv[1]);
return EOF;
}
readFile(f, &map);
}
return 0;
}
/*
int main(int argc, char const *argv[])
{
return core(argc, argv);
}
*/
/**
* debugger main function
* in debug mode, starts the core with correct params
* in release mode, it will use user input files.
int walltest; //warning: unused variable ‘walltest’ [-Wunused-variable]
ret = core(2, array);
printf("\npress any key to continue");
getchar();
//return 0, ret; //Miért van ez a függvény tele szeméttel??? pl 0, smt...
return ret; // így szép.