1. 程式人生 > >一個2048遊戲

一個2048遊戲

寫程式碼容易,構思難啊。為了寫這還專門玩了玩2048小遊戲,將裡面的步驟分解,變成一個一個的函式,才慢慢寫完這個小遊戲。寫加上改程式碼,測差不多4個多晚上啊。 先說自己遇到的一些問題:

    最大的一個問題便是getchar();當輸入一個字元時,它會接收回車鍵,導致程式多跑一邊。 1.使用了 fflush(stdin)用了清空快取區但不知道為什莫不管用。

2.想了一個笨辦法:ch=getchar(); getchar()     或是:scanf("%c\\n", &ch); 反正是搞定了。

查的相關的知識點:

1.產生一定範圍的隨機數:

C語言的獲取隨機數的函式為rand(), 可以獲得一個非負整數的隨機數。要呼叫rand需要引用標頭檔案 stdlib.h
要讓隨機數限定在一個範圍,可以採用模除加加法的方式。
要產生隨機數r, 其範圍為 m<=r<=n,可以使用如下公式:
rand()%(n-m+1)+m
其原理為,對於任意數,
0<=rand()%(n-m+1)<=n-m
於是
0+m<=rand()%(n-m+1)+m<=n-m+m


m<=rand()%(n-m+1)+m<=n
2. exit() 是電腦函式 exit()通常是用在 子程式 中用來終結程式用的,使用後程序自動結束,跳回作業系統。 exit(0) 表示程式正常退出,exit⑴/exit(-1)表示程式異常退出。

3。getchar() 如使用者在按回車之前輸入了不止一個字元,其他字元會保留在鍵盤快取區中,等待後續getchar呼叫讀取
.也就是說,後續的getchar呼叫不會等待使用者按鍵,而直接讀取緩衝區中的字元,直到緩衝區中的字元讀完為後,才等待使用者按鍵.
具體程式碼:
#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define OK 1
#define ERRORY 0


int times = 0;
int pane[9][9];
typedef struct Head
{
	int order;
	int data1;
	int data2;
	struct Head *next;
}Pane_number, *Pane;


//功能函式
void grid();//列印4*4格子
void init_pane();//初始化二維陣列
void move_up();//格子向上移動
void move_down();//格子向下移動
void move_left();//向左移動
void move_right();//向右移動
Pane ergodic_gane(Pane head);//遍歷所有的格子存在連結串列裡
void delete_other(Pane head);//刪除除過表頭以外的連結串列節點
void new_number(Pane head);//移動一次產生一個新數
int judge_end(Pane head);//判斷是否結束
int score();//顯示分數
void select();//方向選擇;
void play(Pane head);
void menu(Pane head);//介面初始化

//函式實現


//列印4*4格子
void grid()
{
	int i = 0, j = 0, k = 0;
	for (k = 0; k<21; k++)
	{
		printf("*");
	}
	printf("\n");
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			printf("*    ");
		}
		printf("*\n");

		for (j = 0; j<4; j++)
		{
			if (pane[i][j] == 0)
			{
				printf("*    ");

			}
			else
			{
				if (pane[i][j] < 10)
				{
					printf("*%d   ", pane[i][j]);
				}
				if (pane[i][j] >= 10 && pane[i][j] < 100)
				{
					printf("*%d  ", pane[i][j]);
				}
				if (pane[i][j] >= 100 && pane[i][j] < 1000)
				{
					printf("*%d ", pane[i][j]);
				}
				if (pane[i][j] >= 1000)
				{
					printf("%d", pane[i][j]);
				}
			}
		}
		printf("*\n");

		for (k = 0; k<21; k++)
		{
			printf("*");
		}
		printf("\n");
	}
}

//初始化二維陣列
void init_pane()
{
	int i = 0, j = 0;
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			pane[i][j] = 0;
		}
	}
	srand(time(NULL));
	i = rand() % 4;
	j = rand() % 4;
	if (i == 0 || i == 2)
	{
		pane[i][j] = 2;
	}
	else
	{
		pane[i][j] = 4;
	}
}

