石头剪刀布联机游戏(C++写的)
  • 板块灌水区
  • 楼主ljcsunrise
  • 当前回复4
  • 已保存回复4
  • 发布时间2024/7/22 17:02
  • 上次更新2024/7/22 18:04:49
查看原帖
石头剪刀布联机游戏(C++写的)
750957
ljcsunrise楼主2024/7/22 17:02

功能基本齐全,有需要的自己加 两坨屎山,卤棒性较差。目前没有发现bug。

服务端代码

#include <winsock2.h>
#include <iostream>
#include <bits/stdc++.h>
#include <time.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
vector<string> wait;
map<string,bool> gotR;
map<SOCKET,string> usrname;
map<string,SOCKET> isused;
map<string,string> match;
map<string,int> chs;
map<string,bool> isinque;
string mp;
string hd[4] = {"未出手","石头","剪刀","布"}; 

void Send(SOCKET s,string str){
	char buf[300] = {0};
    sprintf(buf, str.c_str());
	send(s, buf, 300, 0);
}

int win(int a,int b){
	if(a == b)
		return -1;
	if(a == 1 && b == 2)
		return 1;
	if(a == 2 && b == 3)
		return 1;
	if(a == 3 && b == 1)
		return 1;
	return 0;
}

void save(string str){
	fstream f;
	f.open("chat.tmp",ios::out|ios::app);
	f<<str;
	f.close(); 
}

