首页 » 原創 » 正文

[原创]基于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;
}

发表评论