《C++游戏编程入门》第6章 引用:Tic-Tac-Toe

130 篇文章 4 订阅
92 篇文章 18 订阅

6.1 使用引用

引用为变量提供另一个名称,指针的语法糖。

06.referencing.cpp
#include <iostream>
using namespace std;

int main()
{
    int myScore = 1000;
    int &mikesScore = myScore; // 创建引用,声明时必须初始化

    cout << "myScore is: " << myScore << "\n";
    cout << "mikesScore is: " << mikesScore << "\n\n"; // 访问被引用的值

    cout << "Adding 500 to myScore\n";
    myScore += 500;
    cout << "myScore is: " << myScore << "\n";
    cout << "mikesScore is: " << mikesScore << "\n\n";

    cout << "Adding 500 to mikesScore\n";
    mikesScore += 500; // 修改被引用的值
    cout << "myScore is: " << myScore << "\n";
    cout << "mikesScore is: " << mikesScore << "\n\n";

    return 0;
}

6.2 通过传递引用改变实参

函数传值时无法改变实参,而引用可以。

06.swap.cpp
#include <iostream>
using namespace std;

void badSwap(int x, int y);    // 传值不改变实参
void goodSwap(int &x, int &y); // 传引用可以改变实参

int main()
{
    int myScore = 150;
    int yourScore = 1000;
    cout << "Original values\n";
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n\n";

    cout << "Calling badSwap()\n";
    badSwap(myScore, yourScore);
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n\n";

    cout << "Calling goodSwap()\n";
    goodSwap(myScore, yourScore);
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n";

    return 0;
}

void badSwap(int x, int y)
{
    int temp = x;
    x = y;
    y = temp;
}

void goodSwap(int &x, int &y)
{
    int temp = x;
    x = y;
    y = temp;
}

6.3 传递引用以提高效率

值传递,复制,额外开销。
引用效率高,不需要实参复制。

06.inventory_displayer.cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// parameter vec is a constant reference to a vector of strings
void display(const vector<string> &inventory); // 常量引用无法修改

int main()
{
    vector<string> inventory;
    inventory.push_back("sword");
    inventory.push_back("armor");
    inventory.push_back("shield");

    display(inventory);

    return 0;
}

// parameter vec is a constant reference to a vector of strings
void display(const vector<string> &vec)
{
    cout << "Your items:\n";
    for (vector<string>::const_iterator iter = vec.begin();
         iter != vec.end(); ++iter)
    {
        cout << *iter << endl;
    }
}

6.5 返回引用

返回对象时开销可能较大,可返回引用。

06.inventory_referencer.cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// returns a reference to a string
string &refToElement(vector<string> &inventory, int i);

int main()
{
    vector<string> inventory;
    inventory.push_back("sword");
    inventory.push_back("armor");
    inventory.push_back("shield");

    // displays string that the returned reference refers to
    cout << "Sending the returned reference to cout:\n";
    cout << refToElement(inventory, 0) << "\n\n";

    // assigns one reference to another -- inexpensive assignment
    cout << "Assigning the returned reference to another reference.\n";
    string &rStr = refToElement(inventory, 1);
    cout << "Sending the new reference to cout:\n";
    cout << rStr << "\n\n";

    // copies a string object -- expensive assignment
    cout << "Assigning the returned reference to a string object.\n";
    string str = refToElement(inventory, 2);
    cout << "Sending the new string object to cout:\n";
    cout << str << "\n\n";

    // altering the string object through a returned reference
    cout << "Altering an object through a returned reference.\n";
    rStr = "Healing Potion";
    cout << "Sending the altered object to cout:\n";
    cout << inventory[1] << endl;

    return 0;
}

// returns a reference to a string
string &refToElement(vector<string> &vec, int i)
{
    return vec[i];
}

//返回引用不能指向超出作用域范围的对象(函数返回时,对象已不存在)
string &badReference()
{
    string local = "This string will cease to exist once the function ends.";
    return local;
}

6.6 Tic-Tac-Toc游戏简介

06.tic-tac-toe.cpp
#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);
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();                  // 规则介绍
    char human = humanPiece();       // 人类选择先后手
    char computer = opponent(human); // 计算机取对手
    char turn = X;                   // X先手
    displayBoard(board);             // 显示棋盘

    while (winner(board) == NO_ONE) // 未分胜负
    {
        // 当前轮次
        if (turn == human)
        {
            move = humanMove(board, human); // 人类移动
            board[move] = human;            // 下棋
        }
        else
        {
            move = computerMove(board, computer); // 计算机移动
            board[move] = computer;               // 下棋
        }
        displayBoard(board);   // 显示棋盘
        turn = opponent(turn); // 轮次交替
    }

    announceWinner(winner(board), computer, human); // 宣布获胜情况

    return 0;
}

