.. _step4: 4 重构:使用类 =============== 之前只是用到了简单的控制结构:for、while、if、switch 等,连函数都没用上。当然,这样的好处是容易把自己的想法先实现了,尽管代码很笨,又丑又长,但是思路清晰,容易理解。能够实现随机的井子棋之后,可以考虑重构代码,进一步抽象化。这里使用了类。 .. toctree:: :maxdepth: 2 4.1 TicTacToe 类 ------------------ 把之前下棋的过程,定义了一个 TicTacToe 类,分割成独立的函数,在类外定义: .. code-block:: c++ class TicTacToe { public: TicTacToe(); void begin_info(); // 输出欢迎信息 void user_choose(); // 用户下棋 void computer_choose(); // 计算机下棋 void judge_win_or_lose(); // 判断输赢 void board_info(); // 棋盘状态 void play_game(); // 下棋 private: /* 定义棋盘 board */ // 分别存储在 boundary(边界),以及 sidebar(边栏)的变量里 string boundary; string sidebar; //空白的左边栏 string split_line;// 定义分割线 string mark[3][3] ; // 定义棋子标记 mark string user_name; string bar[3] ; // 定义输出棋子的行 string piece; // 存放用户选择的棋子 int user_x, user_y, choose_number; // 存放用户的棋子坐标 int computer_x, computer_y; // 存放计算机的棋子坐标 int step; // 计算是第几步 bool win_o, win_x; // 判断输赢,是执棋子 O 的还是 X 的赢了 }; 4.2 初始化 ------------ 构造函数 ``TicTacToe()`` 初始化随机种子值,棋子变量和判断输赢的变量 .. code-block:: c++ TicTacToe::TicTacToe() { srand(time(0)); // 改变随机种子值 for (int x = 0; x < 3; ++x) // 初始化棋子为空字符串 { for (int y = 0; y <3; ++y) { mark[x][y] = " "; } } win_o = false; win_x = false; } 4.3 欢迎信息 ------------- ``begin_info()`` 输出欢迎信息,并指导用户下棋 .. code-block:: c++ void TicTacToe::begin_info() { cout << "你叫什么呀:"; cin >> user_name; cout << "\nHello, " << user_name << " ^_^" << " 选择棋子 O 还是 X :"; cin >> piece; cout << "\n棋盘如下:" << endl; boundary = "+---+---+---+"; sidebar = " "; //空白的左边栏 split_line = "------";// 定义分割线 cout << sidebar << boundary << endl; cout << sidebar << "| " << 1 << " | " << 2 << " | " << 3 << " |" << endl; cout << sidebar << boundary << endl; cout << sidebar << "| " << 4 << " | " << 5 << " | " << 6 << " |" << endl; cout << sidebar << boundary << endl; cout << sidebar << "| " << 7 << " | " << 8 << " | " << 9 << " |" << endl; cout << sidebar << boundary << endl; } 4.4 用户下棋 -------------- .. code-block:: c++ void TicTacToe::user_choose() { cout << "\n请输入下棋的位置序号(1~9):"; //用户选择的坐标值 cin >> choose_number; switch (choose_number) { case 1 : user_x = 0, user_y = 0; break; case 2 : user_x = 0, user_y = 1; break; case 3 : user_x = 0, user_y = 2; break; case 4 : user_x = 1, user_y = 0; break; case 5 : user_x = 1, user_y = 1; break; case 6 : user_x = 1, user_y = 2; break; case 7 : user_x = 2, user_y = 0; break; case 8 : user_x = 2, user_y = 1; break; case 9 : user_x = 2, user_y = 2; break; } // 判断用户选择的位置是否已经存在棋子 while (mark[user_x][user_y] == " O " || mark[user_x][user_y] == " X " ) { cout << "棋盘上已经存在棋子,请重新输入:" << endl; cout << "请输入下棋的位置序号(1~9):"; cin >> choose_number; switch (choose_number) { case 1 : user_x = 0, user_y = 0; break; case 2 : user_x = 0, user_y = 1; break; case 3 : user_x = 0, user_y = 2; break; case 4 : user_x = 1, user_y = 0; break; case 5 : user_x = 1, user_y = 1; break; case 6 : user_x = 1, user_y = 2; break; case 7 : user_x = 2, user_y = 0; break; case 8 : user_x = 2, user_y = 1; break; case 9 : user_x = 2, user_y = 2; break; } } } 4.5 计算机下棋 --------------- .. code-block:: c++ void TicTacToe::computer_choose() { computer_x = random(3), computer_y = random(3); // 随机生成坐标值 while (mark[computer_x][computer_y] != " ") // 判断是否棋盘是否已经存在这个棋子 { computer_x = random(3); computer_y = random(3); } } 4.6 判断输赢 -------------- .. code-block:: c++ void TicTacToe::judge_win_or_lose() { // 判断交叉线是否相等 if (mark[0][0] == " O " && mark [1][1] == " O " && mark[2][2] == " O ") win_o = true; if (mark[0][0] == " X " && mark [1][1] == " X " && mark[2][2] == " X ") win_x = true; if (mark[0][2] == " O " && mark [1][1] == " O " && mark[2][0] == " O ") win_o = true; if (mark[0][2] == " X " && mark [1][1] == " X " && mark[2][0] == " X ") win_x = true; // 判断行和列是否相等 for (int c = 0; c < 3; ++c) { if (mark[c][0] == " O " && mark[c][1] == " O " && mark[c][2] == " O ") win_o = true; if (mark[c][0] == " X " && mark[c][1] == " X " && mark[c][2] == " X ") win_x = true; if (mark[0][c] == " O " && mark[1][c] == " O " && mark[2][c] == " O ") win_o = true; if (mark[0][c] == " X " && mark[1][c] == " X " && mark[2][c] == " X ") win_x = true; } } 4.7 棋盘状态 --------------- .. code-block:: c++ void TicTacToe::board_info() { // 输出每一步下棋的棋盘状态 for (int k = 0; k < 3; ++k) { bar[k] = '|' + mark[k][0] + '|' + mark[k][1] + '|' + mark[k][2] + '|' ; } cout << endl; cout << split_line << boundary << endl; cout << " 第 " << bar[0] << endl; cout << sidebar << boundary << endl; cout << " " << step << " " << bar[1] << endl; cout << sidebar << boundary << endl; cout << " 步 " << bar[2] << endl; cout << split_line << boundary << endl; cout << endl; } 4.8 下棋 ----------- .. code-block:: c++ void TicTacToe::play_game() { for (int i = 0; i < 5; ++i) { step = i + 1; user_choose(); mark[user_x][user_y] = " " + piece + " "; if ( i < 4 ) // 如果进行到了第五轮,只能是轮到用户下棋 computer_choose(); judge_win_or_lose(); // 判断用户是否赢了 if (win_x != true && win_o != true) // 如果用户没有赢,则轮到计算机下棋 { if (piece == "O") // 定义与用户不同的棋子 mark[computer_x][computer_y] = " X "; else mark[computer_x][computer_y] = " O "; } judge_win_or_lose(); // 判断计算机是否赢了 board_info(); if (win_o || win_x) { if ( (win_o && piece == "O") || (win_x && piece == "X") ) cout << " 你赢了 ^_^ \n" << endl; else cout << " 你输了 >_< \n" << endl; break; } if (i == 4) // 判断是否平局 { cout << " 平局 -_-# \n" << endl; break; } } } 4.9 main 函数 ----------------- .. code-block:: c++ int main() { TicTacToe tictactoe_sample; tictactoe_sample.begin_info(); tictactoe_sample.play_game(); return 0; } 4.10 本阶段完整代码 --------------------- 完整代码位于 ``/doc/sample/4.1.cpp`` `在线浏览 `_