纯C++游戏编程: Tic-Tac-Toe(三连棋游戏)的实现

   这是在《通过游戏编程实战——教新手学C++编程》上看到的一个小游戏,感觉不错,适合新手学习C++,所以贴出来一起和大家分享!
完整代码见链接:
http://download.csdn.net/detail/rehongchen/4586263 (可在VC、CFree下成功运行)


游戏规则:
双方轮流在一个九个方格的棋盘上画十字(X)或圆圈(O),以所画的三个记号成直、横、斜线相连者为胜。

在计算机上实现,在屏幕上会显示如下窗格:
 
  0 | 1 | 2
  ---------
  3 | 4 | 5
  ---------
  6 | 7 | 8
玩家通过选择上面的数字确定选择的位置,用X表示,计算机用O表示。
创建函数列表:

函数 描述
void instructions(); 显示游戏操作指南
char askYesNo(string question);
接受一个问题,返回“y”或“n”
int askNumber(string question, int high, int low = 0); 询问一定范围内的数字。接受一个问题、一个范围上限和一个范围下限。返回low到high之间的数字
char humanPiece(); 确定玩家的棋子。返回X或O
char opponent(char piece); 返回给定棋子的对应棋子。
void displayBoard(const vector<char>& board); 在屏幕上显示当前棋盘。
char winner(const vector<char>& board); 确定游戏的胜者。返回X、O、或T(和棋)或N(还没有哪一方胜出)
bool isLegal(const vector<char>& board, int move); 判断输入的数字是否合法
int humanMove(const vector<char>& board, char human); 获取人类玩家的下棋。接受一个棋盘与人类玩家的棋子作为参数,返回玩家下棋的数字位置。
int computerMove(vector<char> board, char computer); 获取计算机玩家的下棋。接受一个棋盘与人类玩家的棋子作为参数,返回玩家下棋的数字位置。
void announceWinner(char winner, char computer, char human); 宣布最后结果。

下面从代码中分析C++语法和编程范式:
// Tic-Tac-Toe
// Plays the game of tic-tac-toe against a human opponent

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

// global constants
const char X = 'X';
const char O = 'O';
const char EMPTY = ' ';
const char TIE = 'T';
const char NO_ONE = 'N';

// function prototypes
void instructions();
char askYesNo(string question);
int askNumber(string question, int high, int low = 0);		//注:low默认为0
char humanPiece();
char opponent(char piece);
void displayBoard(const vector<char>& board);
char winner(const vector<char>& board);
bool isLegal(const vector<char>& board, int move);
int humanMove(const vector<char>& board, char human);
int computerMove(vector<char> board, char computer);
void announceWinner(char winner, char computer, char human);

// main function
int main()
{
    int move;
    const int NUM_SQUARES = 9;
    vector<char> board(NUM_SQUARES, EMPTY);

    instructions();
    const char human = humanPiece();				//确定人类是否第一步走棋,返回y或n
    const char computer = opponent(human);
    char turn = X;									//与X相同的先走棋
    displayBoard(board);							

    while (winner(board) == NO_ONE)					//验证是有胜出者
    {
        if (turn == human)
        {
            move = humanMove(board, human);			//因为用户走棋时可能不合法,所以需要在humanMove进行验证,
													
            board[move] = human;
        }
        else
        {
            move = computerMove(board, computer);	//计算机走棋时不需验证合法性,但需完成智能走棋
            board[move] = computer;
        }
        displayBoard(board);
        turn = opponent(turn);						//用以交换出棋顺序
    }

    announceWinner(winner(board), computer, human);	//宣布结果:获胜者或平手

    return 0;
}

// functions
void instructions()
{
    cout << "欢迎来到人机终极大战: Tic-Tac-Toe.\n";
    cout << "--where human brain is pit against silicon processor\n\n";

    cout << "键入数字 0 - 8来选择你选棋的位置. \n";
    cout << "它会被如实的反映在下面的棋盘上:\n\n";
    
    cout << "       0 | 1 | 2\n";
    cout << "       ---------\n";
    cout << "       3 | 4 | 5\n";
    cout << "       ---------\n";
    cout << "       6 | 7 | 8\n\n";

    cout << "准备好了吗?人类,  这场大战马上开始!\n\n";
}

char askYesNo(string question)
{
    char response;
    do
    {
        cout << question << " (y/n): ";
        cin >> response;
    } while (response != 'y' && response != 'n');

    return response;
}

int askNumber(string question, int high, int low)
{
    int number;
    do
    {
        cout << question << " (" << low << " - " << high << "): ";
        cin >> number;
    } while (number > high || number < low);		//直到获得合法结果(0-8)才能退出循环

    return number;
}

char humanPiece()	//确定人类第一步走棋
{
    char go_first = askYesNo("你确定你第一步走棋?");
    if (go_first == 'y')
    {
        cout << "\n好吧,让你先来,你走棋.\n";
        return X;
    }
    else
    {
        cout << "\n你的勇气欠佳... 我先走棋.\n";
        return O;
    }
}