int main() {
    // 初始化winsock的环境
    freopen("logs.txt","a",stdout);
    WSADATA wd;
    if (WSAStartup(MAKEWORD(2, 2), &wd) == SOCKET_ERROR) {
        cout << "WSAStartup  error:" << GetLastError() << endl;
        return 0;
    }

    // 1.创建监听套接字
    SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sListen == INVALID_SOCKET) {
        cout << "socket  error:" << GetLastError() << endl;
        return 0;
    }

    // 2.绑定到ip与端口
    sockaddr_in serverSockAddr;
    serverSockAddr.sin_addr.S_un.S_addr = inet_addr("你的IP地址");
    serverSockAddr.sin_port = htons(7999);
    serverSockAddr.sin_family = AF_INET;
    int len = sizeof(sockaddr_in);
    if (bind(sListen, (SOCKADDR *) &serverSockAddr, len) == SOCKET_ERROR) {
        cout << "bind  error:" << GetLastError() << endl;
        return 0;
    }

    // 3.监听套接字
    if (listen(sListen, 5) == SOCKET_ERROR) {
        cout << "listen  error:" << GetLastError() << endl;
        return 0;
    }

    // 4. select开始了
    fd_set readSet;//定义一个读(接受消息)的集合
    FD_ZERO(&readSet);//初始化集合
    FD_SET(sListen, &readSet);
	time_t now = time(NULL);
	tm* tm_t = localtime(&now);
	cout << "Start the server[time]year:" << tm_t->tm_year + 1900 << " month:" << tm_t->tm_mon + 1 << " day:" << tm_t->tm_mday << " hour:" << tm_t->tm_hour << " minute:" << tm_t->tm_min << " second:" << tm_t->tm_sec<<'\n';		

    while (true) {
        fd_set tmpSet; // 定义一个临时的集合
        FD_ZERO(&tmpSet); // 初始化集合
        tmpSet = readSet; // 每次循环都是所有的套接字

        // 利用select选择出集合中可以读写的多个套接字,有点像筛选
        int ret = select(0, &tmpSet, NULL, NULL, NULL);//最后一个参数为NULL,一直等待,直到有数据过来
        if (ret == SOCKET_ERROR) {
            continue;
        }
        
        ofstream O("serverWin.dat");
        
		// 成功筛选出来的tmpSet可以发送或者接收的socket
        for (int i = 0; i < tmpSet.fd_count; ++i) {
            //获取到套接字
            SOCKET selectedSocket = tmpSet.fd_array[i];


            // 接收到客户端的链接
            if (selectedSocket == sListen) {
                SOCKET c = accept(selectedSocket, NULL, NULL);
                // fd_set集合最大值为64
                if (readSet.fd_count < FD_SETSIZE) {
                    //往集合中添加客户端套接字
                    FD_SET(c, &readSet);
                    cout << c << " logged in.\n" << endl;

                    // 给客户端发送欢迎
                    char buf[100] = {0};
                    sprintf(buf, "hello from server", c);
                    send(c, buf, 100, 0);
                } else {
                    cout << "max 64 clients for now." << endl;
                }

            } else {
                // 接收客户端的数据
				char buf[100] = {0};
                ret = recv(selectedSocket, buf, 100, 0);
                if (ret == SOCKET_ERROR || ret == 0) {
                    closesocket(selectedSocket);
                    FD_CLR(selectedSocket, &readSet);
                    cout << selectedSocket << "logged off.\n" << endl;
					string str = usrname[selectedSocket];
                    str += " logged off.\n";
//					save(str);
					//msg.push_back(str); 
					if(match[usrname[selectedSocket]] != ""){
						gotR[usrname[selectedSocket]] = false;
						gotR[match[usrname[selectedSocket]]] = false;
						chs[usrname[selectedSocket]] = 0;
						chs[match[usrname[selectedSocket]]] = 0;
						match[match[usrname[selectedSocket]]] = "";
						match[usrname[selectedSocket]] = ""; 
					}
                    isused[usrname[selectedSocket]] = 0;
                    usrname[selectedSocket] = "";
                } else {
                	string op;
                	istringstream o(buf);
                	o>>op;
                	if(op == "--login"){
                		string name;
                		o>>name;
                		if(name == "" || isused[name])
                			Send(selectedSocket,"No");
                		else {
                			usrname[selectedSocket] = name,isused[name] = selectedSocket,Send(selectedSocket,"ok");
							string str = usrname[selectedSocket];
		                    str += " logged in.\n";
//							save(str);
							//msg.push_back(str); 
                		}
	                } else if(op == "--join"){
	                	wait.push_back(usrname[selectedSocket]);
	                	isinque[usrname[selectedSocket]] = true;
	                	while(wait.size()>=2){
	                		string a,b;
	                		a = wait[0];
	                		wait.erase(wait.begin());
	                		b = wait[0];
	                		wait.erase(wait.begin());
	                		match[a] = b;
	                		match[b] = a;
	                		gotR[usrname[selectedSocket]] = false;
							gotR[match[usrname[selectedSocket]]] = false;
							chs[usrname[selectedSocket]] = 0;
							chs[match[usrname[selectedSocket]]] = 0;
//	                		cerr<<"match:"<<match[a]<<' '<<match[b]<<'\n';
	                		string str = a;
							str += " and ";
							str += b;
							str += " began to fight\n";
							save(str); 
	                		if(!wait.size())
	                			break;
						}
					} else if(op == "--cancelJoin"){
//						cerr<<"--cancelJoin\n";
						for(auto it = wait.begin();it != wait.end();it++){
//							cerr<<*it<<'\n';
							if(*it == usrname[selectedSocket])
								it = wait.erase(it),it--; 
						}
					} else if(op == "--getWaitStatus"){
//						cerr<<"name:"<<match[usrname[selectedSocket]]<<'\n';
						if(match[usrname[selectedSocket]] != ""){
							Send(selectedSocket,"OK!");
						} else {
							Send(selectedSocket,"Not yet");
						}
					} else if(op == "--getEnemyName"){
						cerr<<usrname[selectedSocket]<<' '<<match[usrname[selectedSocket]]<<'\n';
						if(match[usrname[selectedSocket]] != ""){
//							cerr<<
							Send(selectedSocket,match[usrname[selectedSocket]]);
						} else {
							Send(selectedSocket,"--Ohno");
						}
					} else if(op == "--getEnemyStatus"){
						if(match[usrname[selectedSocket]] == ""){
							Send(selectedSocket,"--Ohno");
						}
						if(chs[match[usrname[selectedSocket]]] != 0)
							Send(selectedSocket,"ok");
						else
							Send(selectedSocket,"no");
					} else if(op == "--rock"){
						chs[usrname[selectedSocket]] = 1;
					} else if(op == "--scissor"){
						chs[usrname[selectedSocket]] = 2;
					} else if(op == "--paper"){
						chs[usrname[selectedSocket]] = 3;
					} else if(op == "--getResult"){
						
						if(!chs[usrname[selectedSocket]] || !chs[match[usrname[selectedSocket]]]){
							Send(selectedSocket,"--wait"); 
//							cerr<<"wait......\n";
							continue;
						}
						int res = win(chs[usrname[selectedSocket]],chs[match[usrname[selectedSocket]]]);
						cerr<<usrname[selectedSocket]<<' '<<match[usrname[selectedSocket]]<<' '<<res<<'\n';
						if(res == -1)
							Send(selectedSocket,"--draw");
						if(res == 1)
							Send(selectedSocket,"--win");
						if(res == 0)
							Send(selectedSocket,"--lose");
						gotR[usrname[selectedSocket]] = true;
						
						if(gotR[usrname[selectedSocket]]&&gotR[match[usrname[selectedSocket]]]){
							string final = usrname[selectedSocket];
							final += "'s choice is ";
							final += hd[chs[usrname[selectedSocket]]];
							final += " and ";
							final += match[usrname[selectedSocket]];
							final += "'s choice is ";
							final += hd[chs[match[usrname[selectedSocket]]]];
							final += ", so finally ";
							if(res == -1){
								final += "they were tied.\n";
							} else {
								if(res == 1)
									final += usrname[selectedSocket];
								if(res == 0)
									final += match[usrname[selectedSocket]];
								final += " winned.\n"; 
							}
//							save(final);
							gotR[usrname[selectedSocket]] = false;
							gotR[match[usrname[selectedSocket]]] = false;
							chs[usrname[selectedSocket]] = 0;
							chs[match[usrname[selectedSocket]]] = 0;
							match[match[usrname[selectedSocket]]] = "";
							match[usrname[selectedSocket]] = ""; 
						}
					} else if(op == "--conn"){
						Send(selectedSocket,"fine");
					}
                    cout << selectedSocket << " sent " << buf << endl;
                }
            }
            
        }
    }

