首頁 » 原創 » 正文

[原創]基於C語言的單詞記憶系統

本文以及程序代碼原創,謝絕轉載!
最近的一個項目,練手用的,大概一個星期的開發時間,不過每天寫代碼16小時以上,摺合標準工作時間差不多半個月吧。
是單詞記憶系統,能實現聯網對戰,離線練習,用戶登錄與註冊,排名,自定義簽名,密碼修改,詞庫選擇,新聞顯示,系統管理等功能。通過自帶詞庫的動態查找切割選詞。
指針用的比較多,還算方便,數組和變量開的有點亂,代碼寫的還是比較隨意,我先用的二維數組保存數據,後來用結構體存的。因為都是單詞遍歷的查找,基本上沒有鏈表,然後數據庫連接,網絡通信那塊時間用的比較久,單詞用的文件io,簡易的寫了個匹配,源碼里都有。界面c控制台,函數動態生成的,總代碼量1500+行。
源碼還算詳細。代碼基本做到了顯示和功能的隔離,模塊耦合性嘛,好像開了挺多的全局變量…
涉及隱私問題,全文中學校使用***代替,姓名使用Dmjsz代替。
效果圖

1

2

3

4

5

6

7

8

9

10

數據庫結構

11

12

源代碼

/**-----源碼前置信息----------------------------------|
|    本軟件中文名為單詞世界,英文名為WordWorld,旨在幫助高|
|中生和大學生背誦英語單詞,包括互聯網對戰和獨立練習,並提 |
|供一系列賬號及詞庫解決方案,希望可以真正幫助到想提高英語 |
|水平的同學。                                         |
|    軟件使用編程軟件為MicrosoftVisualStudio2013,開發者|
|為***Dmjsz同學,開發時間是2016年10月17日到2016年10月23 |
|日,系本人第一次使用c語言開發中小型程序,如有不足,請不吝|
|指教。                                              |
|    本軟件系開發者本人獨立開發完成,但在數據庫連接和網絡|
|通信模塊查閱了相關資料,現向曾經提供幫助的朋友表示感謝!|
|由於作者水平有限,代碼風格顯得較為隨意,主要以實現功能為|
|主,數組的開闢也浪費了不少空間,這些問題將可能在以後逐步|
|解決。本代碼僅供研究學習之用,謝絕轉載。               |
|---------------------------------------------------*/

/*包含的頭文件*/
#include <stdio.h>//標準輸入輸出頭文件
#include <string.h> //字符串處理頭文件
#include <stdlib.h> //standard library標準庫頭文件
#include <winsock2.h>//網絡通信頭文件
#include <conio.h>//字符串*號回顯使用
#include "Windows.h"//windows頭文件
#include "mysql.h"//數據庫相關頭文件

/*包含的庫*/
#pragma comment(lib,"libmysql") //數據庫使用
#pragma comment(lib,"ws2_32.lib")//winsock2鏈接的庫

/*數據庫的define定義*/
char host[25]="127.0.0.1";
#define USERNAME "root" //定義數據庫用戶名
#define PASSWORD "11111111" //定義數據庫密碼
#define DATABASE "data" //定義數據庫名

/*全局變量區*/
//定義全局用戶名,用來保存當前用戶
char username[50] = "";

//定義登錄狀態,0表示未登錄,1表示已登錄
int isLoged = 0;

//定義時間戳,在時間比對時使用
long int firstTimer = 0;

//遊戲可以切換不同的服務器,這裡的變
//量用來保存處理服務器的序列號
int server = 1;

//定義詞庫文件的位置指向
char wordPath[50] = "dic//default.ewf";

//定義結構體,保存對戰時自己和對手的資料
struct ag{
	char name[20];//姓名
	char score[5];//分數
};

//定義5個結構體變量
struct ag ag[5] = { { "", "" }, { "", "" }, { "", "" }, { "", "" }, { "", "" } };

//當數據庫讀取信息時,對個人的不同信息沒有採用結構體形式,而是使用#號分割,
//例如#name#score#saying#,所以原本的循環變量不能保存人數,使用agCounter保存,
//又因為,人數在對戰開始的列表和結果都有顯示,所以定義為全局變量。
int agCounter = 0;

int wordAllNum = 3160;

/*函數定義區,不同函數將在每個函數的開頭具體解釋*/
void dush();
void blank();
void word(char * front, char * back);
void getWelcomeFrame();
void getRegFrame();
void getLoginFrame();
void getUserMainFrame();
void worldButtleSearchFrame();
int worldButtleFrame(int right, int stage);
void worldButtleWaitingFrame();
void worldButtleResultFrame();
void getStartFunction(int state);
void dealFile();
char* ipadd();
char* nowTime();
void dealSql(char *old, char *new);
long int timePast();
void scorelist();
void changePassword();
void changeSaying();
void changeNews();
void closeSystem();
void header();
void footer();
void nowTimeForFooter();

