Advertisement

C 语言小游戏 - 2048

阅读量:

每次可以选择上、下、左、右四个方向中的任意一个方向来操作;每完成一次操作后, 所有的数字方块都会朝着被选择的方向移动, 并靠拢该方向;系统会在所有空白区域中随机出现一个新的数字方块;相邻或碰撞的相同数字方块会合并成一个较大的数字方块;通过不断叠加运算最终形成2048这个目标数值即为游戏成功。

控制方式字母WASD分别为上下左右Q为退出。

复制代码
 /*

    
  ============================================================================
    
  Name        : 2048.c
    
  Author      : Maurits van der Schee
    
  Description : Console version of the game "2048" for GNU/Linux
    
  ============================================================================
    
  */
    
  
    
 #define _XOPEN_SOURCE 500
    
 #include <stdio.h>
    
 #include <stdlib.h>
    
 #include <string.h>
    
 #include <unistd.h>
    
 #include <termios.h>
    
 #include <stdbool.h>
    
 #include <stdint.h>
    
 #include <time.h>
    
 #include <signal.h>
    
  
    
 #define SIZE 4
    
 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<schemes[scheme]+sizeof(original)) {
    
 			background+=2;
    
 			foreground+=2;
    
 		}
    
 	}
    
 	snprintf(color,length,"\033[38;5;%d;48;5;%dm",*foreground,*background);
    
 }
    
  
    
 void drawBoard(uint8_t board[SIZE][SIZE]) {
    
 	uint8_t x,y;
    
 	char color[40], reset[] = "\033[m";
    
 	printf("\033[H");
    
  
    
 	printf("2048.c %17d pts\n\n",score);
    
  
    
 	for (y=0;y<SIZE;y++) {
    
 		for (x=0;x<SIZE;x++) {
    
 			getColor(board[x][y],color,40);
    
 			printf("%s",color);
    
 			printf("       ");
    
 			printf("%s",reset);
    
 		}
    
 		printf("\n");
    
 		for (x=0;x<SIZE;x++) {
    
 			getColor(board[x][y],color,40);
    
 			printf("%s",color);
    
 			if (board[x][y]!=0) {
    
 				char s[8];
    
 				snprintf(s,8,"%u",(uint32_t)1<<board[x][y]);
    
 				uint8_t t = 7-strlen(s);
    
 				printf("%*s%s%*s",t-t/2,"",s,t/2,"");
    
 			} else {
    
 				printf("   ·   ");
    
 			}
    
 			printf("%s",reset);
    
 		}
    
 		printf("\n");
    
 		for (x=0;x<SIZE;x++) {
    
 			getColor(board[x][y],color,40);
    
 			printf("%s",color);
    
 			printf("       ");
    
 			printf("%s",reset);
    
 		}
    
 		printf("\n");
    
 	}
    
 	printf("\n");
    
 	printf("        W,A,S,D or q        \n");
    
 	printf("\033[A"); // one line up
    
 }
    
  
    
 uint8_t findTarget(uint8_t array[SIZE],uint8_t x,uint8_t stop) {
    
 	uint8_t t;
    
 	// if the position is already on the first, don't evaluate
    
 	if (x==0) {
    
 		return x;
    
 	}
    
 	for(t=x-1;;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;x<SIZE;x++) {
    
 		if (array[x]!=0) {
    
 			t = findTarget(array,x,stop);
    
 			// if target is not original position, then move or merge
    
 			if (t!=x) {
    
 				// if target is zero, this is a move
    
 				if (array[t]==0) {
    
 					array[t]=array[x];
    
 				} else if (array[t]==array[x]) {
    
 					// merge (increase power of two)
    
 					array[t]++;
    
 					// increase score
    
 					score+=(uint32_t)1<<array[t];
    
 					// set stop to avoid double merge
    
 					stop = t+1;
    
 				}
    
 				array[x]=0;
    
 				success = true;
    
 			}
    
 		}
    
 	}
    
 	return success;
    
 }
    
  
    
 void rotateBoard(uint8_t board[SIZE][SIZE]) {
    
 	uint8_t i,j,n=SIZE;
    
 	uint8_t tmp;
    
 	for (i=0; i<n/2; i++) {
    
 		for (j=i; j<n-i-1; j++) {
    
 			tmp = board[i][j];
    
 			board[i][j] = board[j][n-i-1];
    
 			board[j][n-i-1] = board[n-i-1][n-j-1];
    
 			board[n-i-1][n-j-1] = board[n-j-1][i];
    
 			board[n-j-1][i] = tmp;
    
 		}
    
 	}
    
 }
    
  
    
 bool moveUp(uint8_t board[SIZE][SIZE]) {
    
 	bool success = false;
    
 	uint8_t x;
    
 	for (x=0;x<SIZE;x++) {
    
 		success |= slideArray(board[x]);
    
 	}
    
 	return success;
    
 }
    
  
    
 bool moveLeft(uint8_t board[SIZE][SIZE]) {
    
 	bool success;
    
 	rotateBoard(board);
    
 	success = moveUp(board);
    
 	rotateBoard(board);
    
 	rotateBoard(board);
    
 	rotateBoard(board);
    
 	return success;
    
 }
    
  
    
 bool moveDown(uint8_t board[SIZE][SIZE]) {
    
 	bool success;
    
 	rotateBoard(board);
    
 	rotateBoard(board);
    
 	success = moveUp(board);
    
 	rotateBoard(board);
    
 	rotateBoard(board);
    
 	return success;
    
 }
    
  
    
 bool moveRight(uint8_t board[SIZE][SIZE]) {
    
 	bool success;
    
 	rotateBoard(board);
    
 	rotateBoard(board);
    
 	rotateBoard(board);
    
 	success = moveUp(board);
    
 	rotateBoard(board);
    
 	return success;
    
 }
    
  
    
 bool findPairDown(uint8_t board[SIZE][SIZE]) {
    
 	bool success = false;
    
 	uint8_t x,y;
    
 	for (x=0;x<SIZE;x++) {
    
 		for (y=0;y<SIZE-1;y++) {
    
 			if (board[x][y]==board[x][y+1]) return true;
    
 		}
    
 	}
    
 	return success;
    
 }
    
  
    
 uint8_t countEmpty(uint8_t board[SIZE][SIZE]) {
    
 	uint8_t x,y;
    
 	uint8_t count=0;
    
 	for (x=0;x<SIZE;x++) {
    
 		for (y=0;y<SIZE;y++) {
    
 			if (board[x][y]==0) {
    
 				count++;
    
 			}
    
 		}
    
 	}
    
 	return count;
    
 }
    
  
    
 bool gameEnded(uint8_t board[SIZE][SIZE]) {
    
 	bool ended = true;
    
 	if (countEmpty(board)>0) 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;x<SIZE;x++) {
    
 		for (y=0;y<SIZE;y++) {
    
 			if (board[x][y]==0) {
    
 				list[len][0]=x;
    
 				list[len][1]=y;
    
 				len++;
    
 			}
    
 		}
    
 	}
    
  
    
 	if (len>0) {
    
 		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<SIZE;x++) {
    
 		for (y=0;y<SIZE;y++) {
    
 			board[x][y]=0;
    
 		}
    
 	}
    
 	addRandom(board);
    
 	addRandom(board);
    
 	drawBoard(board);
    
 	score = 0;
    
 }
    
  
    
 void setBufferedInput(bool enable) {
    
 	static bool enabled = true;
    
 	static struct termios old;
    
 	struct termios new;
    
  
    
 	if (enable && !enabled) {
    
 		// restore the former settings
    
 		tcsetattr(STDIN_FILENO,TCSANOW,&old);
    
 		// set the new state
    
 		enabled = true;
    
 	} else if (!enable && enabled) {
    
 		// get the terminal settings for standard input
    
 		tcgetattr(STDIN_FILENO,&new);
    
 		// we want to keep the old setting to restore them at the end
    
 		old = new;
    
 		// disable canonical mode (buffered i/o) and local echo
    
 		new.c_lflag &=(~ICANON & ~ECHO);
    
 		// set the new settings immediately
    
 		tcsetattr(STDIN_FILENO,TCSANOW,&new);
    
 		// set the new state
    
 		enabled = false;
    
 	}
    
 }
    
  
    
 int test() {
    
 	uint8_t array[SIZE];
    
 	// these are exponents with base 2 (1=2 2=4 3=8)
    
 	uint8_t data[] = {
    
 		0,0,0,1,	1,0,0,0,
    
 		0,0,1,1,	2,0,0,0,
    
 		0,1,0,1,	2,0,0,0,
    
 		1,0,0,1,	2,0,0,0,
    
 		1,0,1,0,	2,0,0,0,
    
 		1,1,1,0,	2,1,0,0,
    
 		1,0,1,1,	2,1,0,0,
    
 		1,1,0,1,	2,1,0,0,
    
 		1,1,1,1,	2,2,0,0,
    
 		2,2,1,1,	3,2,0,0,
    
 		1,1,2,2,	2,3,0,0,
    
 		3,0,1,1,	3,2,0,0,
    
 		2,0,1,1,	2,2,0,0
    
 	};
    
 	uint8_t *in,*out;
    
 	uint8_t t,tests;
    
 	uint8_t i;
    
 	bool success = true;
    
  
    
 	tests = (sizeof(data)/sizeof(data[0]))/(2*SIZE);
    
 	for (t=0;t<tests;t++) {
    
 		in = data+t*2*SIZE;
    
 		out = in + SIZE;
    
 		for (i=0;i<SIZE;i++) {
    
 			array[i] = in[i];
    
 		}
    
 		slideArray(array);
    
 		for (i=0;i<SIZE;i++) {
    
 			if (array[i] != out[i]) {
    
 				success = false;
    
 			}
    
 		}
    
 		if (success==false) {
    
 			for (i=0;i<SIZE;i++) {
    
 				printf("%d ",in[i]);
    
 			}
    
 			printf("=> ");
    
 			for (i=0;i<SIZE;i++) {
    
 				printf("%d ",array[i]);
    
 			}
    
 			printf("expected ");
    
 			for (i=0;i<SIZE;i++) {
    
 				printf("%d ",in[i]);
    
 			}
    
 			printf("=> ");
    
 			for (i=0;i<SIZE;i++) {
    
 				printf("%d ",out[i]);
    
 			}
    
 			printf("\n");
    
 			break;
    
 		}
    
 	}
    
 	if (success) {
    
 		printf("All %u tests executed successfully\n",tests);
    
 	}
    
 	return !success;
    
 }
    
  
    
 void signal_callback_handler(int signum) {
    
 	printf("         TERMINATED         \n");
    
 	setBufferedInput(true);
    
 	printf("\033[?25h\033[m");
    
 	exit(signum);
    
 }
    
  
    
 int main(int argc, char *argv[]) {
    
 	uint8_t board[SIZE][SIZE];
    
 	char c;
    
 	bool 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){
    
 			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");
    
  
    
 	return EXIT_SUCCESS;
    
 }
    
    
    
    
    代码解释

全部评论 (0)

还没有任何评论哟~