c语言大作业,匹配系统,开了三个线程,c89,需要支持pthread.h库。
文件1 color.h
#include <windows.h>
const WORD FORE_BLUE = FOREGROUND_BLUE; //蓝色文本属性
const WORD FORE_GREEN = FOREGROUND_GREEN; //绿色文本属性
const WORD FORE_RED = FOREGROUND_RED; //红色文本属性
const WORD FORE_YELLOW = 6; //(FORE_RED | FORE_GREEN); //黄色文本属性 //c89标准不允许 (FORE_RED | FORE_GREEN)操作,所以直接给出值了,但是可移植性降低了。
const WORD FORE_GRAY = FOREGROUND_INTENSITY; //灰色文本属性 //如果是c99标准请去掉数字换成后面的表达式
const WORD BACK_BLUE = BACKGROUND_BLUE; //蓝色背景属性
const WORD BACK_GREEN = BACKGROUND_GREEN; //绿色背景属性
const WORD BACK_RED = BACKGROUND_RED; //绿色背景属性
const WORD BACK_PURPLE = 80; //(BACK_BLUE | BACK_RED); //紫色背景属性
const WORD BACK_CYAN = 48;//(BACK_BLUE | BACK_GREEN); //青色背景属性
const WORD BACK_YELLOW = 96;//(BACK_RED | BACK_GREEN); //黄色背景属性
const WORD BACK_GRAY = BACKGROUND_INTENSITY; //灰色背景属性
// 以下为windows改变窗口颜色调用
#define get_yellow SetConsoleTextAttribute(handle_out, FORE_YELLOW) //黄色
#define get_red SetConsoleTextAttribute(handle_out, FOREGROUND_INTENSITY | FORE_RED)//红色
#define get_white SetConsoleTextAttribute(handle_out, FORE_GREEN | FORE_BLUE | FORE_RED) //将三原色混合不就是白色(原色嘛)哈哈哈。
#define get_blue SetConsoleTextAttribute(handle_out, FORE_BLUE) //蓝色
#define get_green SetConsoleTextAttribute(handle_out, FORE_GREEN) //绿色
//暂时只用的上这么多颜色啦
void getcolor()
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
}
文件2 match_data.h
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
struct people
{
int id;//用户id
char name[500];//用户名
int grade; //分数
int wait_time; //匹配等待时间
};
struct gaming
{
struct people a;
struct people b;
int average_score;
int time_ing;
};
文件3 match_list.h
///存链表操作头文件
#include "sstring.h"
//#include "solve_error.h"
#include"menu.h"
extern int list_size;
typedef struct data_list //链表的结构,包含了match_data.h中的本程序基本数据(id名字和分数),以及一个指向下一个的指针。
{
struct people data;
struct data_list *next;
} list_data;
struct data_list * list_inint(int n) //初始化一个链表(list_data类型),其中包含n个表,不过本程序不需要初始的n个表,只需要初始化。
{
list_data * head;
list_data * tail;
list_data * p;
head = tail = p = NULL;
list_size=n;
while (n--)
{
p = (list_data *) malloc(sizeof(list_data));//给表分配空间
scanf("%d%s%d", &p->data.id, p->data.name, &p->data.grade);
p->next = NULL;
if (head == NULL)
{
head = p;
tail = p;
}
else
{
tail->next = p;
tail = p;
}
}
return head;//返回头指针
}
list_data * list_add(list_data *head,struct people a,int * kase)//向链表中插入一个数据(插入保证链表按照 “i d” 排好序)。
{
list_size++;
list_data * p = (list_data *) malloc(sizeof(list_data));//给表分配空间
p->data=a;
p->next=NULL;
list_data * head1 = head; //创建新表头——用来遍历到刚好比id小的地方,然后放入此次数据。
if(head==NULL||head->data.id>a.id)
{
p->next=head;
head=p;
return head;
}
else
{
while(head1->next!=NULL && head1->next->data.id <= a.id)
{
head1=head1->next;
}
if(head1->data.id == a.id)//如果出现重id则出现错误输入。
{
free(p);//出错记得释放空间,防止出现漏洞。
error(1);//输出错误信息。
list_size--;
*kase=1;
}
else//插入
{
p->next = head1->next;
head1->next = p;
}
}
return head;
//返回新的头指针。
}
list_data * list_remove(list_data *head,struct people a,int *kase)
{
list_size--;
if(head == NULL)
{
error(2);
list_size++;
*kase = 1;
return head;
}
if(head->data.id == a.id)
{
list_data * temp = head;
head=head->next;
free(temp);
}
else
{
list_data * head1 = head;
while((head1->next != NULL) && (head1->next->data.id !=a.id) )//遍历到要删除的人
{
head1=head1->next;
}
if(head1->next == NULL)//错误2,删除人物不存在。
{
error(2);
list_size++;
*kase = 1;
}
else
{
list_data * temp = head1->next;
head1->next=head1->next->next; //删除操作
free(temp);//记得释放内存。
}
}
return head;
}
int remove_now(list_data * a)//删除当前节点
{
if(a == NULL)
return 0;
if(a->next==NULL)
{
list_data * temp =a;
a=NULL;
free(temp);
list_size--;
return 1;
}
a->data=a->next->data;
list_data * temp =a->next;
a->next=a->next->next;
free(temp);
list_size--;
return 1;
}
int list_print(list_data * head)
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
list_data *p =head;
if(p == NULL)
{
get_red;
printf("there if no one in the match pool\n");
get_white;
}
else
{
int i=1;
get_yellow;
while(p!=NULL)
{
printf("%3d:id=%2d,name=%s,grade=%5d waiting for %d seconds\n",i,p->data.id,p->data.name,p->data.grade,p->data.wait_time);
p = p->next;
i++;
}
get_white;
}
return 1;
}
文件4 menu.h
#include<stdio.h>
//#include"color.h"
#include"solve_error.h"
int menu()//主菜单函数
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
printf("制作者:");
get_yellow;
printf("罗春阳\n\n");Sleep(1*20);
get_white; //这些东西都是调字体颜色的,可以忽略
printf("主菜单\n");Sleep(1*20);
get_green;
printf(" 注:可以输入'q'(加回车)来刷新页面,(命令不分大小写,可随意大小写)\n");
get_white;
printf("########################################################################################################\n");Sleep(1*20);
printf("##");
get_red;
printf(" 功能1:加入或删除用户进入匹配池。 功能2:查看匹配池或游戏池情况 ");Sleep(1*20);
get_white;
printf("##\n");
printf("## add/remove ‘id’ ‘username’ ‘grade’ fgamewait fgameing(-t)(-av) fpoolsize ##\n");Sleep(1*20);
printf("##");
get_red;
printf(" 功能3:结束某个用户的游戏。 功能4:查看各种历史 ");Sleep(1*20);
get_white;
printf("##\n");
printf("## gameover ‘id’ or gameover ‘username’ system-history history ##\n");Sleep(1*20);
printf("##");
get_red;
printf(" 功能5:切换系统信息输出模式。 功能6:查看帮助 ");Sleep(1*20);
get_white;
printf("##\n");
printf("## system-change help ##\n");Sleep(1*20);
printf("## 输入\"exit\"退出程序 ##\n");Sleep(1*20);
printf("########################################################################################################\n\n");Sleep(1*20);
printf("输入代码后回车即可执行相应请求\n"); Sleep(1*20);
return 1;
}
int match_exit()
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
printf(" ■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■■■ \n");Sleep(1*50);
printf(" ■■■ ■■■■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■■ ■ ■ \n");Sleep(1*50);
printf(" ■■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ \n");Sleep(1*50);
printf(" \n\n");
printf(" ■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■■■ \n");Sleep(1*50);
printf(" ■■■ ■■■■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■■ ■ ■ \n");Sleep(1*50);
printf(" ■■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ \n");Sleep(1*50);
printf(" \n\n");Sleep(1*50);
///
printf(" ■ ■ \n");Sleep(1*50);
printf(" ■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■■■■■■■ \n");Sleep(1*50);
printf(" ■ ■ \n");Sleep(1*50);
printf(" ■■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■■■■■■■■■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■■■■■■■■■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■■ \n");Sleep(1*50);
printf(" ■ ■■ \n");Sleep(1*50);
printf(" ■ ■ ■■ \n");Sleep(1*50);
printf(" ■ ■■ ■■■ \n");Sleep(1*50);
printf(" ■■ ■ \n");Sleep(1*50);
printf(" \n\n");
printf(" \n");Sleep(1*50);
printf(" ■■■■■■■■■■■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■■■■■■■■■■■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■■■■■■■■■■■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ ■ ■ \n");Sleep(1*50);
printf(" ■ ■ \n");Sleep(1*50);
printf(" \n\n\n");
get_red;
printf(" 虽然程序已经结束,但是您的操作历史和系统历史以及游戏池仍然会存下来\n 他们存在history.txt,system_history.txt和game.txt中\n");
get_white;
Sleep(1*1000);
system("pause");
exit(0);
}
int help()
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
FILE * fp;
fp = fopen("readme.txt","r");
char kmp[2000];
while(fscanf(fp,"%[^\n]%*c",kmp)==1)
{
if(!strcmp(kmp,"功能"))
{
get_red;
puts(kmp);
get_white;
}
else
puts(kmp);
}
puts("");
return 0;
}
int enter()
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
get_red;
printf("按回车进入系统\n");
get_white;
if(!scanf("%*[^\n]%*c"))
{
getchar();
}
return 0;
}
文件5 solve_error.h
#include"color.h"
#include<stdio.h>
void error(int n)//处理错误的函数
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
if(n==1)
{
get_red;
printf("\n error\n 错误代码:001 重id__请勿反复加入匹配!\n");
get_white;
}
else if(n==2)
{
get_red;
printf("\n error\n 错误代码:002 此id用户未进行匹配__请勿反复退出或开始游戏!\n");
get_white;
}
else if(n==3)
{
get_red;
printf("\n error\n 错误代码:003 输入格式错误__请按照上方格式输入!\n");
get_white;
}
else if(n==4)
{
get_red;
printf("\n error\n 错误代码:004 未找到此游戏用户__此用户未开始游戏,无法结束!\n");
get_white;
}
else if(n==5)
{
get_red;
printf("\n error\n 错误代码:005 无法加入此用户__此用户已经开始游戏,无法再次匹配!\n");
get_white;
}
return;
}
文件6 sstring.h
//本程序需要用到的字符串处理函数
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"match_data.h"
int search_kongge(char a[])//判断空格个数
{
int flag = 0;
int ans = 0;
int i;
for (i = 0; a[i] != '\0'; i++)
{
if (a[i] == ' ' && flag > 0)
ans++;
else
{
flag++;
}
}
return ans;
}
int fengge_one(char get[],char d[])//分割成一个空格的版本
{
sscanf(get,"%s",d);
if(!strcmp(d,"gameover"))
{
sscanf(get,"%*s%s",d);
return 0;
}
else
{
return 1;
}
}
int fengge_three(char get[], char d[], struct people *a)//分割成三个空格的版本
{
sscanf(get, "%s%d%s%d", d, &a->id, a->name, &a->grade);
return 1;
}
int string_sourch(char a[], int n)
{
if (n == 1)
{
int i;
for (i = 0; a[i] != '\0'; i++) //先转换大小写
{
if (a[i] >= 'A' && a[i] <= 'Z')
a[i] = a[i] - 'A' + 'a';
}
if (!strcmp(a, "add"))
return 1;
else if (!strcmp(a, "remove"))
return 2;
else
return 3;
}
else
{
int i;
for (i = 0; a[i] != '\0'; i++) //先转换大小写
{
if (a[i] >= 'A' && a[i] <= 'Z')
a[i] = a[i] - 'A' + 'a';
}
if (!strcmp(a, "fgamewait"))
return 1;
else if (!strcmp(a, "fgameing"))
return 2;
else if(!strcmp(a,"fpoolsize"))
return 4;
else if(!strcmp(a,"q"))
return 5;
else if(!strcmp(a,"exit"))
return 0;
else if(!strcmp(a,"history"))
return 6;
else if(!strcmp(a,"system-history"))
return 7;
else if(!strcmp(a,"system-change"))
return 8;
else if(!strcmp(a,"help"))
return 9;
else if(!strcmp(a,"fgameing-t"))
return 10;
else if(!strcmp(a,"fgameing-av"))
return 11;
else
return 3;
}
}
文件7 game_pool.h
#include<stdio.h>
/*struct gaming
{
struct people a;
struct people b;
int average_score;
};*/
//#include"color.h"
//#include "menu.h"
//#include"match_data.h"
//#include"sstring.h"
#include"match_list.h"
int gameing_print(struct gaming a[],int size)//默认输出游戏进行时间
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
int i;
for(i=0;size>i;i++)
{
printf("%d:\n",i+1);
get_red;
printf("%s",a[i].a.name);
get_white;
printf(" vs ");
get_blue;
printf("%s\n",a[i].b.name);
get_white;
printf("played:%d seconds\n\n",a[i].time_ing);
}
if(size == 0)
{
get_red;
printf("\nthere is no one in gameing\n");
get_white;
}
puts("");
return 0;
}
int gameing_print_a(struct gaming a[],int size)//输出游戏双方的平均分数
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
int i;
for(i=0;size>i;i++)
{
printf("%d:\n",i+1);
get_red;
printf("%s",a[i].a.name);
get_white;
printf(" vs ");
get_blue;
printf("%s\n",a[i].b.name);
get_white;
printf("平均分数为:%d 分\n\n",a[i].average_score);
}
if(size == 0)
{
get_red;
printf("\nthere is no one in gameing\n");
get_white;
}
puts("");
return 0;
}
主c文件 用户动态匹配系统.c
int list_size=0;//当前链表长度
//#include "match_list.h"
#include <pthread.h>
#include "game_pool.h"//保存
//#include"color.h"
int system_history=0;//全局变量,用来改变系统问题是否输出到屏幕。0表示不输出。
int id_card[10000000];//对id进行判重,防止重复id加入游戏。
//int name_card[1000000]; //本来想写一个字符串哈希来对名字判重的,但是没写了,因为没什么意义,名字可以重复。
pthread_mutex_t id_m;
struct mutex_match//定义了一个带锁的链表,方便多线程时的管理。//此为匹配池 匹配池为动态池,动态存储。
{
list_data * head ;
pthread_mutex_t m;
}q;
struct mutex_game //这是游戏池。//游戏池将存在文件game.txt中。
{
struct gaming pool[2000];
int cnt;
pthread_mutex_t m;
}gameing;
struct gaming ttemp[2000];//用来处理游戏池的删除//做中介作用
//
pthread_mutex_t file_game_m;//文件锁,防止多进程同时对文件进行增删查改。
pthread_mutex_t file_history_m;//操作历史文件——锁。
pthread_mutex_t file_history_system_m;//系统操作历史文件(例如match 1 and 2 succeed)。——锁。
int add_to_game(struct people a,struct people b)//加入正在进行中的游戏池。
{
pthread_mutex_lock(&gameing.m);
gameing.pool[gameing.cnt].a=a;
gameing.pool[gameing.cnt].b=b;
gameing.pool[gameing.cnt].average_score=((a.grade+b.grade)>>1);
gameing.cnt++;
pthread_mutex_unlock(&gameing.m);
}
/*#############此 处 为 匹 配 线 程 开 始 #####################*/
int match_server(list_data * head)//匹配程序,遍历匹配,选取合法的用户匹配,每一次匹配提高每个用户的匹配(阈值)(时间越久越容易匹配到人(不过可能被虐菜))。
{
int a=0;
list_data * i;
for(i = head ; i!=NULL ; i = i->next)
{
i->data.wait_time++;
}
for(i = head ; i!=NULL ; i = i->next)//遍历进行匹配
{
list_data * j;
for(j = i->next ; j!=NULL ; j = j->next)
{
int t=abs(i->data.grade - j->data.grade);
if((t <= (i->data.wait_time * 5))&&(t <= (j->data.wait_time * 5)))//符合要求则进入游戏池,并从匹配池删除
{
add_to_game(i->data,j->data);
pthread_mutex_lock(&id_m);//更新id
id_card[i->data.id]=1;
id_card[j->data.id]=1;
pthread_mutex_unlock(&id_m);
if(system_history)//存历史
{
printf("match %d and %d succeed\n",i->data.id,j->data.id);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"match %d and %d succeed\n",i->data.id,j->data.id);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);
if(j->next==NULL)
{
q.head=list_remove(q.head,j->data,&a);
}
else
remove_now(j);
if(i->next==NULL||i==head)
{
q.head=list_remove(q.head,i->data,&a);
}
else
{
remove_now(i);
}
return 0;
}
}
}
return 0;
}
void * solve_task(void *argc)//解决匹配问题
{
while(1)
{
while (list_size>0)//一秒匹配一次
{
pthread_mutex_lock(&q.m);
match_server(q.head);
pthread_mutex_unlock(&q.m);
Sleep(1000);
}
Sleep(1000);
}
}
/*############# 此 处 为 匹 配 线 程 的 结 尾 #####################*/
//-----------------------------------------------------------------------------------------------------------------------------------------分割线
/*############# 此 处 为 游 戏 线 程 的 开 始 #####################*/
int game_file_add()//每五秒刷新一次 游戏进行时文件
{
pthread_mutex_lock(&gameing.m);
pthread_mutex_lock(&file_game_m);
FILE *fp;
fp = fopen("game.txt","w");
int i;
for(i=0;gameing.cnt>i;i++)
{
gameing.pool[i].time_ing+=5;//每次刷新游戏时间加5
fprintf(fp,"%d:\n",i+1);
fprintf(fp," %d %s %d\n",gameing.pool[i].a.id,gameing.pool[i].a.name,gameing.pool[i].a.grade);
fprintf(fp," vs gameing_time:%ds\n",gameing.pool[i].time_ing);
fprintf(fp," %d %s %d\n\n",gameing.pool[i].b.id,gameing.pool[i].b.name,gameing.pool[i].b.grade);
}
fclose(fp);
pthread_mutex_unlock(&gameing.m);
pthread_mutex_unlock(&file_game_m);
return 0;
}
int game_remove_name(char name[])//结束某个用户的游戏——用名称进行删除。
{
pthread_mutex_lock(&gameing.m);
int temp_cnt=0;
int i;
for(i = 0;gameing.cnt>i;i++)
{
if((!strcmp(name,gameing.pool[i].a.name)) || (!strcmp(name,gameing.pool[i].b.name)) )
{
pthread_mutex_lock(&id_m);
id_card[gameing.pool[i].a.id]=0;
id_card[gameing.pool[i].b.id]=0;
pthread_mutex_unlock(&id_m);
continue;
}
ttemp[temp_cnt++]=gameing.pool[i];
}
if(temp_cnt == gameing.cnt)
{
pthread_mutex_unlock(&gameing.m);
if(system_history)//存历史
{
printf("gameover '%s' false\n",name);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"gameover '%s' false\n",name);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);
return 1;
}
else
{
for(i=0;temp_cnt>i;i++)//在前面定义过了
{
gameing.pool[i]=ttemp[i];
}
gameing.cnt=temp_cnt;
}
pthread_mutex_unlock(&gameing.m);
if(system_history)//存历史
{
printf("gameover '%s' succeed\n",name);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"gameover '%s' succeed\n",name);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);//记得开锁。
return 0;
}
int game_remove_id(int id)//结束某个用户的游戏——用id进行删除。
{
pthread_mutex_lock(&gameing.m);
int temp_cnt=0;
int i;
for(i = 0;gameing.cnt>i;i++)
{
if((id == gameing.pool[i].a.id) || (id == gameing.pool[i].b.id))
{
pthread_mutex_lock(&id_m);
id_card[gameing.pool[i].a.id]=0;
id_card[gameing.pool[i].b.id]=0;
pthread_mutex_unlock(&id_m);
continue;
}
ttemp[temp_cnt++]=gameing.pool[i];
}
if(temp_cnt == gameing.cnt)
{
pthread_mutex_unlock(&gameing.m);
if(system_history)//存历史
{
printf("gameover '%d' false\n",id);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"gameover '%d' false\n",id);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);
return 1;
}
else
{
for(i=0;temp_cnt>i;i++)//前面定义过了
{
gameing.pool[i]=ttemp[i];
}
gameing.cnt=temp_cnt;
}
pthread_mutex_unlock(&gameing.m);
if(system_history)//存历史
{
printf("gameover '%d' succeed\n",id);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"gameover '%d' succeed\n",id);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);//记得开锁。
return 0;
}
void *solve_gaming(void *argc)//解决游戏问题
{
while(1)
{
while(gameing.cnt>0)
{
game_file_add();
Sleep(5000);
}
Sleep(5000);
}
}
/*############# 此 处 为 游 戏 线 程 的 结 尾 #####################*/
/*############# 此 处 为 历 史 文 件 处 理 的 开 始 #####################*/
int print_history()输出history.txt文件。
{
pthread_mutex_lock(&file_history_m);
FILE * fp;
int i=1;
fp = fopen("history.txt","r");
char kmp[200];
while(fscanf(fp,"%[^\n]%*c",kmp)==1)
{
printf("%d:",i);
puts(kmp);
i++;
}
puts("");
pthread_mutex_unlock(&file_history_m);
return 0;
}
int print_system_history()///输出系统信息___history_system.txt文件
{
pthread_mutex_lock(&file_history_system_m);
FILE * fp;
int i=1;
fp = fopen("history_system.txt","r");
char kmp[200];
while(fscanf(fp,"%[^\n]%*c",kmp)==1)
{
printf("%d:",i);
puts(kmp);
i++;
}
puts("");
pthread_mutex_unlock(&file_history_system_m);
return 0;
}
/*############# 此 处 为 历 史 文 件 处 理 的 结 尾 #####################*/
/*############# 此 处 为 解 决 游 戏 池 排 序 输 出 的 问 题 开 始 #####################*/
int cmp_time(const void *p1,const void *p2)//时间排序函数
{
const struct gaming *a1 = (const struct gaming *)p1;
const struct gaming *a2 = (const struct gaming *)p2;
return a1->time_ing > a2->time_ing;
}
int cmp_average(const void *p1,const void *p2)//平均分数排序函数
{
const struct gaming *a1 = (const struct gaming *)p1;
const struct gaming *a2 = (const struct gaming *)p2;
return a1->average_score > a2->average_score;
}
int gameing_print_time(struct gaming a[],int n)//按时间排序后输出函数
{
qsort(a,n,sizeof(struct gaming),cmp_time);
gameing_print(a,n);
return 0;
}
int gameing_print_average(struct gaming a[],int n) //按平均成绩排序后输出函数。
{
qsort(a,n,sizeof(struct gaming),cmp_average);
gameing_print_a(a,n);
return 0;
}
/*############# 此 处 为 解 决 游 戏 池 排 序 输 出 的 问 题 结 尾 #####################*/
int main(void)//主函数开始处、、、、、、、、
{
//先输出教程
help();//定义在menu.h
enter();//阻断函数。。给用户看说明的时间//定义在menu.h
system("cls");
//正式进入系统
FILE *file_to_zero;//初始化各个文件防止上一次运行残留。
file_to_zero = fopen("history.txt","w");
fclose(file_to_zero);
file_to_zero = fopen("history_system.txt","w");
fclose(file_to_zero);//初始化 history文件。
file_to_zero = fopen("game.txt","w");
fclose(file_to_zero);
menu(); //输出菜单。
char get[700]; //读取整行输入
char doing[200];//存临时操作名称
struct people a;//存临时用户。
gameing.cnt=0;
q.head=list_inint(0);//初始化链表
pthread_t th1_match;//定义第一个线程 //用于匹配
pthread_t th2_game;//定义第二个线程// 用于进行游戏池更新。
pthread_create(&th1_match,NULL,solve_task,NULL);//创建第一个线程 (匹配线程,每一秒匹配一次)
pthread_create(&th2_game,NULL,solve_gaming,NULL);//创建第二个线程(游戏线程,处理游戏进行时的条件改变__五秒刷新一次)
while(1==1)//反复循环读取用户输入
{
if(!scanf("%[^\n]%*c",get))//输入操作
{
getchar();
continue;
}
pthread_mutex_lock(&file_history_m); //存操作历史。
FILE *history_file_hand;
history_file_hand = fopen("history.txt","a+");
fprintf(history_file_hand,"%s\n",get);
fclose(history_file_hand);
pthread_mutex_unlock(&file_history_m);
/
int kongge=search_kongge(get);//输入按空格分为0,1,3空格形式命令
if(kongge != 3 && kongge != 0 && kongge !=1)//都不是则error
error(3);
else if(kongge == 3)//三空格命令
{
fengge_three(get,doing,&a);//三空格的字符串 分割出来。
int temp=0;
temp=string_sourch(doing,1);//以一号方式执行函数 //为添加和删除匹配(方式 )
if(temp==3)
error(3);
else if(temp == 1)//添加用户
{
int p=0;
pthread_mutex_lock(&q.m);//把链表上锁,防止同时修改。
pthread_mutex_lock(&id_m);//id也要上锁。
if(id_card[a.id])
{
p=1;
error(5);
}
else
q.head = list_add(q.head,a,&p);
pthread_mutex_unlock(&q.m);//释放
pthread_mutex_unlock(&id_m);
if(!p) //处理系统信息,判断添加成功与否
{
pthread_mutex_lock(&id_m);//更新id
id_card[a.id]=1;
pthread_mutex_unlock(&id_m);
if(system_history)
{
printf("add %d succeed\n",a.id);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"add %d succeed\n",a.id);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);
}
else
{
if(system_history)
{
printf("add %d false\n",a.id);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"add %d false\n",a.id);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);
}
///
}
else if(temp == 2)//同上,删除用户
{
int p=0;
pthread_mutex_lock(&q.m);//把链表上锁,防止同时修改。
q.head = list_remove(q.head,a,&p);
pthread_mutex_unlock(&q.m);
if(!p)//处理系统信息,判断删除成功与否
{
if(system_history)
{
printf("remove %d succeed\n",a.id);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"remove %d succeed\n",a.id);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);
}
else
{
if(system_history)
{
printf("remove %d false\n",a.id);
}
pthread_mutex_lock(&file_history_system_m);
FILE *fp;
fp =fopen("history_system.txt","a+");
fprintf(fp,"remove %d false\n",a.id);
fclose(fp);
pthread_mutex_unlock(&file_history_system_m);
}
///
}
}
else if(kongge == 1)//一空格命令
{
if(fengge_one(get,doing))//先分割
{
error(3);
continue;
}
if(doing[0]>='0'&&doing[0]<='9')//判断数字id还是名字
{
int id=0;
int i;
for(i=0;doing[i]!='\0';i++)
{
id=id*10 +(doing[i]-'0');
}
if(game_remove_id(id))
{
error(4);
}
}
else
if(game_remove_name(doing))
{
error(4);
}
}
else if(kongge == 0)//零空格命令
{
int temp=string_sourch(get,2);//以二号方式执行。//是某些单条命令
if(temp ==0)//exit
{
pthread_mutex_lock(&file_game_m);
pthread_mutex_lock(&file_history_m);
pthread_mutex_lock(&file_history_system_m);
match_exit();
pthread_mutex_unlock(&file_game_m);
pthread_mutex_unlock(&file_history_m);
pthread_mutex_unlock(&file_history_system_m);
}
else if(temp==3)//没这个命令
error(3);
else if(temp == 1)//fgamewait
{
pthread_mutex_lock(&q.m);//把链表上锁,防止同时修改。
list_print(q.head);
pthread_mutex_unlock(&q.m);//释放
}
else if(temp == 2)//fgameing
{
pthread_mutex_lock(&gameing.m);
gameing_print(gameing.pool,gameing.cnt);
pthread_mutex_unlock(&gameing.m);
}
else if(temp == 4)//fpoolsize
{
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
printf("now the pool size is: ");
get_red;
printf("%d\n",list_size);
get_white;
}
else if(temp == 5)//q//刷新
{
system("cls");
menu();
}
else if(temp == 6)//history
{
print_history();
}
else if(temp == 7)//system-history
{
print_system_history();
}
else if(temp == 8)//system-change
{
system_history ^=1;
if(system_history == 1)
printf("change to system_out (此模式下将及时的输出所有系统信息)\n");
else
{
printf("change to system_in(关闭系统信息输出)\n");
}
}
else if(temp == 9)//help
{
help();//直接输出帮助____定义在menu.h中。
}
else if(temp == 10)//fgameing-t//按时间排序从小到大输出。
{
pthread_mutex_lock(&gameing.m);
gameing_print_time(gameing.pool,gameing.cnt);
pthread_mutex_unlock(&gameing.m);
}
else if(temp == 11)//fgameing-av//按比赛双方的平均分数排序从小到大输出。
{
pthread_mutex_lock(&gameing.m);
gameing_print_average(gameing.pool,gameing.cnt);
pthread_mutex_unlock(&gameing.m);
}
}
}
return 0;
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// . ' \\| |// `.
// / \\||| : |||// \
// / _||||| -:- |||||- \
// | | \\\ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
//
// .............................................
// 佛祖保佑 永无BUG
// 佛曰:
// 写字楼里写字间,写字间里程序员;
// 程序人员写程序,又拿程序换酒钱。
// 酒醒只在网上坐,酒醉还来网下眠;
// 酒醉酒醒日复日,网上网下年复年。
// 但愿老死电脑间,不愿鞠躬老板前;
// 奔驰宝马贵者趣,公交自行程序员。
// 别人笑我忒疯癫,我笑自己命太贱;
// 不见满街漂亮妹,哪个归得程序员?
}
教程文件 readme.txt (必须与主函数文件处于同一文件夹下运行)
功能
1:
add remove
添加用户和删除用户进匹配池(匹配系统会根据添加进来的用户动态的进行匹配,每一个用户第一秒只会匹配根自己分数相差5分以内的对手,
但是每过一秒他们的阈值会增加5分(就算是与跟自己分差很多的对手游戏也比没人好)及第二秒就可能会匹配到跟自己相差10分的对手了,以此类推)。
add操作。
add+(id)+(user_name)+(user_grade) 中间用空格隔开回车即可添加,(id和名字和分数)
(其实是模拟前端用户点击匹配然后进行的操作--这里没有图形界面所以用linux类型的命令进行交互)
remove操作。
remove+(id)+(user_name)+(user_grade) 中间用空格隔开回车即可删除,(id和名字和分数)
(模拟前端用户点击取消匹配然后进行的操作,注意,用户可能会匹配成功,如果匹配成功了就无法取消了。)
功能
2:
fgamewait fgameing(-t)(-av) fpoolsize
查看匹配池或游戏池情况(匹配系统随时可能会匹配成功,成功的人会移除匹配池,所以我们随时可以查看一下匹配池情况(可看到池中各种数值))
fgamewait(输入此命令然后回车,可以看到还在等待匹配的用户即匹配池中的所有人的详细情况)
例如输出
1:id= 1,name=lcy,grade= 1500 waiting for 5 seconds
fgameing(-t)(-av)(输入此命令然后回车,可以看到正在游戏的用户即游戏池中人的数量,包括他们的游戏时长,并且这些信息存在game.txt中结束程序也不会消失)
(可以加上后缀(-t)或者(-av)(分别表示按游戏"进行时间"和游戏玩家的"平均分数"从小到大排序后输出)(例如:(fgameing-t) (fgameing-av))
例如输出
1:
lcy vs hdm
played:5 seconds
fpoolsize(输入此命令然后回车,可以看到还在等待匹配的用户即匹配池中人的数量)
例如输出
now the pool size is: 0
功能
3:
gameover 'id' gameover 'name'
结束某个用户的游戏(用来模拟游戏结束前端向服务器发送的请求)(用户必须要正在游戏才能结束哦)
gameover+(id)或者gameover+(user_name) (中间用空格隔开回车即可删除)(id 和 名字 都行效果一样)
随后那个用户就会从游戏池中被删除。。当然game.txt中他也会被删除。
功能
4:
查看各种历史
history (输入此命令然后回车,可以看到自己的所有历史输入,他将按顺序展示出来,(包括无意义的命令)(这些信息存在history.txt文件中))
例如输出
1:add 1 罗春阳 1500
2:add 2 hdm 1530
3:fgame
4:fgamewait
system-history(输入此命令然后回车,可以看到系统的所有历史信息,他将按顺序展示出来,(系统每次匹配到一个人或者加入一个用户都会产生一个信息)(这个信息存在history_system.txt文件中))
例如输出
1:add 1 and 2 succeed
功能
5:
切换系统信息输出模式
system-change(输入此命令然后回车,可以将系统输出及时的输出到终端屏幕上)
(系统每次匹配到一个人或者加入一个用户都会产生一个信息)(开启输出后这个信息将能及时的展示在终端屏幕上)
(再输入一次即可关闭)。
功能
6:
查看帮助
help(输入此命令然后回车 将再次展示此页面)
输入一个字母'q'加回车可以刷新页面(如果你觉得页面太长不舒服的话)。
以上