/*
列表動態行處理函數
我們把一行分為5個部分,即開始符“|”,左顯示字符區,
中間空格區,右顯示字符區,結束符號“|”,我們給函數
傳入左顯示字符和右顯示字符區,由程序計算剩餘空間,
在中間填滿空格,使程序可以動態處理。
例如:word("hello","world");則:
        | hello                                      world|
 開始符↑ ↑左顯示字符區 ↑中間空格區    右顯示字符區↑  ↑結束符
*/
void word(char * front, char * back){
	int count = strlen(front) + strlen(back);//兩邊字符求和
	if ((count <= 50)){//總字符不超過50
		int left = 57 - count;//剩餘字符數
		char fin[60] = "|  ";//定義60字符,開始是“|”
		char * blank = { " " };
		char * backblack = " |\n";
		strcat(fin, front);//粘貼左顯示字符區到fin
		for (int i = 1; i <= left - 5; i++){
			strcat(fin, blank);
		}//粘貼空格
		strcat(fin, back);//粘貼右顯示字符區到fin
		strcat(fin, backblack);
		printf("%s", fin);//打印整行
	}
	else{
		word("發生意外:傳遞的字符串超過最大長度", "");//溢出處理
		dush();
	}
}
//全行空白的情況
void blank(){
	printf("|");
	for (int i = 1; i <= 55; i++)printf(" ");
	printf("|\n");
}
//全行橫線分隔符
void dush(){
	printf("|");
	for (int i = 1; i <= 55; i++)printf("-");
	printf("|\n");
}
//定義頭部顯示
void header(){
	dush();
	word("單詞世界WordWorld", "Dmjsz製作");
	dush();
	blank();
}
//定義尾部顯示
void footer(){
	blank();
	dush();
	nowTimeForFooter();
	dush();
}
//頭部專用時間處理函數
void nowTimeForFooter(){
	SYSTEMTIME sys;
	GetLocalTime(&sys);
	char temptimer[10] = "";
	char timer[30] = "";
	//分別獲取年月日時分秒,保存到數組中
	int item[6] = { sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond };
	for (int i = 0; i <= 5; i++){//遍曆數組
		//將數字轉換為字符數組,否則沒法使用strcat函數
		_itoa(item[i], temptimer, 10);
		//年與月和月與日之間使用“-”分割
		if (i == 1 || i == 2){ 
			strcat(timer, "-"); 
		}
		//日與時之間使用空格分割
		else if (i == 3){ 
			strcat(timer, " ");
		}
		//時與分和分與秒之間使用“:”分割
		else if (i == 4 || i == 5){ 
			strcat(timer, ":");
		}
		//如果小於10的數字則前面補0
		if (item[i] <= 9){ 
			strcat(timer, "0"); 
		}
		strcat(timer, temptimer);
	}
	word("CopyRight 2016 dmjsz", timer);
}
//數據庫專用時間處理函數
//總體與前一個函數相似
char* nowTime(int state){
	SYSTEMTIME sys;
	GetLocalTime(&sys);
	char temptimer[10] = "";
	char timer[30] = "";
	int item[6] = { sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond };
	for (int i = 0; i <= 5; i++){
		_itoa(item[i], temptimer, 10);
		if (i == 1 || i == 2){ 
			strcat(timer, "-"); 
		}
		else if (i == 3){ 
			strcat(timer, " "); 
		}
		else if (i == 4 || i == 5){
			strcat(timer, ":"); 
		}
		if (item[i] <= 9){
			strcat(timer, "0"); 
		}
		strcat(timer, temptimer);
	}
	char date[11] = "";
	strncpy(date, timer, 10);
	switch (state){
	case 1:return timer; break;
	case 2:return date;
	}
}
/*測定時間流逝的函數*/
long int timePast(){
	SYSTEMTIME sys;
	GetLocalTime(&sys);
	long int secondR = sys.wDay * 60 * 60 * 24 + sys.wHour * 60 * 60 + sys.wMinute * 60 + sys.wSecond;
	return secondR;
}
/*SQL查詢函數*/
char* query_sql(char* sql) {
	char result[30000] = "";
	MYSQL my_connection;//一個數據庫連接
	int res;//sql返回位
	MYSQL_RES *res_ptr;//查詢結果指針
	MYSQL_FIELD *field;//字段結構指針
	MYSQL_ROW result_row;//按照行返回查詢信息
	int row, column;//返回行數與列數
	int i, j;//循環控制變量
	mysql_init(&my_connection);//初始化連接
	if (mysql_real_connect(&my_connection, host, USERNAME, PASSWORD,
		DATABASE, 0, NULL, CLIENT_FOUND_ROWS)) {//不為空連接成功
		mysql_query(&my_connection, "set names utf8");//支持中文
		res = mysql_query(&my_connection, sql);
		if (res) {
			word("數據庫查詢連接失敗!", "");
			mysql_close(&my_connection);//關閉連接
		}
		else {
			res_ptr = mysql_store_result(&my_connection);
			if (res_ptr) {
				column = mysql_num_fields(res_ptr);
				row = mysql_num_rows(res_ptr) + 1;
	            //以行的形式輸出結果
				for (i = 1; i < row; i++) {
					result_row = mysql_fetch_row(res_ptr);
					for (j = 0; j < column; j++){
						strcat(result, "#");
						strcat(result, result_row[j]);
					}
				}
			}
			strcat(result, "#");
			mysql_close(&my_connection);
			char *p = result;
			return p;
		}
	}
}
/*SQL執行函數,與插入類似,相同注釋不再描述*/
void exe_sql(char* sql) {
	MYSQL my_connection;
	int res;
	mysql_init(&my_connection);
	if (mysql_real_connect(&my_connection, host, USERNAME, PASSWORD,
		DATABASE, 0, NULL, CLIENT_FOUND_ROWS)) {
		mysql_query(&my_connection, "set names utf8");
		res = mysql_query(&my_connection, sql);
		if (res) {
			mysql_close(&my_connection);
		}
		else {
			mysql_close(&my_connection);
		}
	}
	else {
		word("數據庫執行結果失敗!", "");
	}
}
/*查詢ip函數*/
char* ipadd()
{
	WSADATA wsaData;
	char name[255];
	char *ip;
	PHOSTENT hostinfo;
	if (WSAStartup(MAKEWORD(2, 0), &wsaData) == 0) {
		if (gethostname(name, sizeof(name)) == 0) {
			if ((hostinfo = gethostbyname(name)) != NULL) {
				ip = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
				return ip;
			}
		}
		WSACleanup();
	}
}
/*更改詞庫函數*/
void changeDic(){
	system("cls");
	header();
	word("請選擇需要更換的詞庫類別", "");
	blank();
	word("輸入序號並回車!", "");
	word("1--->大學英語4級", "");
	word("2--->大學英語6級", "");
	footer();
	char c = getchar()-'0';
	switch (c){
	case 1:strcpy(wordPath, "dic//4.ewf");
		wordAllNum = 3160;
		word("更換完成!",""); 
		Sleep(2000); 
		getUserMainFrame(1);
		break;
	case 2:strcpy(wordPath, "dic//6.ewf");
		wordAllNum = 1285;
		word("更換完成!", "");
		Sleep(2000); 
		getUserMainFrame(1);
		break;
	default:
		word("選擇錯誤!", "");
		Sleep(2000); 
		changeDic();
	}
	
}
/*
獲取開始窗口,其實函數形參等待接受不同的階段,
本函數本身不執行,而是專門給getStartFunction函數執行的
*/
int getStartFrame(int state){
	//Windows API,取得句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//定義控制台顏色為純白
	SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED 
		| FOREGROUND_GREEN | FOREGROUND_BLUE);
	//清空屏幕
	system("cls");
	header();
	switch (state){
	case 1:
		word("------>正在檢查網絡情況...", ""); 
		break;

	case 2:
		word("        網絡連通正常,數據傳輸速度正常!", ""); 
		blank();
		word("------>正在檢查核心組件...", ""); 
		break;
	case 3:
		word("        網絡連通正常,數據傳輸速度正常!", "");
		blank();
		word("        組件測試通過,核心文件正常!", ""); 
		blank();
		word("------>正在與遠程服務器進行握手...   ", "");
		break;
	case 4:
		word("        網絡連通正常,數據傳輸速度正常!", ""); 
		blank();
		word("        組件測試通過,核心文件正常!", "");
		blank();
		word("        與服務器握手成功,沒有更新信息!", ""); 
		blank();
		word("------>正在等待數據傳輸完畢...", ""); 
		break;
	case -2:
		word("        網絡連通異常,請檢查網絡是否正確連接!", "");
		break;
		break;
	case -3:
		word("        網絡連通正常,數據傳輸速度正常!", ""); blank();
		word("        缺少必要的核心組件!", ""); break;
	case -4:
		word("        網絡連通正常,數據傳輸速度正常!", ""); blank();
		word("        組件測試通過,核心文件正常!", ""); blank();
		word(" ------>沒有正確的和遠程服務器取得聯繫!", ""); blank();
		word("        請輸入一個新的數據服務器地址,回車確認!", "");
		footer();
		gets(host);
		getStartFunction(2);
		break;
	}
	footer();
	return 0;
}
/*
開始函數,各項功能檢查,也是程序的起點
*/
void getStartFunction(int state){
	FILE * fp;
	switch (state){
	case 1:
		printf("正在檢查網絡連通情況,請稍後...");
		//114.114.114.114是中國電信DNS,用它來測試網絡連通性
		if (system("ping -n 1 114.114.114.114")){//如果返回值是0
			getStartFrame(-2);//網絡不通
		}
		else{ 
			getStartFrame(2);//打開第二個檢查窗口 
			Sleep(2000); 
			getStartFunction(2); //開始檢查第二項
		} 
		break;
	case 2:
		fp = fopen(wordPath, "r");//測試詞庫文件是否存在
		if (fp == NULL) { 
			getStartFrame(-3); 
		}
		else { fclose(fp);//關閉詞庫
		Sleep(2000); 
		getStartFrame(3); //打開第三個檢查窗口
		getStartFunction(3); //開始檢查第三項
		}
		break;
	case 3:
		if (query_sql("select * from user;") == NULL){ //檢查數據庫是否連通
			getStartFrame(-4);
		}
		else { 
			Sleep(2000);
			getStartFrame(4); 
			getStartFunction(4);
		}
		break;
	case 4:{
			   Sleep(2000);
			   getWelcomeFrame(1); }//所有檢查通過,進入歡迎頁面
	}
}
/*
歡迎屏幕的滾動效果
*/
void getWelcomeFunction(){
	char welword[21] = "Welcome To WordWorld";//定義字符串
	char *p1 = welword;
	char container[21] = "";
	char *p2 = container;
	//屏幕逐個字符顯示效果,定義p1指針指向原字符串,
	//p2指針指向空的新字符串,每隔0.2秒拷貝一個字符,
	//實現字母滾動效果
	while (*p1 != 0){
		Sleep(200);
		system("cls");
		*p2 = *p1;
		p1 += 1; 
		p2 += 1;
		dush();
		word(container, "歡迎來到單詞世界!");
	}
	blank();
	word("您需要登錄賬戶與全世界的朋友一起並肩作戰!", "");
	blank();
	word("創立賬戶請按[N],登錄已有賬戶請按[L]", "");
	blank();
	word("--->服務大區:南方電信專區  切換[C]", "");
	blank();
	footer();
}
/*
歡迎屏幕的框架
*/
void getWelcomeFrame(int area){
	if (area == 1){//如果不檢查area,每次切換大區就要重啟本函數,
		           //那麼滾動效果也就要再出現一次,顯然沒有這樣的必要,
			       //所以,只在第一次顯示歡迎屏幕的時候播放字符滾動效果
		char welword[21] = "Welcome To WordWorld";
		char *p1 = welword;
		char container[21] = "";
		char *p2 = container;
		while (*p1 != 0){
			Sleep(200);
			system("cls");
			*p2 = *p1; 
			p1 += 1;
			p2 += 1;
			dush();
			word(container, "歡迎來到單詞世界!");
		}
	}
	else{
		system("cls");
		dush();
		word("Welcome To WordWorld", "歡迎來到單詞世界!");
	}
	blank();
	word("您需要登錄賬戶與全世界的朋友一起並肩作戰!", "");
	blank();
	word("創立賬戶請按[N],登錄已有賬戶請按[L],關閉請按[X]", "");
	blank();
	if (area % 2 == 1){ //南方北方輪換顯示
		word("--->服務大區:南方電信專區  切換[C]", ""); 
		server = 1;
	}
	else{ 
		word("--->服務大區:北方網通專區  切換[C]", ""); 
		server = 2;
	}
	blank();
	footer();
	//獲取字符輸入
	while (!_kbhit())break;
	char  f = _getch();

	if (f == 'C' || f == 'c'){ 
		getWelcomeFrame(area + 1); 
	}
	if (f == 'X' || f == 'x'){
		exit(0);
	}
	if (f == 'N' || f == 'n'){ 
		getRegFrame(1);
	}
	if (f == 'L' || f == 'l'){ 
		getLoginFrame(1); 
	}
	getWelcomeFrame(1);
}
/*
註冊賬號函數
當state=1時是輸入用戶名的操作,state=2時是確認密碼的操作
*/
void getRegFrame(int state){

	switch (state){
	case 1:	system("cls");
		header();
		word("註冊賬號", "");
		blank();
		word("------>請輸入您的用戶名,回車確認", ""); 
		blank();
		word("       稍後將輸入密碼", ""); 
		blank(); 
		
		footer();
	
		while (1){
			gets(username);
			if (strlen(username) <= 15){ 
				getRegFrame(2);//轉入密碼輸入流程 
			}
			else{ //判斷字符防止過大
				printf("請輸入少於15個字符的用戶名!"); 
			}
		}
	case 2:system("cls"); header();
		word("註冊賬號", "");
		blank();
		char tempstr[200] = "";
		strcat(tempstr, "你好,");
		strcat(tempstr, username);
		strcat(tempstr, "。歡迎加入我們!");
		word(tempstr, ""); blank();
		word("------>請輸入您的密碼,回車確認!", "");
		blank();
		footer();
		while (1){
			//密碼顯示*號
			char password[50] = "";
			char add[200] = "";
			char ch = '\0';
			int i = 0;
			while (ch != '\r')
			{
				ch = _getch();

				if (ch == '\r')
				{
					password[i] = '\0';
					break;
				}
				if (ch != '\b')
				{
					putchar('*');
					password[i] = ch;
					i++;
				}
				else
				{
					getRegFrame(2);
				}
			}
			printf("\n");
			printf("正在查詢遠程數據表...... \n");
			//向數據庫插入新用戶數據,同時在配置數據庫時,注意把
			//username字段設置為唯一,當已存在同名用戶時,新用戶
			//將無法創建。
			if (strlen(password) <= 15){
				char p[200] = "insert into user(username,password,\
							  	      saying,ipadd,lastlogin) values('";
				strcat(p, username);
				strcat(p, "','");
				strcat(p, password);
				strcat(p, "','");
				strcat(p, "No Saying!");
				strcat(p, "','");
				strcat(p, ipadd());
				strcat(p, "','");
				strcat(p, nowTime(1));
				strcat(p, "');");
				char *exe = p;
				exe_sql(exe); 
				getLoginFrame(1);
			}
			else{ 
				printf("請輸入少於15個字符的密碼!");
			}
		}
	}
}
/*
登錄賬號函數
當state=1時是輸入用戶名的操作,state=2時是確認密碼的操作
*/
void getLoginFrame(int state){
	switch (state){
	case 1:	system("cls");
		header();
		word("登陸賬號", "");
		blank();
		word("------>請輸入您的用戶名,回車確認", ""); 
		blank();
		word("       稍後將輸入密碼", ""); 
		blank(); 
		blank(); 
		dush();
		char temp[11] = "";
		strcpy(temp, nowTime(2));
		word("CopyRight 2016 dmjsz", temp); 
		dush();
		while (1){
			gets(username);
			if (strlen(username) <= 15){ 
				getLoginFrame(2); 
			}
			else{ 
				printf("請輸入少於15個字符的用戶名!"); //判斷字符防止過大
			}
		}

	case 2:system("cls");
		header();
		word("登錄賬號", "");
		blank();
		char tempstr[200] = "";
		strcat(tempstr, "你好,");
		strcat(tempstr, username);
		strcat(tempstr, "。歡迎回來!");
		word(tempstr, ""); 
		blank();
		word("------>請輸入您的密碼,回車確認!", ""); 
		blank();
		footer();
		if (isLoged == 0){//當沒有登錄時
			char password[50] = "";
			char sqlw[200] = "";
			char ch = '\0';
			int i = 0;
			//密碼顯示*號
			while (ch != '\r')
			{
				ch = _getch();

				if (ch == '\r')
				{
					password[i] = '\0';
					break;
				}
				if (ch != '\b')
				{
					putchar('*');
					password[i] = ch;
					i++;
				}
				else
				{
					getLoginFrame(2);

				}
			}
			printf("\n");
			//執行登錄語句
			if (strlen(password) <= 15){
				char sqlw[200] = "";
				char *p;
				printf("正在查詢遠程數據表...... \n");
				strcat(sqlw, "select password from user where username='");
				strcat(sqlw, username);
				strcat(sqlw, "';");
				p = query_sql(sqlw);
				char temp[20] = "";
				dealSql(p, temp);
				if (strcmp(password, temp) == 0){
					printf("登錄成功");
					isLoged = 1;
					getUserMainFrame(1);
					return;
				}
				else{
					printf("登陸失敗,任意鍵繼續!");
					getchar();
					getLoginFrame(2);
				}
			}
			else{ printf("請輸入少於15個字符的密碼!");
			}
			getWelcomeFrame(1);
		}
	}
}
/*
主窗口函數
*/
void getUserMainFrame(int state){
	switch (state){
	case 1:	system("cls");
		char news1[80] = "";
		char news2[80] = "";
		char score[200] = "";
		char coin[10] = "";
		char sqlw[200] = "";
		char systemstate[50] = "";
		//定義大量數組保存不同數據!
		char dealSqlStr[200] = "";
		char dealSqlStr2[200] = "";
		char dealSqlStr3[200] = "";
		char dealSqlStr4[200] = "";
		char dealSqlStr5[200] = "";
		char dealSqlStr6[200] = "";
		char lastlogin[200] = "";
		char stage[200] = "";
		printf("正在查詢遠程數據表...... \n");
		//查新新聞1
		strcpy(sqlw, "select news1 from system where version=1;");
		dealSql(query_sql(sqlw), dealSqlStr);
		strcpy(news1, dealSqlStr);
		//查新聞2
		strcpy(sqlw, "select news2 from system where version=1;");
		dealSql(query_sql(sqlw), dealSqlStr6);
		strcpy(news2, dealSqlStr6);
		//獲取系統狀態
		strcpy(sqlw, "select systemstate from system where version=1;");
		dealSql(query_sql(sqlw), dealSqlStr5);
		strcpy(systemstate, dealSqlStr5);
		//如果系統狀態為0,表示整個系統被關閉,
		//那麼除了admin其它用戶將不能進入
		if ((strcmp(systemstate, "0") == 0) && (strcmp(username, "admin") != 0)){
			printf("系統已被管理員關閉!\n請聯繫管理員!\n任意鍵退出!\n");
			getchar();
			exit(0);
		}
		//向數據表查詢用戶信息
		//查詢用戶分數
		strcpy(sqlw, "select score from user where username='");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		dealSql(query_sql(sqlw), dealSqlStr4);
		strcpy(score, dealSqlStr4);
		//查詢用戶硬幣
		strcpy(sqlw, "select coin from user where username='");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		dealSql(query_sql(sqlw), dealSqlStr2);
		strcpy(coin, dealSqlStr2);
		//查詢用戶最後登錄時間
		strcpy(sqlw, "select lastlogin from user where username='");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		dealSql(query_sql(sqlw), dealSqlStr2);
		strcpy(lastlogin, dealSqlStr2);
		//查詢用戶等級
		strcpy(sqlw, "select stage from user where username='");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		dealSql(query_sql(sqlw), dealSqlStr3);
		strcpy(stage, dealSqlStr3);
		//更新登錄時間
		strcpy(sqlw, "update user set lastlogin='");
		strcat(sqlw, nowTime(1));
		strcat(sqlw, "' where username = '");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		char *exe = sqlw;
		exe_sql(exe);
		//更新用戶ip地址
		strcpy(sqlw, "update user set ipadd='");
		strcat(sqlw, ipadd());
		strcat(sqlw, "' where username = '");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		*exe = sqlw;
		exe_sql(exe);
		system("cls");
		//定義控制台大小
		system("mode con cols=58 lines=32");
		header();
		word("全區新聞", "");
		word(news1, "");
		word(news2, "");
		dush(); blank();
		char temp[200] = "   歡迎!";
		strcat(temp, username);
		strcat(temp, ",最近登錄時間:");
		strcat(temp, lastlogin);
		word(temp, "");
		char info[200] = "   等級--->";
		strcat(info, stage);
		strcat(info, "   積分--->");
		strcat(info, score);
		word(info, "");
		char info2[200] = "";
		strcat(info2, "   硬幣--->");
		strcat(info2, coin);
		word(info2, "");
		dush(); blank();
		word("                請選擇功能:", ""); 
		blank();
		word("         世界對戰[B]", "賽外練習[P]               ");
		blank();
		word("         大區排名[L]", "詞庫管理[R]               ");
		blank();
		word("         修改口號[S]", "修改密碼[W]               ");
		blank();
		word("         註冊用戶[M]", "切換用戶[C]               "); 
		blank();
		if (strcmp(username, "admin") == 0){//只有是管理員才顯示系統相關的更改選項
			word("         修改新聞[N]", "關閉系統[E]               ");
			blank();
		}
		footer();
		//獲取用戶輸入
		while (!_kbhit())break;
		char  f = _getch();
		if (f == 'X' || f == 'x'){ 
			exit(0); 
		}
		if (f == 'B' || f == 'b'){
			worldButtleSearchFrame();
		}
		if (f == 'P' || f == 'p'){ 
			practiceFrame(1, 0);
		}
		if (f == 'L' || f == 'l'){ 
			scorelist(); }
		if (f == 'R' || f == 'r'){ 
			changeDic();
		}
		if (f == 'W' || f == 'w'){ 
			changePassword(); 
		}
		if (f == 'S' || f == 's'){ 
			changeSaying(); 
		}
		if (f == 'M' || f == 'm'){ 
			isLoged = 0; 
			getRegFrame(1);
		}
		if (f == 'C' || f == 'c'){ 
			isLoged = 0; 
			getLoginFrame(1); 
		}
		if (strcmp(username, "admin") == 0){//如果是管理員
			if (f == 'N' || f == 'n'){ 
				changeNews(); 
			}
			if (f == 'E' || f == 'e'){ 
				closeSystem(); 
			}
		}
		getUserMainFrame(1);
	}
}
/*
管理員更改新聞函數,涉及到數據庫插入
*/
void changeNews(){
	system("cls");
	printf("請問你要更改第幾條新聞?按數字1或2回答。\n");
	while (!_kbhit())break;
	char  f = _getch();
	if (f == '1'){
		printf("請輸入第一條新聞內容:\n");
		char content[55] = "";
		gets(content);
		if (strlen(content) < 50){
			char sqlw[200] = "update system set news1='";
			strcat(sqlw, content);
			strcat(sqlw, "';");
			char *exe = sqlw; exe_sql(exe);
			printf("新聞更改完畢!任意鍵確認!\n");
			getchar();
			getUserMainFrame(1);
		}
		else{

			printf("請輸入少於50個字符的新聞!任意鍵確認!\n");
			getchar();
			changeNews();
		}
	}
	if (f == '2'){
		printf("請輸入第二條新聞內容:\n");
		char content[55] = "";
		gets(content);
		if (strlen(content) < 50){
			char sqlw[200] = "update system set news2='";
			strcat(sqlw, content);
			strcat(sqlw, "';");
			char *exe = sqlw; exe_sql(exe);
			printf("新聞更改完畢!任意鍵確認!\n");
			getchar();
			getUserMainFrame(1);
		}
		else{
			printf("請輸入少於50個字符的新聞!任意鍵確認!\n");
			getchar();
			changeNews();
		}
	}
	changeNews();
}
/*
關閉系統的函數,主要是修改system表中的systemstate字段
*/
void closeSystem(){
	system("cls");
	char sqlw[200] = "";
	char systemstate[50] = "";
	char dealSqlStr[200] = "";
	strcpy(sqlw, "select systemstate from system where version=1;");
	dealSql(query_sql(sqlw), dealSqlStr);
	strcpy(systemstate, dealSqlStr);
	if (strcmp(systemstate, "1") == 0){
		printf("警告!關閉系統後所有用戶不能正常登錄!\n");
		printf("輸入Y確定,輸入N取消!\n");
		while (!_kbhit())break;
		char  f = _getch();
		if (f == 'N' || f == 'n'){ 
			getUserMainFrame(1);
		}
		if (f == 'Y' || f == 'y'){
			char p[100] = "update system set systemstate=0";
			char *exe = p; exe_sql(exe);
			printf("系統已經關閉!任意鍵返回!\n");
			getchar();
			getUserMainFrame(1);
		}
	}
	if (strcmp(systemstate, "0") == 0){
		printf("是否開啟系統?\n");
		printf("輸入Y確定,輸入N取消!\n");
		while (!_kbhit())break;
		char  f = _getch();
		if (f == 'N' || f == 'n'){ getUserMainFrame(1); }
		if (f == 'Y' || f == 'y'){
			char p[100] = "update system set systemstate=1";
			char *exe = p; exe_sql(exe);
			printf("系統已經開啟!任意鍵返回!\n");
			getchar();
			getUserMainFrame(1);
		}
	}
}