//格子向上移動
void move_up()
{
	//遍歷每個格子,合併相同的數字
	int k = 0, i = 0, j = 0;
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			if (pane[j][i] == 0)
				;
			else
			{
				for (k = j + 1; k<4; k++)
				{
					if (pane[k][i] == 0)
						;
					else
					{
						if (pane[j][i] == pane[k][i])
						{
							pane[j][i] = pane[j][i] * 2;
							pane[k][i] = 0;
							break;
						}

					}
				}
			}
		}
	}
	//向上來移動格子,使得其沒有空格
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			if (pane[j][i] == 0)
			{
				for (k = j + 1; k<4; k++)
				{
					if (pane[k][i] == 0)
						;
					else
					{
						pane[j][i] = pane[k][i];
						pane[k][i] = 0;
						break;
					}
				}

			}
		}
	}
}

//格子向下移動
void move_down()
{
	//遍歷每個格子,合併相同的數字
	int k = 0, i = 0, j = 0;
	for (i = 3; i >= 0; i--)
	{
		for (j = 3; j >= 0; j--)
		{
			if (pane[j][i] == 0)
				;
			else
			{
				for (k = j - 1; k >= 0; k--)
				{
					if (pane[k][i] == 0)
						;
					else
					{
						if (pane[k][i] == pane[j][i])
						{
							pane[j][i] = pane[j][i] * 2;
							pane[k][i] = 0;
							break;
						}

					}
				}
			}
		}
	}
	//向下來移動格子,使得其沒有空格
	for (i = 3; i >= 0; i--)
	{
		for (j = 3; j >= 0; j--)
		{
			if (pane[j][i] == 0)
			{
				for (k = j - 1; k >= 0; k--)
				{
					if (pane[k][i] == 0)
						;
					else
					{
						pane[j][i] = pane[k][i];
						pane[k][i] = 0;
						break;
					}
				}

			}
		}
	}

}

//向左移動
void move_left()
{
	//遍歷每個格子,合併相同的數字
	int k = 0, i = 0, j = 0;
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			if (pane[i][j] == 0)
				;
			else
			{
				for (k = j + 1; k<4; k++)
				{
					if (pane[i][k] == 0)
						;
					else
					{
						if (pane[i][k] == pane[i][k])
						{
							pane[i][j] = pane[i][j] * 2;
							pane[i][k] = 0;
							break;
						}

					}
				}
			}
		}
	}
	//向左來移動格子,使得其沒有空格
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			if (pane[i][j] == 0)
			{
				for (k = j + 1; k<4; k++)
				{
					if (pane[i][k] == 0)
						;
					else
					{
						pane[i][j] = pane[i][k];
						pane[i][k] = 0;
						break;
					}
				}

			}
		}
	}
}

//向右移動
void move_right()
{
	//遍歷每個格子,合併相同的數字
	int k = 0, i = 0, j = 0;
	for (i = 3; i >= 0; i--)
	{
		for (j = 3; j >= 0; j--)
		{
			if (pane[i][j] == 0)
				;
			else
			{
				for (k = j - 1; k >= 0; k--)
				{
					if (pane[i][k] == 0)
						;
					else
					{
						if (pane[i][k] == pane[i][j])
						{
							pane[i][j] = pane[i][j] * 2;
							pane[i][k] = 0;
							break;
						}

					}
				}
			}
		}
	}
	//向右來移動格子,使得其沒有空格
	for (i = 3; i >= 0; i--)
	{
		for (j = 3; j >= 0; j--)
		{
			if (pane[i][j] == 0)
			{
				for (k = j - 1; k >= 0; k--)
				{
					if (pane[i][k] == 0)
						;
					else
					{
						pane[i][j] = pane[i][k];
						pane[i][k] = 0;
						break;
					}
				}

			}
		}
	}

}

