純C++遊戲程式設計: Tic-Tac-Toe(三連棋遊戲)的實現

GeekWay發表於2012-09-21

   這是在《通過遊戲程式設計實戰——教新手學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




相關文章