/*
用戶修改自己的口號
*/
void changeSaying(){
	system("cls");
	header();
	word("請輸入新的口號,回車確定!", "");
	footer();
	char sqlw[200] = "";
	char newPassword[50] = "";
	gets(newPassword);
	if (strlen(newPassword) >= 15){
		printf("請輸入小於15個字符的口號!任意鍵繼續!");
		getchar();
		changePassword();
	}
	else{
		strcpy(sqlw, "update user set saying='");
		strcat(sqlw, newPassword);
		strcat(sqlw, "' where username = '");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		char *exe = sqlw;
		exe_sql(exe);
		printf("口號更改成功!任意鍵繼續!");
		getchar();
		getUserMainFrame(1);
	}
}
/*
用戶更改自己的密碼
*/
void changePassword(){
	system("cls");
	dush();
	word("單詞世界WordWorld", "Dmjsz製作[X]"); dush(); blank();
	word("請輸入新的密碼,回車確定!", ""); blank();
	footer();
	char sqlw[200] = "";
	char newPassword[50] = "";
	char ch = '\0';
	int i = 0;
	while (ch != '\r')
	{
		ch = _getch();

		if (ch == '\r')
		{
			newPassword[i] = '\0';
			break;
		}
		if (ch != '\b')
		{
			putchar('*');
			newPassword[i] = ch;
			i++;
		}
		else
		{
			changePassword();
		}
	}
	printf("\n");
	if (strlen(newPassword) >= 15){
		printf("請輸入小於15個字符的密碼!任意鍵繼續!");
		getchar();
		changePassword();
	}
	else{
		strcpy(sqlw, "update user set password='");
		strcat(sqlw, newPassword);
		strcat(sqlw, "' where username = '");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		char *exe = sqlw;
		exe_sql(exe);
		printf("密碼更改成功!任意鍵繼續!");
		getchar();
		getUserMainFrame(1);
	}
}
//顯示排名最高的6個用戶
void scorelist(){
	char sqlw[200] = "";
	char dealSqlStr[2000] = "";
	char list[2000] = "";
	strcpy(sqlw, "SELECT username, score,saying FROM user \
		ORDER BY score DESC LIMIT 0 , 6;");
	strcpy(dealSqlStr, query_sql(sqlw));
	strcpy(list, dealSqlStr);
	char strCollection2[300][200] = { "" };
	char *p = dealSqlStr;
	int i = 0; 
	int j = 0; 
	int k = 0;
	while (k < strlen(dealSqlStr)){
		if (k == 0){ i++;
		k++; 
		continue;
		}
		if (*p != '#'){ 
			strCollection2[i][j] = *p;
			p++; 
			j++; 
		}
		else{ 
			p++; 
			i++; 
			j = 0; 
		}
		k++;
	}
	int count = 0;
	char temp[200] = "";
	system("mode con cols=58 lines=30");
	header();
	for (i = 0; i < 30; i++){
		for (j = 0; j < 20; j++){
			if (strCollection2[i][j] == NULL)continue;
			if (j == 0){
				count++;
				if (count == 1){
					strcat(temp, "第");
					char temp3[10] = "";
					_itoa((i + 1) / 3, temp3, 10);
					strcat(temp, temp3);
					strcat(temp, "名,名稱:");
					strcat(temp, &strCollection2[i][j]);
					strcat(temp, "  積分:");
				}
				if (count == 2){
					strcat(temp, &strCollection2[i][j]);
				}
				if (count == 3){
					strcpy(temp, "簽名:");
					strcat(temp, &strCollection2[i][j]);
					strcat(temp, "。");
				}
				if (count == 2){ word(temp, ""); }
				if (count == 3){
					word(temp, "");
					blank();
					count = 0;
					strcpy(temp, "");
				}
			}
		}
	}
	dush();
	strcpy(temp, nowTime(2));
	word("按q鍵返回主界面!", "");
	footer();
	while (!_kbhit())break;
	char  f = _getch();
	if (f == 'Q' || f == 'q'){ getUserMainFrame(1); }
}
/*
世界對戰搜索頁面
*/
void worldButtleSearchFrame(){
	system("cls");
	system("mode con cols=58 lines=28");
	header();
	word("搜索對手中...", "");
	blank(); dush();
	word("已經找到的對手:", "");
	blank();
	char agname[500] = "";
	char sqlw[200] = "";
	char old[500] = "";
	strcpy(sqlw, "update user set buttlestate=1");
	strcat(sqlw, " where username = '");
	strcat(sqlw, username);
	strcat(sqlw, "';");
	char *exe = sqlw;
	exe_sql(exe);
	//獲取用戶的對戰狀態
	strcpy(sqlw, "select username,score,saying from user where buttlestate=1;");
	strcpy(agname, query_sql(sqlw));
	strcpy(old, agname);
	char strCollection[30][20] = { "" };
	char *p = agname;
	int i = 0; 
	int j = 0; 
	int k = 0;
	while (k < strlen(agname)){
		if (k == 0){ i++;
		k++; 
		continue; }
		if (*p != '#'){ 
			strCollection[i][j] = *p;
			p++; 
			j++; }
		else{ p++; 
			i++; 
			j = 0; }
		k++;
	}
	int count = 0;
	char temp[200] = "";
	for (i = 0; i < 30; i++){

		for (j = 0; j < 20; j++){
			//如果姓名為null表示沒有對手了
			if (strCollection[i][j] == NULL)continue;
			if (j == 0){
				count++;
				if (count == 1){
					strcat(temp, "--->對手姓名:");
					strcat(temp, &strCollection[i][j]);
					strcpy(ag[agCounter].name, &strCollection[i][j]);
					strcat(temp, "  對手積分:");
				}
				if (count == 2){
					strcat(temp, &strCollection[i][j]);
					strcpy(ag[agCounter].score, &strCollection[i][j]);
					agCounter++;
				}
				if (count == 3){
					strcpy(temp, "    個性簽名:");
					strcat(temp, &strCollection[i][j]);
					strcat(temp, "。");
				}
				if (count == 2){ word(temp, ""); }
				if (count == 3){
					word(temp, "");
					blank();
					count = 0;
					strcpy(temp, "");
				}
			}
		}
	}
	footer();
	int second = 0; //秒數
	int person = 0;//對戰人數
	//每過5秒刷新一次
	for (second = 60;second >= 0; second -= 5){
		strcpy(agname, query_sql(sqlw));
		if (strcmp(old, agname) != 0){
			worldButtleSearchFrame();
		}
		strcpy(old, agname);
		person++;
		Sleep(5000);
	}
	if (person == 0){//如果沒有人對戰
		printf("等待超時,任意鍵返回!");
		getchar();
		getUserMainFrame(1);
	}
	else{
		worldButtleFrame(0, 1);
	}
}
/*
由於數據庫查詢的數據是帶有#號分割的,這個函數專門是去掉#號的
*/
void dealSql(char *old, char *new){
	char *p1 = "";
	char *p2 = "";
	p1 = old;
	p2 = new;
	while (*p1 != NULL){
		if (*p1 != '#'){
			*p2 = *p1; 
			p2++; };
		p1++;
	}
	strcat(new, "\0");
	strcat(old, "\0");
}
/*
處理詞庫文件函數
由於我從網上下載的詞庫帶有音標
例如 book /book/ .書
所以這個函數將字符串開頭到第一個/符號作為單詞
第一個.到結尾作為翻譯保存
*/
void dealFile(int i, char* english, char *chinese){

	FILE *fp;
	int WhichLine = i;
	int CurrentIndex = 0;
	char StrLine[1024];
	if ((fp = fopen(wordPath, "r")) == NULL)
	{
		printf("詞庫文件不存在!"); return NULL;
	}
	while (!feof(fp))
	{
		if (CurrentIndex == WhichLine)
		{
			fgets(StrLine, 1024, fp);
			break;
		}
		fgets(StrLine, 1024, fp);
		CurrentIndex++;
	}
	fclose(fp);
	char *p1; 
	char *p2; 
	int pos = 0; 
	int first = 0; 
	int second = 0;
	int fristMark = 0; 
	int secondMark = 0;
	int third = 0;
	int thirdMark = 0;
	p1 = StrLine;
	while (pos <= strlen(StrLine)){
		if (*p1 == '/'&&first == 0){ 
			fristMark = 1; //記錄第一標記位
			first = pos; 
		}
		if (*p1 == '.'&&secondMark == 0){
			secondMark = 1; //記錄第二標記位
			second = pos; 
		}
		if (*p1 == '\n'&&thirdMark == 0){ 
			thirdMark = 1; //記錄第三標記位
			third = pos;
		}
		p1++; 
		pos++;
	}
	char temp1[200] = "";
	strncpy(temp1, StrLine, first);
	strcat(temp1, "\0");
	char temp2[200] = "";
	strncpy(temp2, StrLine + second + 1, third);
	strcat(temp2, "\0");
	strcpy(english, temp1);
	strcpy(chinese, temp2);
}