// 显示游戏操作指南
void instructions()
{
    cout << "Welcome to the ultimate man-machine showdown: Tic-Tac-Toe.\n";
    cout << "--where human brain is pit against silicon processor\n\n";

    cout << "Make your move known by entering a number, 0 - 8.  The number\n";
    cout << "corresponds to the desired board position, as illustrated:\n\n";

    cout << "       0 | 1 | 2\n";
    cout << "       ---------\n";
    cout << "       3 | 4 | 5\n";
    cout << "       ---------\n";
    cout << "       6 | 7 | 8\n\n";

    cout << "Prepare yourself, human.  The battle is about to begin.\n\n";
}

// 一直询问,直到输入y或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);

    return number;
}

// 是否先手
char humanPiece()
{
    char go_first = askYesNo("Do you require the first move?");
    if (go_first == 'y')
    {
        cout << "\nThen take the first move.  You will need it.\n";
        return X;
    }
    else
    {
        cout << "\nYour bravery will be your undoing... I will go first.\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";
}

// 返回获胜情况
// 玩家获胜,X或O
// 方格已填满且无人获胜,T
// 方格未填满且无人获胜,N
char winner(const vector<char> &board)
{
    // 8种获胜情况
    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
    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]];
        }
    }

    // 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("Where will you move?", (board.size() - 1));
    while (!isLegal(move, board))
    {
        cout << "\nThat square is already occupied, foolish human.\n";
        move = askNumber("Where will you move?", (board.size() - 1));
    }
    cout << "Fine...\n";

    return move;
}

// 计算机获取最优下棋位置
int computerMove(vector<char> board, char computer)
{
    const unsigned NUM = board.size();
    // 遍历查找计算机能一步获胜的方格位置
    for (unsigned move = 0; move < NUM; move++)
    {
        if (isLegal(move, board)) // 当前位置为空
        {
            // 尝试移动
            board[move] = computer;
            // 测试计算机能否获胜
            if (winner(board) == computer)
                return move;
            // 撤销移动
            board[move] = EMPTY;
        }
    }

    // 遍历查找人类能一步获胜的方格位置
    char human = opponent(computer);
    for (unsigned move = 0; move < NUM; move++)
    {
        if (isLegal(move, board)) // 当前位置为空
        {
            // 尝试移动
            board[move] = human;
            // 测试人类能否获胜
            if (winner(board) == human)
                return move;
            // 撤销移动
            board[move] = EMPTY;
        }
    }

    // 中心》四边》四角
    const int BEST_MOVES[NUM] = {4, 0, 2, 6, 8, 1, 3, 5, 7};
    for (unsigned move = 0; move < NUM; move++)
        if (isLegal(BEST_MOVES[move], board))
            return move;

    return -1; // 不可能
}

// 宣布获胜情况
void announceWinner(char winner, char computer, char human)
{
    if (winner == computer)
    {
        cout << winner << "'s won!\n";
        cout << "As I predicted, human, I am triumphant once more -- proof\n";
        cout << "that computers are superior to humans in all regards.\n";
    }

    else if (winner == human)
    {
        cout << winner << "'s won!\n";
        cout << "No, no!  It cannot be!  Somehow you tricked me, human.\n";
        cout << "But never again!  I, the computer, so swear it!\n";
    }

    else
    {
        cout << "It's a tie.\n";
        cout << "You were most lucky, human, and somehow managed to tie me.\n";
        cout << "Celebrate... for this is the best you will ever achieve.\n";
    }
}
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
tic-tac-toe是一种井字棋游戏,在一个3×3的棋盘上,两名玩家轮流在空白格中放置自己的棋子,先将3颗自己的棋子连成一条直线的一方获胜。 首先,我们需要定义一个tictactoe类。这个类应该具备以下功能:初始化游戏、显示棋盘、玩家行动和判断游戏是否结束。 我们可以在类的构造函数中初始化游戏。初始化时,我们可以使用一个二维字符数组来表示棋盘,将所有的格子都赋值为空白。另外,我们需要一个变量来表示当前玩家,初始值为玩家1。我们还可以定义一个变量来表示游戏是否结束,初始值为false。 接下来,我们可以编写一个方法来显示棋盘。该方法会遍历棋盘数组,并打印每个格子的状态,例如打印空白格为"-",玩家1的棋子为"X",玩家2的棋子为"O"。 然后,我们需要编写一个方法来实现玩家的行动。该方法需要接收玩家的坐标作为参数,在指定坐标上放置当前玩家的棋子。我们需要检查这个位置是否为空,如果为空则可以放置棋子并切换当前玩家。 接下来,我们需要编写一个方法来判断游戏是否结束。我们需要检查是否有任意一方已经获胜,也就是是否有一行、一列或一条对角线上存在连成一条直线的三个相同棋子。如果有,那么游戏结束,我们将结束变量置为true。另外,如果棋盘已经满了,即所有格子都被填满,且没有任何一方获胜,那么游戏也结束。 最后,我们可以在主函数中创建一个tictactoe对象,并循环执行游戏,直到游戏结束。每次轮到一个玩家行动时,我们可以要求玩家输入一个坐标,并调用行动方法。然后显示棋盘。如果游戏结束,我们可以显示获胜方或平局的消息。 这样,我们就完成了一个简单的tic-tac-toe游戏的Java编程。通过这个例子,我们了解了如何使用类和方法来设计和实现一个游戏

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值