//	f.close();
    // 关闭监听套接字
    closesocket(sListen);

    // 清理winsock环境
    WSACleanup();

    return 0;
}

客户端代码

#include<winsock2.h>//winsock2的头文件
#include<iostream>
#include<conio.h>
#include<bits/stdc++.h>
#define get char buf[300] = {0};recv(s, buf, 300, 0);

using namespace std;
string username;
string hd[4] = {"未出手\n","石头\n","剪刀\n","布\n"}; 
int win = 0,draw = 0,lose = 0,sum = 0;

//勿忘,链接dll的lib
#pragma comment(lib, "ws2_32.lib")

int Send(SOCKET s,string str){
	char buf[300] = {0};
    sprintf(buf, str.c_str());
	return send(s, buf, 300, 0);
}

void savedata(){
	ofstream o(username.c_str());
	o<<win<<'\n'<<draw<<'\n'<<lose<<'\n'<<sum<<'\n';
	o.close();
}

int main() {
    //加载winsock2的环境
    WSADATA wd;
    if (WSAStartup(MAKEWORD(2, 2), &wd) != 0) {
        cout << "WSAStartup  error:" << GetLastError() << endl;
        return 0;
    }

    //1.创建流式套接字
    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s == INVALID_SOCKET) {
        cout << "socket  error:" << GetLastError() << endl;
        return 0;
    }

    //2.连接服务器
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7999);
    addr.sin_addr.S_un.S_addr = inet_addr("服务端IP地址");

    int len = sizeof(sockaddr_in);
    if (connect(s, (SOCKADDR *) &addr, len) == SOCKET_ERROR) {
        cout << "connect  error:" << GetLastError() << endl;
        return 0;
    }

    //3接收服务端的消息
    char buf[300] = {0};
    recv(s, buf, 300, 0);
    cout << buf << endl;

    //3随时给服务端发消息
    int ret = 0;
    do {
    	while(1){
    		system("cls");
    		cout<<"请输入用户名!";
    		cin>>username;
    		string ss = "--login "+username;
    		Send(s,ss);
    		get;
//    		cerr<<"return:"<<buf<<'\n';
    		if(buf[0] != 'N')
    			break; 
    	} 
		ifstream i(username.c_str());
		if(!i.is_open()){
			savedata();
		} else{
			i>>win>>draw>>lose>>sum;
			i.close();
		}
    	do{
			ret = Send(s,"--conn"); 
    		get;
    		system("cls");
    		savedata();
    		cout<<"决斗\n\n你好,"<<username<<"!\n1、开始匹配!\n2、查看战绩\n3、帮助\n"; 
    		int choice;
    		cin>>choice;
    		if(choice == 1){
    			cout<<"开始匹配!按任意键取消!\n";
    			ret = Send(s,"--join");
    			while(1){
    				if(_kbhit()){
    					getch();
    					ret = Send(s,"--cancelJoin");
    					break;
					}
    				ret = Send(s,"--getWaitStatus");
    				get;
    				string res = buf;
    				if(res == "OK!"){
    					bool isdo = false,isedo = false;
						ret = Send(s,"--getEnemyName"); 
						get;
						string ename = buf;
						if(ename == "--Ohno"){
							cout<<"你的对手掉线了……";
							break; 
						}
						cout<<"匹配成功!你的对手为"<<ename<<'\n';
						sum++;
						Sleep(600);
						int lastRe = time(0);
						int you = 0;
    					while(1){
    						if(!_kbhit()){
    							if(time(0) - lastRe < 1)
    								continue;
    							system("cls");
    							ret = Send(s,"--getEnemyStatus");
    							get;
    							string ss = buf;
    							if(ss == "--Ohno"){
    								cout<<"你的对手掉线了!\n";
    								break;
								}
								if(ss=="ok") 
									isedo = true;
								cout<<"你"<<(isdo?"出了\n":"没出\n");
								cout<<"你的出手:"<<hd[you]; 
    							cout<<"你:"<<username<<(isdo?"已出手\n":"尚未出手\n");
    							cout<<"对手:"<<ename<<(isedo?"已出手\n":"尚未出手\n"); 
    							cout<<"\n\n你要出?(1=石头、2=剪刀、3=布)\n";
    							if(isdo && ss == "ok"){
    								ret = Send(s,"--getResult");
    								get;
    								string res = buf;
    								if(res != "--wait"){
    									system("cls");
//    									cerr<<res<<'\n';
	    								if(res == "--draw")
	    									cout<<"平局!\n",draw++;
	    								if(res == "--win")
	    									cout<<"胜利!\n",win++;
	    								if(res == "--lose")
	    									cout<<"失败!\n",lose++;
	    								system("pause");
	    								break;
									}
								}
								lastRe = time(0);
							} else if(!isdo) {
								char ch = getch();
								if(ch == '1')
									ret = Send(s,"--rock"),you = 1;
								else if(ch == '2')
									ret = Send(s,"--scissor"),you = 2;
								else if(ch == '3')
									ret = Send(s,"--paper"),you = 3;
								else
									continue; 
								isdo = true;
								lastRe = 0;
							} else
								getch(),lastRe = 0;
						}
    					break;
					}
				}
			}else if(choice == 2){
				system("cls");
				cout<<"决斗\n\n你好,"<<username<<"!\n在过去的"<<sum<<"场决斗中,你的战绩如下:\n胜:"<<win<<"场\n负:"<<lose<<"场\n平:"<<draw<<"场\n网络/其它故障:"<<sum-win-lose-draw<<"场\n"; 
    			system("pause");
			} else if(choice == 3){
				system("cls");
				cout<<"你是弱智吗?"; 
    			system("pause");
			}
			Sleep(200); 
		}while (ret != SOCKET_ERROR && ret != 0);
    } while (ret != SOCKET_ERROR && ret != 0);
	cout<<"The server was closed\n";

    //4.关闭监听套接字
    closesocket(s);

    //清理winsock2的环境
    WSACleanup();
    getchar();
    getchar();
    getchar();
    getchar();

    return 0;
}
2024/7/22 17:02
加载中...