/*
對戰函數
對戰時,反覆遞歸調用,並傳入新的值以控制比賽
*/
int worldButtleFrame(int right, int stage){
	if (stage == 1){
		//如果處在第一階段,那麼首先清空對戰狀態,以防止其它對手的匹配
		char sqlw[200] = "";
		firstTimer = timePast();
		strcpy(sqlw, "update user set buttlestate=0");
		strcat(sqlw, " where username = '");
		strcat(sqlw, username);
		strcat(sqlw, "';");
		char *exe = sqlw;
		exe_sql(exe);
	}
	system("cls");
	system("mode con cols=58 lines=22");
	header();
	char sign[200] = "還剩下";
	char num[5] = "";
	_itoa(10 - stage, num, 10);
	strcat(sign, num);
	strcat(sign, "題!,時間還有");
	strcpy(num, "");
	long int temp = timePast();
	_itoa(180 - (temp - firstTimer), num, 10);
	strcat(sign, num);
	strcat(sign, "秒");
	word(username, sign);
	dush(); blank();
	word("請根據中文寫出英文對應的單詞", ""); blank();
	char a[100] = "aaa"; char b[100] = "bbb";
	//隨機數抽取題號
	int rd = rand() % wordAllNum;
	//抽取中文和英文
	dealFile(rd, a, b);
	char letter[20] = "<---共";
	strcpy(num, "");
	_itoa(strlen(a), num, 10);
	strcat(letter, num);
	strcat(letter, "個字母!");
	word(b, letter);
	blank(); 
	dush();
	word("請輸入單詞,回車確定:", "");
	footer();
	char userenter[200] = "";
	gets(userenter);
	if (stage >= 10){ 
		//當題目計數大於10的時候開始進入等待界面
		worldButtleWaitingFrame(right, username);
		return 0; }
	if (strcmp(userenter, a) == 0){
		printf("正確!"); 
		Sleep(500); 
		right++; 
		stage++; 
		worldButtleFrame(right, stage);
	}
	else{ 
		printf("錯誤!\n"); 
		printf("正確答案:%s", a); 
		Sleep(2000); 
		stage++; 
		worldButtleFrame(right, stage); 
	}
}
/*
練習模塊函數
就是不需要等待匹配對手,沒有時間限制
*/
int practiceFrame(int right, int stage){
	system("cls");
	system("mode con cols=58 lines=22");
	header();
	char sign[200] = "還剩下";
	char num[5] = "";
	_itoa(10 - stage, num, 10);
	strcat(sign, num);
	strcat(sign, "題!");
	word(username, sign);
	dush(); blank();
	word("請根據中文寫出英文對應的單詞", ""); blank();
	char a[100] = "aaa"; char b[100] = "bbb";
	int rd = rand() % wordAllNum;
	dealFile(rd, a, b);
	char letter[20] = "<---共";
	strcpy(num, "");
	_itoa(strlen(a), num, 10);
	strcat(letter, num);
	strcat(letter, "個字母!");
	word(b, letter);
	blank(); dush();
	word("請輸入單詞,回車確定:", "");
	footer();
	char userenter[200] = "";
	gets(userenter);
	if (stage >= 10){ 
		getUserMainFrame(1);
		return 0; 
	}
	if (strcmp(userenter, a) == 0){ 
		printf("正確!"); 
	Sleep(500); 
	right++; 
	stage++; 
	practiceFrame(right, stage); 
	}
	else{ printf("錯誤!\n"); 
	printf("正確答案:%s", a);
	Sleep(2000); 
	stage++;
	practiceFrame(right, stage);
	}
}
/*
等待對手完成的函數
在這期間會進行分數比對工作,超時將不能參與排名
*/
void worldButtleWaitingFrame(int right, char *username){
	char sqlw[200] = "";
	char agname[200] = "";
	char score[10] = "";
	int scoreInt = 0;
	int tempInt = 0;
	strcpy(sqlw, "select score from user where username='");
	strcat(sqlw, username);
	strcat(sqlw, "';");
	strcpy(score, query_sql(sqlw));
	char dealSqlInt[10] = "";
	//單獨對sql的#號處理
	strncpy(dealSqlInt, score + 1, strlen(score) - 2);
	scoreInt = atoi(dealSqlInt);
	scoreInt = scoreInt + right * 10;
	strcpy(sqlw, "update user set score=");
	_itoa(scoreInt, score, 10);
	strcat(sqlw, score);
	strcat(sqlw, " where username = '");
	strcat(sqlw, username);
	strcat(sqlw, "';");
	char *exe = sqlw;
	exe_sql(exe);
	system("cls");
	system("mode con cols=58 lines=28");
	header();
	char sign[50] = "最長等待時間";
	char num[5] = "";
	strcpy(num, "");
	long int temp = timePast();
	//最長等待時間也是根據完成時間定義的
	_itoa(180 - (temp - firstTimer), num, 10);
	strcat(sign, num);
	strcat(sign, "秒");
	if ((180 - (temp - firstTimer))>0){
		word("等待對手完成中...", sign);
	}
	else{
		word("您已超時,本次測驗不計分!", "");
		blank();
		word("5秒後自動關閉本頁面!", "");
		Sleep(5000);
		getUserMainFrame(1);
	}
	footer();
	//睡眠到倒計時結束為止,使得大家時間同步
	Sleep(((180 - (temp - firstTimer)) + 2) * 1000);
	worldButtleResultFrame();
}
/*
對戰結果函數
*/
void worldButtleResultFrame(){
	system("cls");
	system("mode con cols=58 lines=28");
	header();
	word("結果統計表", "");
	blank(); dush();
	word("成績是:", "");
	char temp[20] = "";
	char sqlw[200] = "";
	for (int i = 0; i < agCounter; i++){
		if (ag[i].name != NULL){
			char name[20] = "";
			//拷貝對手姓名
			strcpy(name, ag[i].name);
			int oldscore = atoi(ag[i].score);
			char score[10] = "";
			//查詢對手分數
			strcpy(sqlw, "select score from user where username='");
			strcat(sqlw, name);
			strcat(sqlw, "';");
			strcpy(score, query_sql(sqlw));
			char dealSqlInt[10] = "";//單獨對sql的#號處理
			strncpy(dealSqlInt, score + 1, strlen(score) - 2);
			int newscore = atoi(dealSqlInt);
			char temp[200] = "";
			if (oldscore != newscore){//如果發現對手的分數發生了變化
				char dealNum[5] = "";
				int scorechange = newscore - oldscore;
				int right = scorechange / 10;
				_itoa(right, dealNum, 10);//int轉char數組
				strcpy(temp, name);
				strcat(temp, "--->答對");
				strcat(temp, dealNum);
				strcat(temp, "題,積");
				_itoa(scorechange, dealNum, 10);
				strcat(temp, dealNum);
				strcat(temp, "分!");
				word(temp, "");
			}
			else{//如果對手分數沒有變化
				strcpy(temp, name);
				strcat(temp, ",超時或全錯,沒有成績!");
				word(temp, "");
			}
		}
	}
	footer();
	getchar();
	agCounter = 0;//對戰人數歸零,等待新一波的對戰
	getUserMainFrame(1);
}

/*主函數*/
int main(int argc, char *argv[]) {
	getStartFunction(1);//調用起始函數
	getchar();
	return 0;
}

發表評論