用C語言編寫2048遊戲

2048_C_code

用C語言編寫的2048

1

要實現我們的 2048 小遊戲,需要涉及一些數據結構的知識,以及一些 Linux 的系統調用。此外,爲了方便在屏幕上使用字符繪圖,我們還需要使用一個文本界面的屏幕繪圖庫 ncurses ,具體到操作就是在編譯的時候需要加上 -lcurses 選項。
安裝ncurses庫:
sudo apt-get install libncurses5-dev

設計思路

要實現 2048 遊戲目前有兩個關鍵點:

  1. 在滿足條件情況下消除方塊
  2. 允許在遊戲主界面(16 宮格)中任意一格輸出數據
    其中第二點藉助 ncurses 庫可以較容易實現,但是第一點要稍微麻煩些。第一點的實現思路是,我們創建一個與遊戲地圖相同維數的數組矩陣,通過數組矩陣來維護 2048 遊戲中每個格子的數據與狀態,從而玩家的移動操作都可以映射爲對數組矩陣的操作。

基礎工作

  1. 引頭文件
    編寫自己的頭文件head.h。
    添加庫函數頭文件:
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
  1. 創建函數
void draw(); //用於繪製遊戲界面
void play(); //遊戲運行的邏輯主體
void init(); //初始化函數,用於完成一些必要的初始化操作
void draw_one(int y, int x); //繪製單個數字
void cnt_value(int *new_y, int *new_x);
int game_over(); //結束遊戲
int cnt_one(int y, int x);
  1. 編寫函數
    創建函數文件head.c。
    添加函數的內容。
