专栏文章

Ultimate Tik Tak Toe

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mioo3hrs
此快照首次捕获于
2025/12/02 22:22
3 个月前
此快照最后确认于
2025/12/02 22:22
3 个月前
查看原文
Ultimate Tik Tak Toe游戏。
支持局域网联机和单人与MINMAX对站(很难打)
坐标的表示非常简单:
TEXT
   |   |
 1 | 2 | 3
   |   |
---+---+---
   |   |
 4 | 5 |  6
   |   |
---+---+---
   |   |
 7 | 8 |  9
   |   |
表示为 (大格子编号,小格子编号)
不会规则的网上搜,你不一定是先手,你是蓝方。
注意,对于MINMAX,程序卡了5秒以内是正常现象,因为MINMAX的搜索层数达到了7层!如果想要减轻难度/提高运行速度,修改第二行的 DIFFICULTY
源码
大号UI版本CPP
#include<bits/stdc++.h>
#define DIFFICULTY 7
#include<windows.h>
using namespace std;
const char EMPTY='.';
const char PLAYER_X='X';
const char PLAYER_O='O';
const char TIE='T';
mt19937 rng(time(0));
void color(int r,int g,int b)
	{wprintf(L"\x1b[38;2;%d;%d;%dm",r,g,b);}
void HideCursor(){
	CONSOLE_CURSOR_INFO cursor_info={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
using namespace std;
void gotoxy(int x, int y){
	HANDLE hout;
	COORD pos;
	pos.X=x;
	pos.Y=y;
	hout=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hout, pos);
}
class SmallBoard{
public:
    char board[3][3];
    char winner;
    SmallBoard(){
        for(int i=0;i<3;i++)for(int j=0;j<3;j++)
		board[i][j]=EMPTY;winner=EMPTY;
    }
    bool makeMove(int row,int col,char player){
        if(row<0||row>=3||col<0||col>=3||board[row][col]
		!=EMPTY||winner!=EMPTY)return false;
        board[row][col]=player;checkWinner();
        return true;
    }
    void checkWinner(){
        for(int i=0;i<3;i++)
            if(board[i][0]!=EMPTY&&board[i][0]==
			board[i][1]&&board[i][0]==board[i][2]){
                winner=board[i][0];return;}
        for(int j=0;j<3;j++)
            if(board[0][j]!=EMPTY&&board[0][j]==
			board[1][j]&&board[0][j]==board[2][j]){
                winner=board[0][j];return;}
        if(board[0][0]!=EMPTY&&board[0][0]==
		board[1][1]&&board[0][0]==board[2][2]){
            winner=board[0][0];return;}
        if(board[0][2]!=EMPTY&&board[0][2]==
		board[1][1]&&board[0][2]==board[2][0]){
            winner=board[0][2];return;}
        bool isFull=true;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++)
                if(board[i][j]==EMPTY){
                    isFull=false;break;}
            if (!isFull)break;
        }
        if(isFull)winner=TIE;
    }
};
class UltimateBoard{
public:
    SmallBoard boards[3][3];
    char currentPlayer;
    int nextBoardRow;
    int nextBoardCol;
    bool gameOver;
    char ultimateWinner;
    UltimateBoard():currentPlayer(PLAYER_X),nextBoardRow(-1)
	,nextBoardCol(-1),gameOver(false),ultimateWinner(EMPTY){}
    bool makeMove(int bigRow,int bigCol,int smallRow,int smallCol){
        if(gameOver)return false;
        if(nextBoardRow!=-1&&nextBoardCol!=-1&&(bigRow!=
		nextBoardRow||bigCol!=nextBoardCol))return false;
        if(boards[bigRow][bigCol].winner!=EMPTY)return false;
        if(!boards[bigRow][bigCol].makeMove
		(smallRow,smallCol,currentPlayer))return false;
        checkUltimateWinner();
		nextBoardRow=smallRow;nextBoardCol=smallCol;
        if(boards[nextBoardRow][nextBoardCol].winner!=EMPTY)
            nextBoardRow=-1,nextBoardCol=-1;
        currentPlayer=(currentPlayer==PLAYER_X)?PLAYER_O:PLAYER_X;
        return true;
    }
    void checkUltimateWinner(){
        for(int i=0;i<3;i++){
            if(boards[i][0].winner==PLAYER_X&& boards[i][1].
			winner==PLAYER_X&&boards[i][2].winner==PLAYER_X){
                gameOver=true;ultimateWinner=PLAYER_X;return;}
            if(boards[i][0].winner==PLAYER_O&& boards[i][1].
			winner==PLAYER_O&&boards[i][2].winner==PLAYER_O){
                gameOver=true;ultimateWinner=PLAYER_O;return;}
        }
        for(int j=0;j<3;j++){
            if(boards[0][j].winner==PLAYER_X&&boards[1][j].
			winner==PLAYER_X&&boards[2][j].winner==PLAYER_X){
                gameOver=true;ultimateWinner=PLAYER_X;return;}
            if(boards[0][j].winner==PLAYER_O&&boards[1][j].
			winner==PLAYER_O&&boards[2][j].winner==PLAYER_O){
                gameOver=true;ultimateWinner=PLAYER_O;return;}
        }
        if(boards[0][0].winner==PLAYER_X&&boards[1][1].
		winner==PLAYER_X&&boards[2][2].winner==PLAYER_X){
            gameOver=true;ultimateWinner=PLAYER_X;return;}
        if(boards[0][2].winner==PLAYER_X&&boards[1][1].
		winner==PLAYER_X&&boards[2][0].winner==PLAYER_X){
            gameOver=true;ultimateWinner=PLAYER_X;return;}
        if(boards[0][0].winner==PLAYER_O&&boards[1][1].
		winner==PLAYER_O&&boards[2][2].winner==PLAYER_O){
			gameOver=true;ultimateWinner=PLAYER_O;return;}
        if(boards[0][2].winner==PLAYER_O&&boards[1][1].
		winner==PLAYER_O&&boards[2][0].winner==PLAYER_O){
            gameOver=true;ultimateWinner=PLAYER_O;return;}
        bool isFull=true;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++)
                if(boards[i][j].winner==EMPTY){
                    isFull=false;
                    break;
                }
            if(!isFull)break;
        }
        if(isFull){
            gameOver=true;
            ultimateWinner=TIE;
        }
    }
	tuple<int,int,int> down(char w){
		if(w==PLAYER_O)return make_tuple(200,10,10);
		else if(w==PLAYER_X)return make_tuple(10,150,150);
		else if(w==TIE)return make_tuple(120,120,120);
		else return make_tuple(50,50,50);
	}
	void print_square(int x,int y){
		int rol=(y-3)/8,col=(x-4)/16;
		tuple<int,int,int>c;
		gotoxy(x,y);
		c=down(boards[rol][col].board[0][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		color(120,120,120);cout<<"■";
		c=down(boards[rol][col].board[0][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		color(120,120,120);cout<<"■";
		c=down(boards[rol][col].board[0][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		gotoxy(x,y+1);
		color(120,120,120);cout<<"■■■■■";
		gotoxy(x,y+2);
		c=down(boards[rol][col].board[1][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		color(120,120,120);cout<<"■";
		c=down(boards[rol][col].board[1][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		color(120,120,120);cout<<"■";
		c=down(boards[rol][col].board[1][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		gotoxy(x,y+3);
		color(120,120,120);cout<<"■■■■■";
		gotoxy(x,y+4);
		c=down(boards[rol][col].board[2][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		color(120,120,120);cout<<"■";
		c=down(boards[rol][col].board[2][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		color(120,120,120);cout<<"■";
		c=down(boards[rol][col].board[2][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
	}
    void print(){
		color(200,200,200);
		puts("\
                        \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
 ■■■■■■■■■■■■■■■■■■■■■■■\n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
 ■■■■■■■■■■■■■■■■■■■■■■■\n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \n\
        ■       ■       \
");
		color(120,120,120);
		for(int y=3;y<=19;y+=8)
			for(int x=4;x<=36;x+=16)
				print_square(x,y);
	}	
    vector<pair<pair<int,int>,pair<int,int>>>getPossibleMoves()const{
        vector<pair<pair<int,int>,pair<int,int>>>moves;
        if(gameOver)return moves;
        vector<pair<int,int>>bigBoardsToCheck;
        if(nextBoardRow==-1||nextBoardCol==-1){
            for(int i=0;i<3;i++)for(int j=0;j<3;j++)
                if(boards[i][j].winner==EMPTY)bigBoardsToCheck.emplace_back(i,j);
        }else bigBoardsToCheck.emplace_back(nextBoardRow,nextBoardCol);
        for(const auto& bigPos:bigBoardsToCheck){
            int bigRow=bigPos.first;
            int bigCol=bigPos.second;
            for(int smallRow=0;smallRow<3;smallRow++)
                for(int smallCol=0;smallCol<3;smallCol++)
                    if(boards[bigRow][bigCol].board[smallRow][smallCol]==EMPTY)
                        moves.emplace_back(make_pair(bigRow,bigCol),make_pair(smallRow,smallCol));
        }
        return moves;
    }
    int evaluate()const{
        if(gameOver)
            if(ultimateWinner==PLAYER_X)return 1000;
            else if(ultimateWinner==PLAYER_O)return -1000;
            else return 0;
        int score=0;
        for(int i=0;i<3;i++)for(int j=0;j<3;j++)
            if(boards[i][j].winner==PLAYER_X)score+=10;
            else if(boards[i][j].winner==PLAYER_O)score-=10;
            else for(int x=0;x<3;x++)for(int y=0;y<3;y++)
                if(boards[i][j].board[x][y]==PLAYER_X)score+=1;
                else if(boards[i][j].board[x][y]==PLAYER_O)score-=1;
        return score;
    }
};
class AI{
public:
    pair<pair<int,int>,pair<int,int>>findBestMove(UltimateBoard& board,int depth,bool isMaximizing){
        vector<pair<pair<int,int>,pair<int,int>>>bestMoves;
        int bestValue=isMaximizing?-numeric_limits<int>::max():numeric_limits<int>::max();
        vector<pair<pair<int,int>,pair<int,int>>>possibleMoves=board.getPossibleMoves();
        for(const auto& move:possibleMoves){
            UltimateBoard newBoard=board;
            newBoard.makeMove(move.first.first,move.first.second,move.second.first,move.second.second);
            int moveValue=minimax(newBoard,depth-1,
			-numeric_limits<int>::max(),numeric_limits<int>::max(),!isMaximizing);
            if((isMaximizing&&moveValue>bestValue)||(!isMaximizing&&moveValue<bestValue))
                bestValue=moveValue,bestMoves.clear(),bestMoves.push_back(move);
            else if(moveValue==bestValue)bestMoves.push_back(move);
        }
        if(!bestMoves.empty()){
            uniform_int_distribution<int>dist(0,bestMoves.size()-1);
            return bestMoves[dist(rng)];
        }
        return make_pair(make_pair(-1,-1),make_pair(-1,-1));
    }
private:
    int minimax(UltimateBoard& board,int depth,int alpha,int beta,bool isMaximizing){
        if(depth==0||board.gameOver)
            return board.evaluate();
        if(isMaximizing){
            int maxEval=-numeric_limits<int>::max();
            vector<pair<pair<int,int>,pair<int,int>>>possibleMoves=board.getPossibleMoves();
            for (const auto& move:possibleMoves){
                UltimateBoard newBoard=board;
                newBoard.makeMove(move.first.first,move.first.second,move.second.first,move.second.second);
                int eval=minimax(newBoard,depth-1,alpha,beta,false);
                maxEval=max(maxEval,eval);
                alpha=max(alpha, eval);
                if(beta<=alpha)break;
            }
            return maxEval;
        }
		else{
            int minEval=numeric_limits<int>::max();
            vector<pair<pair<int,int>,pair<int,int>>>possibleMoves=board.getPossibleMoves();
            for(const auto& move:possibleMoves){
                UltimateBoard newBoard=board;
                newBoard.makeMove(move.first.first,move.first.second,move.second.first,move.second.second);
                int eval=minimax(newBoard,depth-1,alpha,beta,true);
                minEval=min(minEval, eval);
                beta=min(beta,eval);
                if(beta<=alpha)break;
            }
            return minEval;
        }
    }
};
void setsize(int col, int row){
	char cmd[64];
	sprintf(cmd,"mode con cols=%d lines=%d",col,row);
	system(cmd);
}
int main() {
	HideCursor();
	setsize(50,29);
	SetConsoleTitle("Tik Tak Toe - PLUS");
	SetWindowLongPtrA(GetConsoleWindow(),GWL_STYLE,GetWindowLongPtrA(
	GetConsoleWindow(),GWL_STYLE)&~WS_SIZEBOX&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX);
	DWORD mode;GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	if(hOut==INVALID_HANDLE_VALUE)return GetLastError();DWORD dwMode=0;
	if(!GetConsoleMode(hOut,&dwMode))return GetLastError();dwMode|=0x0004;
	if(!SetConsoleMode(hOut,dwMode))return GetLastError();
    UltimateBoard board;AI ai;
    pair<pair<int,int>,pair<int,int>>bestMove;
    board.currentPlayer=(rng()&1)?PLAYER_X:PLAYER_O;
    while(!board.gameOver){
        if(board.currentPlayer==PLAYER_X){
        	system("cls");
        	int z[3][3]={{1,2,3},{4,5,6},{7,8,9},};
        	int a,b,zl[10][2]={{0,0},{0,0},{0,1},
			{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
			color(230,230,230);
        	cout<<"AI在 ("<<z[bestMove.first.first][bestMove.first.second]<<" "
                 <<z[bestMove.second.first][bestMove.second.second]<<") 下棋"<<endl;
       		board.print();
			gotoxy(0,25);color(230,230,230);
			cout<<"你的回合: ";cin>>a>>b;
            if(!board.makeMove(zl[a][0],zl[a][1],zl[b][0],zl[b][1])){
                cout<<"无效的走法,请重试!"<<endl;
                Sleep(1000);continue;
            }
        }
		else bestMove=ai.findBestMove(board,DIFFICULTY,false),
            board.makeMove(bestMove.first.first,bestMove.first.second,
						bestMove.second.first,bestMove.second.second);
    }
	system("cls");
    board.print();
    gotoxy(0,25);color(230,230,230);
    if(board.ultimateWinner==PLAYER_X)
        cout<<"恭喜你赢了!"<<endl;
    else if(board.ultimateWinner==PLAYER_O) 
        cout<<"连人机都赢不了,太逊了!"<<endl;
    else cout<<"平局,还行!"<<endl;
    Sleep(10000);
    return 0;
}
小型UI版本CPP
#include<bits/stdc++.h>
#define DIFFICULTY 7
#include<windows.h>
using namespace std;
const char EMPTY='.';
const char PLAYER_X='X';
const char PLAYER_O='O';
const char TIE='T';
mt19937 rng(time(0));
void color(int r,int g,int b)
	{wprintf(L"\x1b[38;2;%d;%d;%dm",r,g,b);}
void HideCursor(){
	CONSOLE_CURSOR_INFO cursor_info={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
using namespace std;
void gotoxy(int x, int y){
	HANDLE hout;
	COORD pos;
	pos.X=x;
	pos.Y=y;
	hout=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hout, pos);
}
class SmallBoard{
public:
    char board[3][3];
    char winner;
    SmallBoard(){
        for(int i=0;i<3;i++)for(int j=0;j<3;j++)
		board[i][j]=EMPTY;winner=EMPTY;
    }
    bool makeMove(int row,int col,char player){
        if(row<0||row>=3||col<0||col>=3||board[row][col]
		!=EMPTY||winner!=EMPTY)return false;
        board[row][col]=player;checkWinner();
        return true;
    }
    void checkWinner(){
        for(int i=0;i<3;i++)
            if(board[i][0]!=EMPTY&&board[i][0]==
			board[i][1]&&board[i][0]==board[i][2]){
                winner=board[i][0];return;}
        for(int j=0;j<3;j++)
            if(board[0][j]!=EMPTY&&board[0][j]==
			board[1][j]&&board[0][j]==board[2][j]){
                winner=board[0][j];return;}
        if(board[0][0]!=EMPTY&&board[0][0]==
		board[1][1]&&board[0][0]==board[2][2]){
            winner=board[0][0];return;}
        if(board[0][2]!=EMPTY&&board[0][2]==
		board[1][1]&&board[0][2]==board[2][0]){
            winner=board[0][2];return;}
        bool isFull=true;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++)
                if(board[i][j]==EMPTY){
                    isFull=false;break;}
            if (!isFull)break;
        }
        if(isFull)winner=TIE;
    }
};
class UltimateBoard{
public:
    SmallBoard boards[3][3];
    char currentPlayer;
    int nextBoardRow;
    int nextBoardCol;
    bool gameOver;
    char ultimateWinner;
    UltimateBoard():currentPlayer(PLAYER_X),nextBoardRow(-1)
	,nextBoardCol(-1),gameOver(false),ultimateWinner(EMPTY){}
    bool makeMove(int bigRow,int bigCol,int smallRow,int smallCol){
        if(gameOver)return false;
        if(nextBoardRow!=-1&&nextBoardCol!=-1&&(bigRow!=
		nextBoardRow||bigCol!=nextBoardCol))return false;
        if(boards[bigRow][bigCol].winner!=EMPTY)return false;
        if(!boards[bigRow][bigCol].makeMove
		(smallRow,smallCol,currentPlayer))return false;
        checkUltimateWinner();
		nextBoardRow=smallRow;nextBoardCol=smallCol;
        if(boards[nextBoardRow][nextBoardCol].winner!=EMPTY)
            nextBoardRow=-1,nextBoardCol=-1;
        currentPlayer=(currentPlayer==PLAYER_X)?PLAYER_O:PLAYER_X;
        return true;
    }
    void checkUltimateWinner(){
        for(int i=0;i<3;i++){
            if(boards[i][0].winner==PLAYER_X&& boards[i][1].
			winner==PLAYER_X&&boards[i][2].winner==PLAYER_X){
                gameOver=true;ultimateWinner=PLAYER_X;return;}
            if(boards[i][0].winner==PLAYER_O&& boards[i][1].
			winner==PLAYER_O&&boards[i][2].winner==PLAYER_O){
                gameOver=true;ultimateWinner=PLAYER_O;return;}
        }
        for(int j=0;j<3;j++){
            if(boards[0][j].winner==PLAYER_X&&boards[1][j].
			winner==PLAYER_X&&boards[2][j].winner==PLAYER_X){
                gameOver=true;ultimateWinner=PLAYER_X;return;}
            if(boards[0][j].winner==PLAYER_O&&boards[1][j].
			winner==PLAYER_O&&boards[2][j].winner==PLAYER_O){
                gameOver=true;ultimateWinner=PLAYER_O;return;}
        }
        if(boards[0][0].winner==PLAYER_X&&boards[1][1].
		winner==PLAYER_X&&boards[2][2].winner==PLAYER_X){
            gameOver=true;ultimateWinner=PLAYER_X;return;}
        if(boards[0][2].winner==PLAYER_X&&boards[1][1].
		winner==PLAYER_X&&boards[2][0].winner==PLAYER_X){
            gameOver=true;ultimateWinner=PLAYER_X;return;}
        if(boards[0][0].winner==PLAYER_O&&boards[1][1].
		winner==PLAYER_O&&boards[2][2].winner==PLAYER_O){
			gameOver=true;ultimateWinner=PLAYER_O;return;}
        if(boards[0][2].winner==PLAYER_O&&boards[1][1].
		winner==PLAYER_O&&boards[2][0].winner==PLAYER_O){
            gameOver=true;ultimateWinner=PLAYER_O;return;}
        bool isFull=true;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++)
                if(boards[i][j].winner==EMPTY){
                    isFull=false;
                    break;
                }
            if(!isFull)break;
        }
        if(isFull){
            gameOver=true;
            ultimateWinner=TIE;
        }
    }
	tuple<int,int,int> down(char w){
		if(w==PLAYER_O)return make_tuple(200,10,10);
		else if(w==PLAYER_X)return make_tuple(10,150,150);
		else if(w==TIE)return make_tuple(120,120,120);
		else return make_tuple(50,50,50);
	}
	void print_square(int x,int y){
		int rol=(y-3)/6,col=(x-4)/12;
		tuple<int,int,int>c;
		gotoxy(x,y);
		c=down(boards[rol][col].board[0][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[0][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[0][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		gotoxy(x,y+1);
		c=down(boards[rol][col].board[1][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[1][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[1][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		gotoxy(x,y+2);
		c=down(boards[rol][col].board[2][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[2][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[2][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
	}
    void print(){
		color(200,200,200);
		puts("\
                  \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
 ■■■■■■■■■■■■■■■■■\n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
 ■■■■■■■■■■■■■■■■■\n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \
");
		color(120,120,120);
		for(int y=3;y<=15;y+=6)
			for(int x=4;x<=28;x+=12)
				print_square(x,y);
	}	
    vector<pair<pair<int,int>,pair<int,int>>>getPossibleMoves()const{
        vector<pair<pair<int,int>,pair<int,int>>>moves;
        if(gameOver)return moves;
        vector<pair<int,int>>bigBoardsToCheck;
        if(nextBoardRow==-1||nextBoardCol==-1){
            for(int i=0;i<3;i++)for(int j=0;j<3;j++)
                if(boards[i][j].winner==EMPTY)bigBoardsToCheck.emplace_back(i,j);
        }else bigBoardsToCheck.emplace_back(nextBoardRow,nextBoardCol);
        for(const auto& bigPos:bigBoardsToCheck){
            int bigRow=bigPos.first;
            int bigCol=bigPos.second;
            for(int smallRow=0;smallRow<3;smallRow++)
                for(int smallCol=0;smallCol<3;smallCol++)
                    if(boards[bigRow][bigCol].board[smallRow][smallCol]==EMPTY)
                        moves.emplace_back(make_pair(bigRow,bigCol),make_pair(smallRow,smallCol));
        }
        return moves;
    }
    int evaluate()const{
        if(gameOver)
            if(ultimateWinner==PLAYER_X)return 1000;
            else if(ultimateWinner==PLAYER_O)return -1000;
            else return 0;
        int score=0;
        for(int i=0;i<3;i++)for(int j=0;j<3;j++)
            if(boards[i][j].winner==PLAYER_X)score+=10;
            else if(boards[i][j].winner==PLAYER_O)score-=10;
            else for(int x=0;x<3;x++)for(int y=0;y<3;y++)
                if(boards[i][j].board[x][y]==PLAYER_X)score+=1;
                else if(boards[i][j].board[x][y]==PLAYER_O)score-=1;
        return score;
    }
};
class AI{
public:
    pair<pair<int,int>,pair<int,int>>findBestMove(UltimateBoard& board,int depth,bool isMaximizing){
        vector<pair<pair<int,int>,pair<int,int>>>bestMoves;
        int bestValue=isMaximizing?-numeric_limits<int>::max():numeric_limits<int>::max();
        vector<pair<pair<int,int>,pair<int,int>>>possibleMoves=board.getPossibleMoves();
        for(const auto& move:possibleMoves){
            UltimateBoard newBoard=board;
            newBoard.makeMove(move.first.first,move.first.second,move.second.first,move.second.second);
            int moveValue=minimax(newBoard,depth-1,
			-numeric_limits<int>::max(),numeric_limits<int>::max(),!isMaximizing);
            if((isMaximizing&&moveValue>bestValue)||(!isMaximizing&&moveValue<bestValue))
                bestValue=moveValue,bestMoves.clear(),bestMoves.push_back(move);
            else if(moveValue==bestValue)bestMoves.push_back(move);
        }
        if(!bestMoves.empty()){
            uniform_int_distribution<int>dist(0,bestMoves.size()-1);
            return bestMoves[dist(rng)];
        }
        return make_pair(make_pair(-1,-1),make_pair(-1,-1));
    }
private:
    int minimax(UltimateBoard& board,int depth,int alpha,int beta,bool isMaximizing){
        if(depth==0||board.gameOver)
            return board.evaluate();
        if(isMaximizing){
            int maxEval=-numeric_limits<int>::max();
            vector<pair<pair<int,int>,pair<int,int>>>possibleMoves=board.getPossibleMoves();
            for (const auto& move:possibleMoves){
                UltimateBoard newBoard=board;
                newBoard.makeMove(move.first.first,move.first.second,move.second.first,move.second.second);
                int eval=minimax(newBoard,depth-1,alpha,beta,false);
                maxEval=max(maxEval,eval);
                alpha=max(alpha, eval);
                if(beta<=alpha)break;
            }
            return maxEval;
        }
		else{
            int minEval=numeric_limits<int>::max();
            vector<pair<pair<int,int>,pair<int,int>>>possibleMoves=board.getPossibleMoves();
            for(const auto& move:possibleMoves){
                UltimateBoard newBoard=board;
                newBoard.makeMove(move.first.first,move.first.second,move.second.first,move.second.second);
                int eval=minimax(newBoard,depth-1,alpha,beta,true);
                minEval=min(minEval, eval);
                beta=min(beta,eval);
                if(beta<=alpha)break;
            }
            return minEval;
        }
    }
};
void setsize(int col, int row){
	char cmd[64];
	sprintf(cmd,"mode con cols=%d lines=%d",col,row);
	system(cmd);
}
int main() {
	HideCursor();
	setsize(38,24);
	SetConsoleTitle("Tik Tak Toe - PLUS");
	SetWindowLongPtrA(GetConsoleWindow(),GWL_STYLE,GetWindowLongPtrA(
	GetConsoleWindow(),GWL_STYLE)&~WS_SIZEBOX&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX);
	DWORD mode;GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	if(hOut==INVALID_HANDLE_VALUE)return GetLastError();DWORD dwMode=0;
	if(!GetConsoleMode(hOut,&dwMode))return GetLastError();dwMode|=0x0004;
	if(!SetConsoleMode(hOut,dwMode))return GetLastError();
    UltimateBoard board;AI ai;
    pair<pair<int,int>,pair<int,int>>bestMove;
    board.currentPlayer=(rng()&1)?PLAYER_X:PLAYER_O;
    while(!board.gameOver){
        if(board.currentPlayer==PLAYER_X){
        	system("cls");
        	int z[3][3]={{1,2,3},{4,5,6},{7,8,9},};
        	int a,b,zl[10][2]={{0,0},{0,0},{0,1},
			{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
			color(230,230,230);
        	cout<<"AI在 ("<<z[bestMove.first.first][bestMove.first.second]<<" "
                 <<z[bestMove.second.first][bestMove.second.second]<<") 下棋"<<endl;
       		board.print();
			gotoxy(0,20);color(230,230,230);
			cout<<"你的回合: ";cin>>a>>b;
            if(!board.makeMove(zl[a][0],zl[a][1],zl[b][0],zl[b][1])){
                cout<<"无效的走法,请重试!"<<endl;
                Sleep(1000);continue;
            }
        }
		else bestMove=ai.findBestMove(board,DIFFICULTY,false),
            board.makeMove(bestMove.first.first,bestMove.first.second,
						bestMove.second.first,bestMove.second.second);
    }
	system("cls");
    board.print();
    gotoxy(0,20);color(230,230,230);
    if(board.ultimateWinner==PLAYER_X)
        cout<<"恭喜你赢了!"<<endl;
    else if(board.ultimateWinner==PLAYER_O) 
        cout<<"连人机都赢不了,太逊了!"<<endl;
    else cout<<"平局,还行!"<<endl;
    Sleep(10000);
    return 0;
}
局域网联机版本(支持randmin等虚拟局域网)CPP
#include<bits/stdc++.h>
#include<winsock2.h>
#include<ws2tcpip.h>
#include<windows.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
const char EMPTY='.';
const char PLAYER_X='X';
const char PLAYER_O='O';
const char TIE='T';
const int PORT = 55555;
const int BUFFER_SIZE = 1024;
mt19937 rng(time(0));
void color(int r,int g,int b)
	{wprintf(L"\x1b[38;2;%d;%d;%dm",r,g,b);}
void HideCursor(){
	CONSOLE_CURSOR_INFO cursor_info={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
bool InitializeWinsock(){
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){
        cerr<<"WSAStartup failed."<<endl;
        return false;
    }
    return true;
}
void setsize(int col, int row){
	char cmd[64];
	sprintf(cmd,"mode con cols=%d lines=%d",col,row);
	system(cmd);
}
int InitializeUI(){
	setsize(38,24);
	SetConsoleTitle("Ultimate Tik Tak Toe - Online");
	SetWindowLongPtrA(GetConsoleWindow(),GWL_STYLE,GetWindowLongPtrA(
	GetConsoleWindow(),GWL_STYLE)&~WS_SIZEBOX&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX);
	DWORD mode;GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	if(hOut==INVALID_HANDLE_VALUE)return GetLastError();DWORD dwMode=0;
	if(!GetConsoleMode(hOut,&dwMode))return GetLastError();dwMode|=0x0004;
	if(!SetConsoleMode(hOut,dwMode))return GetLastError();return 0;
}
void gotoxy(int x, int y){
	HANDLE hout;
	COORD pos;
	pos.X=x;
	pos.Y=y;
	hout=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hout, pos);
}
class SmallBoard{
public:
    char board[3][3];
    char winner;
    SmallBoard(){
        for(int i=0;i<3;i++)for(int j=0;j<3;j++)
		board[i][j]=EMPTY;winner=EMPTY;
    }
    bool makeMove(int row,int col,char player){
        if(row<0||row>=3||col<0||col>=3||board[row][col]
		!=EMPTY||winner!=EMPTY)return false;
        board[row][col]=player;checkWinner();
        return true;
    }
    void checkWinner(){
        for(int i=0;i<3;i++)
            if(board[i][0]!=EMPTY&&board[i][0]==
			board[i][1]&&board[i][0]==board[i][2]){
                winner=board[i][0];return;}
        for(int j=0;j<3;j++)
            if(board[0][j]!=EMPTY&&board[0][j]==
			board[1][j]&&board[0][j]==board[2][j]){
                winner=board[0][j];return;}
        if(board[0][0]!=EMPTY&&board[0][0]==
		board[1][1]&&board[0][0]==board[2][2]){
            winner=board[0][0];return;}
        if(board[0][2]!=EMPTY&&board[0][2]==
		board[1][1]&&board[0][2]==board[2][0]){
            winner=board[0][2];return;}
        bool isFull=true;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++)
                if(board[i][j]==EMPTY){
                    isFull=false;break;}
            if (!isFull)break;
        }
        if(isFull)winner=TIE;
    }
};
class UltimateBoard{
public:
    SmallBoard boards[3][3];
    char currentPlayer;
    int nextBoardRow;
    int nextBoardCol;
    bool gameOver;
    char ultimateWinner;
    UltimateBoard():currentPlayer(PLAYER_X),nextBoardRow(-1)
	,nextBoardCol(-1),gameOver(false),ultimateWinner(EMPTY){}
    bool makeMove(int bigRow,int bigCol,int smallRow,int smallCol){
        if(gameOver)return false;
        if(nextBoardRow!=-1&&nextBoardCol!=-1&&(bigRow!=
		nextBoardRow||bigCol!=nextBoardCol))return false;
        if(boards[bigRow][bigCol].winner!=EMPTY)return false;
        if(!boards[bigRow][bigCol].makeMove
		(smallRow,smallCol,currentPlayer))return false;
        checkUltimateWinner();
		nextBoardRow=smallRow;nextBoardCol=smallCol;
        if(boards[nextBoardRow][nextBoardCol].winner!=EMPTY)
            nextBoardRow=-1,nextBoardCol=-1;
        currentPlayer=(currentPlayer==PLAYER_X)?PLAYER_O:PLAYER_X;
        return true;
    }
    void checkUltimateWinner(){
        for(int i=0;i<3;i++){
            if(boards[i][0].winner==PLAYER_X&& boards[i][1].
			winner==PLAYER_X&&boards[i][2].winner==PLAYER_X){
                gameOver=true;ultimateWinner=PLAYER_X;return;}
            if(boards[i][0].winner==PLAYER_O&& boards[i][1].
			winner==PLAYER_O&&boards[i][2].winner==PLAYER_O){
                gameOver=true;ultimateWinner=PLAYER_O;return;}
        }
        for(int j=0;j<3;j++){
            if(boards[0][j].winner==PLAYER_X&&boards[1][j].
			winner==PLAYER_X&&boards[2][j].winner==PLAYER_X){
                gameOver=true;ultimateWinner=PLAYER_X;return;}
            if(boards[0][j].winner==PLAYER_O&&boards[1][j].
			winner==PLAYER_O&&boards[2][j].winner==PLAYER_O){
                gameOver=true;ultimateWinner=PLAYER_O;return;}
        }
        if(boards[0][0].winner==PLAYER_X&&boards[1][1].
		winner==PLAYER_X&&boards[2][2].winner==PLAYER_X){
            gameOver=true;ultimateWinner=PLAYER_X;return;}
        if(boards[0][2].winner==PLAYER_X&&boards[1][1].
		winner==PLAYER_X&&boards[2][0].winner==PLAYER_X){
            gameOver=true;ultimateWinner=PLAYER_X;return;}
        if(boards[0][0].winner==PLAYER_O&&boards[1][1].
		winner==PLAYER_O&&boards[2][2].winner==PLAYER_O){
			gameOver=true;ultimateWinner=PLAYER_O;return;}
        if(boards[0][2].winner==PLAYER_O&&boards[1][1].
		winner==PLAYER_O&&boards[2][0].winner==PLAYER_O){
            gameOver=true;ultimateWinner=PLAYER_O;return;}
        bool isFull=true;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++)
                if(boards[i][j].winner==EMPTY){
                    isFull=false;
                    break;
                }
            if(!isFull)break;
        }
        if(isFull){
            gameOver=true;
            ultimateWinner=TIE;
        }
    }
	tuple<int,int,int> down(char w){
		if(w==PLAYER_O)return make_tuple(200,10,10);
		else if(w==PLAYER_X)return make_tuple(10,150,150);
		else if(w==TIE)return make_tuple(120,120,120);
		else return make_tuple(50,50,50);
	}
	void print_square(int x,int y){
		int rol=(y-3)/6,col=(x-4)/12;
		tuple<int,int,int>c;
		gotoxy(x,y);
		c=down(boards[rol][col].board[0][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[0][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[0][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		gotoxy(x,y+1);
		c=down(boards[rol][col].board[1][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[1][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[1][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		gotoxy(x,y+2);
		c=down(boards[rol][col].board[2][0]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[2][1]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
		c=down(boards[rol][col].board[2][2]);
		if(boards[rol][col].winner!=EMPTY)
            c=down(boards[rol][col].winner);
		color(get<0>(c),get<1>(c),get<2>(c));
		cout<<"■";
	}
    void print(){
		color(200,200,200);
		puts("\
                  \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
 ■■■■■■■■■■■■■■■■■\n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
 ■■■■■■■■■■■■■■■■■\n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \n\
      ■     ■     \
");
		color(120,120,120);
		for(int y=3;y<=15;y+=6)
			for(int x=4;x<=28;x+=12)
				print_square(x,y);
	}	
    vector<pair<pair<int,int>,pair<int,int>>>getPossibleMoves()const{
        vector<pair<pair<int,int>,pair<int,int>>>moves;
        if(gameOver)return moves;
        vector<pair<int,int>>bigBoardsToCheck;
        if(nextBoardRow==-1||nextBoardCol==-1){
            for(int i=0;i<3;i++)for(int j=0;j<3;j++)
                if(boards[i][j].winner==EMPTY)bigBoardsToCheck.emplace_back(i,j);
        }else bigBoardsToCheck.emplace_back(nextBoardRow,nextBoardCol);
        for(const auto& bigPos:bigBoardsToCheck){
            int bigRow=bigPos.first;
            int bigCol=bigPos.second;
            for(int smallRow=0;smallRow<3;smallRow++)
                for(int smallCol=0;smallCol<3;smallCol++)
                    if(boards[bigRow][bigCol].board[smallRow][smallCol]==EMPTY)
                        moves.emplace_back(make_pair(bigRow,bigCol),make_pair(smallRow,smallCol));
        }
        return moves;
    }
    int evaluate()const{
        if(gameOver)
            if(ultimateWinner==PLAYER_X)return 1000;
            else if(ultimateWinner==PLAYER_O)return -1000;
            else return 0;
        int score=0;
        for(int i=0;i<3;i++)for(int j=0;j<3;j++)
            if(boards[i][j].winner==PLAYER_X)score+=10;
            else if(boards[i][j].winner==PLAYER_O)score-=10;
            else for(int x=0;x<3;x++)for(int y=0;y<3;y++)
                if(boards[i][j].board[x][y]==PLAYER_X)score+=1;
                else if(boards[i][j].board[x][y]==PLAYER_O)score-=1;
        return score;
    }
};
class LAN{
public:
void RunServer(){
	SOCKET listenSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(listenSocket==INVALID_SOCKET){
        cerr<<"Error creating socket: "<<WSAGetLastError()<<endl;
        return;
    }
    sockaddr_in serverAddr;
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_addr.s_addr=INADDR_ANY;
    serverAddr.sin_port=htons(PORT);
    if(bind(listenSocket,(sockaddr*)&serverAddr,sizeof(serverAddr))==SOCKET_ERROR){
        cerr<<"Bind failed: "<<WSAGetLastError()<<endl;
        closesocket(listenSocket);return;
    }
    if(listen(listenSocket,1)==SOCKET_ERROR){
        cerr<<"Listen failed: "<<WSAGetLastError()<<endl;
        closesocket(listenSocket);return;
    }
    cout<<"Server is waiting for client connection..."<<endl;
    SOCKET clientSocket=accept(listenSocket,NULL,NULL);
    if(clientSocket==INVALID_SOCKET) {
        cerr<<"Accept failed: "<<WSAGetLastError()<<endl;
        closesocket(listenSocket);return;
    }
    closesocket(listenSocket);
    cout<<"Client connected."<<endl;
    UltimateBoard board;
    pair<int,int>lastMove;
    board.currentPlayer=(rng()&1)?PLAYER_X:PLAYER_O;
    if(board.currentPlayer==PLAYER_X){
    	cout<<"You first."<<endl;string message="second";
    	send(clientSocket,message.c_str(),message.size()+1,0);
	}
    else{
    	cout<<"You second."<<endl;string message="first";
    	send(clientSocket,message.c_str(),message.size()+1,0);
	}
	Sleep(1500);
    char buffer[BUFFER_SIZE];
    while(!board.gameOver){
    	if(board.currentPlayer==PLAYER_X){
    		system("cls");
        	int a,b,zl[10][2]={{0,0},{0,0},{0,1},
			{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
			color(230,230,230);
        	cout<<"对方在 ("<<lastMove.first<<" "<<lastMove.second<<") 下棋"<<endl;
       		board.print();
			gotoxy(0,20);color(230,230,230);
			cout<<"你的回合: ";cin>>a>>b;
            if(!board.makeMove(zl[a][0],zl[a][1],zl[b][0],zl[b][1])){
                cout<<"无效的走法,请重试!"<<endl;
                Sleep(1000);continue;
            }
            string message=to_string(a)+" "+to_string(b);lastMove=make_pair(a,b);
            send(clientSocket,message.c_str(),message.size()+1,0);
		}
		else{
			system("cls");
			cout<<"你在 ("<<lastMove.first<<" "<<lastMove.second<<") 下棋"<<endl;
			board.print();gotoxy(0,20);color(230,230,230);cout<<"等待对方走棋...... ";
			int bytesReceived=recv(clientSocket,buffer,BUFFER_SIZE,0);
            if(bytesReceived<=0){
                cout<<"Client disconnected."<<endl;
                board.ultimateWinner=PLAYER_X;
                Sleep(1000);
                break;
            }
            string receivedStr(buffer,bytesReceived);
            size_t spacePos=receivedStr.find(' ');
            if(spacePos!=std::string::npos){
                int num1=stoi(receivedStr.substr(0,spacePos));
                int num2=stoi(receivedStr.substr(spacePos+1));
                int zl[10][2]={{0,0},{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
                board.makeMove(zl[num1][0],zl[num1][1],zl[num2][0],zl[num2][1]);
                lastMove=make_pair(num1,num2);
            }
		}
	}
	system("cls");board.print();closesocket(clientSocket);
    gotoxy(0,20);color(230,230,230);
    if(board.ultimateWinner==PLAYER_X)
        cout<<"恭喜你赢了!"<<endl;
    else if(board.ultimateWinner==PLAYER_O) 
        cout<<"竟然输了!"<<endl;
    else cout<<"平局,还行!"<<endl;
    Sleep(10000);
}
void RunClient(){
	SOCKET clientSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if (clientSocket==INVALID_SOCKET){
        cerr<<"Error creating socket: "<<WSAGetLastError()<<endl;
        return;
    }
    string serverIP;
    cout<<"Enter server IP address: ";
    cin>>serverIP;
    sockaddr_in serverAddr;
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_port=htons(PORT);
    inet_pton(AF_INET,serverIP.c_str(),&serverAddr.sin_addr);
    if(connect(clientSocket,(sockaddr*)&serverAddr,sizeof(serverAddr))==SOCKET_ERROR){
        cerr<<"Connect failed: "<<WSAGetLastError()<<endl;
        closesocket(clientSocket);return;
    }
    cout<<"Connected to server."<<endl;
    char buffer[BUFFER_SIZE];UltimateBoard board;
	int byteReceived=recv(clientSocket,buffer,BUFFER_SIZE,0);
	string firstMsg(buffer,byteReceived);
	if(firstMsg.find("first")!=string::npos){
		board.currentPlayer=PLAYER_X;
	    cout<<firstMsg<<endl;
	    cout<<"You first."<<endl;
	}
	else{
	    board.currentPlayer=PLAYER_O;
	    cout<<"You second."<<endl;
	}
	pair<int,int>lastMove;
	while(!board.gameOver){
		if(board.currentPlayer==PLAYER_X){
    		system("cls");
        	int a,b,zl[10][2]={{0,0},{0,0},{0,1},
			{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
			color(230,230,230);
        	cout<<"对方在 ("<<lastMove.first<<" "<<lastMove.second<<") 下棋"<<endl;
       		board.print();
			gotoxy(0,20);color(230,230,230);
			cout<<"你的回合: ";cin>>a>>b;
            if(!board.makeMove(zl[a][0],zl[a][1],zl[b][0],zl[b][1])){
                cout<<"无效的走法,请重试!"<<endl;
                Sleep(1000);continue;
            }
            string message=to_string(a)+" "+to_string(b);lastMove=make_pair(a,b);
            send(clientSocket,message.c_str(),message.size()+1,0);
		}
		else{
			system("cls");
			cout<<"你在 ("<<lastMove.first<<" "<<lastMove.second<<") 下棋"<<endl;
			board.print();gotoxy(0,20);color(230,230,230);cout<<"等待对方走棋...... ";
			int bytesReceived=recv(clientSocket,buffer,BUFFER_SIZE,0);
            if(bytesReceived<=0){
                cout<<"Client disconnected."<<endl;
                board.ultimateWinner=PLAYER_X;
                Sleep(1000);
                break;
            }
            string receivedStr(buffer,bytesReceived);
            size_t spacePos=receivedStr.find(' ');
            if(spacePos!=std::string::npos){
                int num1=stoi(receivedStr.substr(0,spacePos));
                int num2=stoi(receivedStr.substr(spacePos+1));
                int zl[10][2]={{0,0},{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
                board.makeMove(zl[num1][0],zl[num1][1],zl[num2][0],zl[num2][1]);
                lastMove=make_pair(num1,num2);
            }
		}
	}
	system("cls");board.print();closesocket(clientSocket);
    gotoxy(0,20);color(230,230,230);
    if(board.ultimateWinner==PLAYER_X)
        cout<<"恭喜你赢了!"<<endl;
    else if(board.ultimateWinner==PLAYER_O) 
        cout<<"竟然输了!"<<endl;
    else cout<<"平局,还行!"<<endl;
    Sleep(10000);
}
};
int main() {
	InitializeUI();
	if(!InitializeWinsock()){return 1;}int choice;
	while(true){
		cout<<"Choose mode:\n1. Server\n2. Client\nEnter choice :";
		cin>>choice;
		if(choice==1||choice==2)break;
		cout<<"Invalid choice."<<endl;
		Sleep(1000);system("cls");
	}
	LAN lan;
    if(choice==1)lan.RunServer();
    else lan.RunClient();
    return 0;
}
要开\textcolor{red}{要开} -lws2_32 的编译命令\textcolor{red}{的编译命令}
只有小UI。。。因为作者喜欢。

评论

0 条评论,欢迎与作者交流。

正在加载评论...