char opponent(char piece)		//返回对手走棋标志
{
    if (piece == X)
	{
        return O;
	}
    else
	{
        return X;
	}
}

void displayBoard(const vector<char>& board)	//注意:这里接收棋盘的引用,展示当前棋盘布局
{
    cout << "\n\t" << board[0] << " | " << board[1] << " | " << board[2];
    cout << "\n\t" << "---------";
    cout << "\n\t" << board[3] << " | " << board[4] << " | " << board[5];
    cout << "\n\t" << "---------";
    cout << "\n\t" << board[6] << " | " << board[7] << " | " << board[8];
    cout << "\n\n";
}

char winner(const vector<char>& board)			//表示棋盘的向量是通过常量引用传递(const vector<char>&)的,
{												//传递引用非常高效,且向量被保护起来,防止任何修改

    //列出所有可能胜出的情况
    const int WINNING_ROWS[8][3] = { {0, 1, 2},
                                     {3, 4, 5},
                                     {6, 7, 8},
                                     {0, 3, 6},
                                     {1, 4, 7},
                                     {2, 5, 8},
                                     {0, 4, 8},
                                     {2, 4, 6} };
    const int TOTAL_ROWS = 8;

    // if any winning row has three values that are the same (and not EMPTY),
    // then we have a winner
	//如果有任意一行上的三个内容均相同(但不为EMPTY)
	//那么就有一方胜出
    for(int row = 0; row < TOTAL_ROWS; ++row)
    {
        if ( (board[WINNING_ROWS[row][0]] != EMPTY) &&
             (board[WINNING_ROWS[row][0]] == board[WINNING_ROWS[row][1]]) &&
             (board[WINNING_ROWS[row][1]] == board[WINNING_ROWS[row][2]]) )
        {
            return board[WINNING_ROWS[row][0]];			//返回第一个棋子的位置,也就是返回“X”或“O” 
        } 
    }

    // since nobody has won, check for a tie (no empty squares left)
	//如果没有一方胜出,看是否是平手
    if (count(board.begin(), board.end(), EMPTY) == 0)
        return TIE;

    // since nobody has won and it isn't a tie, the game ain't over
	//未见分晓
    return NO_ONE;
}

inline bool isLegal(int move, const vector<char>& board)
{
    return (board[move] == EMPTY);
}

int humanMove(const vector<char>& board, char human)
{
    int move = askNumber("你打算选哪个位置?", (board.size() - 1));
    while (!isLegal(move, board))
    {
        cout << "\n这个位置已经有棋子占据了, 愚蠢的人类.\n";
        move = askNumber("你打算选哪个位置?", (board.size() - 1));
    }
    cout << "好吧...\n";

    return move;
}

int computerMove(vector<char> board, char computer)
{ 
    unsigned int move = 0;
    bool found = false;

    //if computer can win on next move, that抯 the move to make
    while (!found && move < board.size())
    {
        if (isLegal(move, board))
        {
			//try move
            board[move] = computer;
            //test for winner
            found = winner(board) == computer;   
			//undo move
            board[move] = EMPTY;
        }

        if (!found)
        {
            ++move;
        }
    }
  
    //otherwise, if opponent can win on next move, that's the move to make
    if (!found)
    {
        move = 0;
        char human = opponent(computer);

        while (!found && move < board.size())
        {
            if (isLegal(move, board))
            {
				//try move
				board[move] = human;  
				//test for winner
                found = winner(board) == human;     
			    //undo move
				board[move] = EMPTY;        
            }

            if (!found)
            {
                ++move;
            }
        }
    }

    //otherwise, moving to the best open square is the move to make
    if (!found)
    {
        move = 0;
        unsigned int i = 0;

        const int BEST_MOVES[] = {4, 0, 2, 6, 8, 1, 3, 5, 7};
        //pick best open square
        while (!found && i <  board.size())
        {
            move = BEST_MOVES[i];
            if (isLegal(move, board))
            {
                found = true;
            }

            ++i;
        }
    }

    cout << "我选择的位置是: " << move << endl;
	return move;
}

void announceWinner(char winner, char computer, char human)
{
	if (winner == computer)
    {
        cout << winner << " 胜出!\n";
        cout << "我早就预料到了, 人类, 事实证明,我才是最优秀的。\n";
        cout << "计算机要比人类聪明!\n";
    }

	else if (winner == human)
    {
        cout << winner << "'s won!\n";
        cout << "不不!  这不是真的!  你肯定耍花招了, 人类.\n";
        cout << "但是不会又下一次了!  我,计算机,我发誓!\n";
    }

	else
    {
        cout << "平手了.\n";
        cout << "这次是你幸运, 人类, 肯定是什么操纵了这场比赛.\n";
        cout << "同样祝贺你... 因为这是你从没有过的殊荣.\n";
	}
}
如需转载,请注明出处:http://blog.csdn.net/rehongchen/article/details/8005753




没有更多推荐了,返回首页