#include "head.h"
int a[4][4] = {0};
int empty;
int old_y, old_x;
void draw()
{
	int n, m, x, y;
	char c[4] = {'0', '0', '0', '0'};
	clear();
	for(n=0;n<9;n+=2)
	{
		for(m=0;m<21;m++)
		{
			move(n, m);
			addch('-');
			refresh();
		}
	}
	for(m=0;m<22;m+=5)
	{
		for(n=1;n<8;n++)
		{
			move(n,m);
			addch('|');
			refresh();
		}
	}
	for(y=0;y<4;y++)
	{
		for(x=0;x<4;x++)
		{
			draw_one(y, x);
		}
	}
}
void play()
{
	int x, y, i, new_x, new_y, temp;
	int old_empty, move;
	char ch;

	while(1)
	{
		move = 0;
		old_empty = empty;
		ch = getch();
		switch(ch) {
			case 97:    //左移  a
			case 104:   // h
			case 68:    // 左移方向鍵
				for(y = 0; y < 4; y++)
					for(x = 0; x < 4; )
					{
						if(a[y][x] == 0)
						{
							x++;
							continue;
						}
						else
						{
							for(i = x + 1; i < 4; i++)
							{
								if(a[y][i] == 0)
								{
									continue;
								}
								else
								{
									if(a[y][x] == a[y][i])
									{
										a[y][x] += a[y][i];
										a[y][i] = 0;
										empty++;
										break;
									}
									else
									{
										break;
									}
								}
							}
							x = i;
						}
					}
				for(y = 0; y < 4; y++)
					for(x = 0; x < 4; x++)
					{
						if(a[y][x] == 0)
						{
							continue;
						}
						else
						{
							for(i = x; (i > 0) && (a[y][i-1] == 0); i--)
							{
								a[y][i-1] = a[y][i];
								a[y][i] = 1;
								move = 1;
							}
						}
					}
				break;
			case 100:   //右移 d
			case 108:   // l
			case 67:    //右移方向鍵
				for(y = 0; y < 4; y++)
					for(x = 3; x >= 0; )
					{
						if(a[y][x] == 0)
						{
							x--;
							continue;
						}
						else
						{
							for(i = x - 1; i >= 0; i--)
							{
								if(a[y][i] == 0)
								{
									continue;
								}
								else if(a[y][x] == a[y][i])
								{
									a[y][x] += a[y][i];
									a[y][i] = 0;
									empty++;
									break;
								}
								else
								{
									break;
								}
							}
							x = i;
						}
					}
				for(y = 0; y < 4; y++)
					for(x = 3; x >= 0; x--)
					{
						if(a[y][x] == 0)
						{
							continue;
						} else
						{
							for(i = x; (i < 3) && (a[y][i+1] == 0); i++)
							{
								a[y][i+1] = a[y][i];
								a[y][i] = 0;
								move = 1;
							}
						}
					}
				break;
			case 119:   //上移 w
			case 107:   //k
			case 65:    //上移方向鍵
				for(x = 0; x < 4; x++)
					for(y = 0; y < 4; )
					{
						if(a[y][x] == 0)
						{
							y++;
							continue;
						}
						else
						{
							for(i = y + 1; i < 4; i++)
							{
								if(a[i][x] == 0)
								{
									continue;
								}
								else if(a[y][x] == a[i][x])
								{
									a[y][x] += a[i][x];
									a[i][x] = 0;
									empty++;
									break;
								} else
								{
									break;
								}
							}
							y = i;
						}
					}
				for(x = 0; x < 4; x++)
					for(y = 0; y < 4; y++)
					{
						if(a[y][x] == 0)
						{
							continue;
						}
						else
						{
							for(i = y; (i > 0) && (a[i-1][x] == 0); i--)
							{
								a[i-1][x] = a[i][x];
								a[i][x] = 0;
								move = 1;
							}
						}
					}
				break;
			case 115:   //下移 s
			case 106:   //j
			case 66:    //下移方向鍵
				for(x = 0; x < 4; x++)
					for(y = 3; y >= 0; )
					{
						if(a[y][x] == 0)
						{
							y--;
							continue;
						}
						else
						{
							for(i = y - 1; i >= 0; i--)
							{
								if(a[i][x] == 0)
								{
									continue;
								}
								else if(a[y][x] == a[i][x])
								{
									a[y][x] += a[i][x];
									a[i][x] = 0;
									empty++;
									break;
								}
								else
								{
									break;
								}
							}
							y = i;
						}
					}
				for(x = 0; x < 4; x++)
					for(y = 3; y >= 0; y--)
					{
						if(a[y][x] == 0)
						{
							continue;
						}
						else
						{
							for(i = y; (i < 3) && (a[i+1][x] == 0); i++)
							{
								a[i+1][x] = a[i][x];
								a[i][x] = 0;
								move = 1;
							}
						}
					}
				break;
			case 'Q':
			case 'q':
				game_over();
				break;
			default:
				continue;
				break;
		}
		if(empty <= 0)
			game_over();
		if((empty != old_empty) || (move == 1))
		{
			do{
				new_x = rand() % 4;
				new_y = rand() % 4;
			}while(a[new_y][new_x] != 0);

			cnt_value(&new_y, &new_x);

			do {
				temp = rand() % 4;
			}while(temp == 0 || temp == 2);
			a[new_y][new_x] = temp + 1;
			empty--;
		}
		draw();
	}
}
void init()
{
	int x, y;
	initscr();
	cbreak();
	noecho();
	curs_set(0);
	empty = 15;
	srand(time(0));
	x = rand() % 4;
	y = rand() % 4;
	a[y][x] = 2;
	draw();
}
void draw_one(int y, int x)
{
	int i, m, k, j;
	char c[5] = {0x00};
	i = a[y][x];
	m = 0;
	while(i>0)
	{
		j = i %10;
		c[m++] = j + '0';
		i = i / 10;
	}
	m = 0;
	k = (x+1) * 5 - 1;
	while(c[m] != 0x00)
	{
		move(2*y+1, k);
		addch(c[m++]);
		k--;
	}
}
void cnt_value(int *new_y, int *new_x)
{
	int max_x, max_y, x, y, value;
	int max = 0;

	max = cnt_one(*new_y, *new_x);
	for(y = 0; y < 4; y++)
		for(x = 0; x < 4; x++)
		{
			// 如果(y, x)對應的空格爲空
			if(!a[y][x])
			{
				// 優先選取周圍空格最多的空格展示新數字
				value = cnt_one(y, x);
				if(value > max && old_y != y && old_x != x)
				{
					// 避免在同一位置反覆出現新數字
					*new_y = y;
					*new_x = x;
					old_x = x;
					old_y = y;
					break;
				}
			}
		}
}
int game_over()
{
	sleep(1);
	endwin();
	exit(0);
}
int cnt_one(int y, int x)
{
	int value = 0;
	if(y - 1 > 0)
		a[y-1][x] ? 0 : value++;
	if(y + 1 < 4)
		a[y+1][x] ? 0 : value++;
	if(x - 1 >= 0)
		a[y][x-1] ? 0 : value++;
	if(x + 1 < 4)
		a[y][x+1] ? 0 : value++;
	if(y - 1 >= 0 && x - 1 >= 0)
		a[y-1][x-1] ? 0 : value++;
	if(y - 1 >= 0 && x + 1 < 4)
		a[y-1][x+1] ? 0 : value++;
	if(y + 1 < 4 && x - 1 >= 0)
		a[y+1][x-1] ? 0 : value++;
	if(y + 1 < 4 && x + 1 < 4)
		a[y+1][x+1] ? 0 : value++;
	return value;

}
  1. 編寫主函數game_2048.c
#include "head.h"
int main()
{
	init();
	play();
	endwin();
	return 0;
}
  1. 編寫makefile文件
test:game_2048.o head.o
	gcc game_2048.o head.o -o test -lcurses
game_2048.o:game_2048.c
	gcc -c -Wall game_2048.c -o game_2048.o -lcurses
head.o:head.c
	gcc -c -Wall head.c -o head.o -lcurses

.PHONY:clean
clean:
	rm *.o test

  1. 編譯
    make
  2. 結果在這裏插入圖片描述
    [外鏈圖片轉存失敗(img-HlCDoo0v-1565955275132)(picture/1.png)]
    [外鏈圖片轉存失敗(img-NpvIMnir-1565955275134)(picture/2.png)]

2

也可以用Game_2048.c一個文件進行編譯

gcc Game_2048.c -o 2048 -lcurses

[外鏈圖片轉存失敗(img-zIWXnzpJ-1565955275135)(picture/3.png)]

[外鏈圖片轉存失敗(img-ph1SKZxg-1565955275136)(picture/2.png)]
代碼地址:
Github地址
參考:

實驗樓->C 語言製作 2048
C 語言製作 2048

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章