/* ============================================================================ Name : 2048.c Author : Maurits van der Schee Description : Console version of the game "2048" for GNU/Linux ============================================================================ */ #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include #include #include #include #define SIZE 4 #define HIGHSCORES_DEFAULT_NAME "mevdschee" #define HIGHSCORES_DEFAULT_SCORE 10 // ^ these are the default name and score which will be used when creating // a default score file. #define HIGHSCORES_NUMBER 10 // How many highscores in a file? #define LOGIN_NAME_USUAL 32 char score_file0[FILENAME_MAX + 1], score_file1[FILENAME_MAX + 1] = ""; char *score_file; char player_name[LOGIN_NAME_MAX + 1]; struct score_rec{ char name[LOGIN_NAME_MAX + 1]; uint32_t score; } highscores[HIGHSCORES_NUMBER + 1], player_score_rec; uint32_t score=0; uint8_t scheme=0; void getColor(uint8_t value, char *color, size_t length) { uint8_t original[] = {8,255,1,255,2,255,3,255,4,255,5,255,6,255,7,255,9,0,10,0,11,0,12,0,13,0,14,0,255,0,255,0}; uint8_t blackwhite[] = {232,255,234,255,236,255,238,255,240,255,242,255,244,255,246,0,248,0,249,0,250,0,251,0,252,0,253,0,254,0,255,0}; uint8_t bluered[] = {235,255,63,255,57,255,93,255,129,255,165,255,201,255,200,255,199,255,198,255,197,255,196,255,196,255,196,255,196,255,196,255}; uint8_t *schemes[] = {original,blackwhite,bluered}; uint8_t *background = schemes[scheme]+0; uint8_t *foreground = schemes[scheme]+1; if (value > 0) while (value--) { if (background+2=0;t--) { if (array[t]!=0) { if (array[t]!=array[x]) { // merge is not possible, take next position return t+1; } return t; } else { // we should not slide further, return this one if (t==stop) { return t; } } } // we did not find a return x; } bool slideArray(uint8_t array[SIZE]) { bool success = false; uint8_t x,t,stop=0; for (x=0;x0) return false; if (findPairDown(board)) return false; rotateBoard(board); if (findPairDown(board)) ended = false; rotateBoard(board); rotateBoard(board); rotateBoard(board); return ended; } void addRandom(uint8_t board[SIZE][SIZE]) { static bool initialized = false; uint8_t x,y; uint8_t r,len=0; uint8_t n,list[SIZE*SIZE][2]; if (!initialized) { srand(time(NULL)); initialized = true; } for (x=0;x0) { r = rand()%len; x = list[r][0]; y = list[r][1]; n = (rand()%10)/9+1; board[x][y]=n; } } void initBoard(uint8_t board[SIZE][SIZE]) { uint8_t x,y; for (x=0;x "); for (i=0;i "); for (i=0;iscore - ((struct score_rec *)a)->score; } int makeScorefile(const char *file_path){ FILE *fp; fp = fopen(file_path, "w"); if (!fp){ return EXIT_FAILURE; } struct score_rec default_scores[HIGHSCORES_NUMBER]; for (uint32_t i = 0; i < HIGHSCORES_NUMBER; i++){ strcpy(default_scores[i].name, HIGHSCORES_DEFAULT_NAME); default_scores[i].score = HIGHSCORES_DEFAULT_SCORE; } uint32_t w_items = fwrite(default_scores, sizeof(struct score_rec),HIGHSCORES_NUMBER, fp); fclose(fp); if (w_items != HIGHSCORES_NUMBER){ return EXIT_FAILURE; } return EXIT_SUCCESS; } void whichScorefile(){ if (access(score_file, F_OK) != 0){ if (makeScorefile(score_file) == EXIT_FAILURE){ if (score_file == score_file1){ score_file = NULL; return; }else{ score_file = score_file1; whichScorefile(); return; } } } FILE *fp; fp = fopen(score_file, "r+"); if (fp == NULL){ if (score_file == score_file1){ score_file = NULL; return; }else{ score_file = score_file1; whichScorefile(); return; } } fclose(fp); return; } void readHighscores(){ FILE *fp; fp = fopen(score_file, "r"); if (!fp){ fprintf(stderr, "Error opening score file for reading and writing"); exit(EXIT_FAILURE); } fread(highscores, sizeof(struct score_rec), HIGHSCORES_NUMBER, fp); fclose(fp); } void updateHighscores(){ FILE *fp; fp = fopen(score_file, "w"); strcpy(highscores[HIGHSCORES_NUMBER].name, player_name); highscores[HIGHSCORES_NUMBER].score = score; qsort(&highscores, HIGHSCORES_NUMBER + 1, sizeof(struct score_rec), compareScorerecs); fwrite(highscores, sizeof(struct score_rec), HIGHSCORES_NUMBER, fp); fclose(fp); } void printHighscores(){ //TODO: prettier printing char line[LOGIN_NAME_USUAL + 6 + 1] = {0}; memset(line, ' ', LOGIN_NAME_USUAL - 4 - 6); printf("Name%sScore\n", line); memset(line, '=', LOGIN_NAME_USUAL + 6); puts(line); memset(line, 0, LOGIN_NAME_USUAL + 6 + 1); for (uint32_t i = 0; i < HIGHSCORES_NUMBER; i++){ memset(line, ' ', LOGIN_NAME_USUAL - 6 - strlen(highscores[i].name)); printf("%s%s%d\n", highscores[i].name, line, highscores[i].score); } } int main(int argc, char *argv[]) { uint8_t board[SIZE][SIZE]; char c; bool success; strcpy(score_file0, "/var/games/2048scores"); strcpy(score_file1, getpwuid(geteuid())->pw_dir); strcat(score_file1, "/.2048scores"); score_file = score_file0; whichScorefile(); // which score file should we use? if (score_file == NULL){ fprintf(stderr, "Could not use any of highscores\n"); return EXIT_FAILURE; } if(!strcmp(argv[1], "scores")){ readHighscores(); printHighscores(); return EXIT_SUCCESS; } if (argc == 2 && strcmp(argv[1],"test")==0) { return test(); } if (argc == 2 && strcmp(argv[1],"blackwhite")==0) { scheme = 1; } if (argc == 2 && strcmp(argv[1],"bluered")==0) { scheme = 2; } printf("\033[?25l\033[2J"); // register signal handler for when ctrl-c is pressed signal(SIGINT, signal_callback_handler); initBoard(board); setBufferedInput(false); while (true) { c=getchar(); if (c == -1){ //TODO: maybe replace this -1 with a pre-defined constant(if it's in one of header files) puts("\nError! Cannot read keyboard input!"); break; } switch(c) { case 97: // 'a' key case 104: // 'h' key case 68: // left arrow success = moveLeft(board); break; case 100: // 'd' key case 108: // 'l' key case 67: // right arrow success = moveRight(board); break; case 119: // 'w' key case 107: // 'k' key case 65: // up arrow success = moveUp(board); break; case 115: // 's' key case 106: // 'j' key case 66: // down arrow success = moveDown(board); break; default: success = false; } if (success) { drawBoard(board); usleep(150000); addRandom(board); drawBoard(board); if (gameEnded(board)) { printf(" GAME OVER \n"); break; } } if (c=='q') { printf(" QUIT? (y/n) \n"); c=getchar(); if (c=='y') { break; } drawBoard(board); } if (c=='r') { printf(" RESTART? (y/n) \n"); c=getchar(); if (c=='y') { initBoard(board); } drawBoard(board); } } setBufferedInput(true); printf("\033[?25h\033[m"); char *username; username = getpwuid(geteuid())->pw_name; printf("Enter your name[%s]: ", username); fgets(player_name, LOGIN_NAME_MAX, stdin); player_name[strlen(player_name) - 1] = '\0'; if (!strcmp(player_name, "")){ strcpy(player_name, username); } updateHighscores(); // reads high scores from disk, sorts them and again writes to disk printHighscores(); return EXIT_SUCCESS; }