//產生一個新數
void new_number(Pane head)
{
	int i = 0, k = 0;
	Pane sign, re;
	sign = ergodic_gane(head);
	re = ergodic_gane(head);
	//隨機選擇一個空格子,賦值給2
	srand(time(NULL));
	k = rand() % sign->order + 1;
	//printf("空個數:%d\n", re->order);
	//printf("被選擇的格子:%d\n", k);
	for (i = 0; i <= re->order; i++)
	{
		sign = sign->next;
		if (sign->order == k)
		{
			pane[sign->data1][sign->data2] = 2;
			//printf("座標是:%d  %d\n", sign->data1, sign->data2);
		}
	}

}

//顯示分數
int score()
{
	int i = 0, j = 0, total = 0;
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			if (pane[i][j] != 0)
				total = pane[i][j] + total;
		}
	}
	printf("The score: %d\n", total);
	return (0);
}

//遍歷所有的格子將資訊存在連結串列裡
Pane ergodic_gane(Pane head)
{
	int i = 0, j = 0, sum = 0;
	//現遍歷所有的格子
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			if (pane[i][j] == 0)
			{
				Pane p = (Pane)malloc(sizeof(Pane_number));
				p->data1 = i;
				p->data2 = j;
				sum = sum++;
				p->order = sum;

				p->next = head->next;
				head->next = p;
			}
		}

	}
	if (head->next == NULL)
	{
		head->order = 0;
	}
	else
	{
		head->order = head->next->order;
	}
	return (head);
}

//刪除除過表頭以外的連結串列節點
void delete_other(Pane head)
{
	Pane p, q;
	p = head->next;
	if (head->next == NULL)
		;
	else
	{
		q = p->next;
		free(p);
		p = q;
	}
	head->order = 0;
	head->next = 0;
}

//判斷是否結束
int judge_end(Pane head)
{
	int i = 0, j = 0, k = 0;
	Pane mm;
	mm = ergodic_gane(head);
	for (i = 0; i<4; i++)
	{
		for (j = 0; j<4; j++)
		{
			if (pane[i][j] == 2048)
				k = 1;
		}
	}
	//printf("判斷已呼叫\n");
	if (mm->order == 0 || k == 1)
		return ERRORY;
	else
		return OK;
}

//選擇移動方向
void select()
{
	char ch = 0;
	//fflush(stdin);
	printf("Please import control key !\n");
	scanf("%c\\n", &ch); //接收了回車鍵,消除回車鍵的影響

	if (ch <= 'z' && ch >= 'a')
		ch -= 32;
	while (ch != 'A' && ch != 'D' && ch != 'S' && ch != 'W' && ch != 'Q')
	{
		printf("caution!   caution! \n");
		printf("please enter again !\n");
		scanf("%c\\n", &ch);
		if (ch <= 'z' && ch >= 'a')
			ch -= 32;
	}

	switch (ch)
	{
	case 'A':	move_left(); break;
	case 'D':	move_right(); break;
	case 'S':   move_down(); break;
	case 'W':   move_up(); break;
	case 'Q':   exit(0);
	default: break;
	}
}

void play(Pane head)
{
	new_number(head);
	score();
	grid();
	delete_other(head);
}

//介面初始化
void menu(Pane head)
{
	system("color 05");
	printf("****************************\n");
	printf("          2048            \n\n");
	printf("Control by:\n"
		" w/s/a/d or W/S/A/D\n");
	printf("press q or Q quit game!\n");
	printf("****************************\n");
	printf("Press any key to continue . . .\n");
	getchar();
	system("cls");
	init_pane();
	new_number(head);
	grid();
	system("pause");
}

int main()
{
	Pane head;
	head = (Pane)malloc(sizeof(Pane_number));
	head->next = NULL;

	menu(head);

	while (judge_end(head))
	{
		select();
		system("cls");
		play(head);
	}
	return 0;
}