問題描述
我最近開始從事我的程式碼的清潔/物流工作,如果你能給我一些關於如何改進某些事情的技巧,我將不勝感激。
這是一個簡單的控制檯 Hangman 遊戲我做了:
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <vector>
using std::cout; using std::cin;
using std::endl; using std::string;
using std::vector; using std::ifstream;
void Clear_Screen(){
cout << string(1000, 'n');
}
vector<string> Add_Lines(unsigned short int usiLength){
vector<string> vecsLines_Vector;
for(unsigned short int i = 0; i < usiLength; i++){
vecsLines_Vector.push_back("_");
}
return vecsLines_Vector;
}
string Output_Guesses(vector<string> vecsVector, unsigned short int usiLimit){
string sOutput;
for(unsigned short int usiI = 0; usiI < usiLimit; usiI++){
sOutput += vecsVector[usiI] + " ";
}
return sOutput;
}
int main(){
while(true){
cout << "t" << " __ __ _______ __ _ _______ __ __ _______ __ _ " << endl
<< "t" << "| | | || _ || | | || || |_| || _ || | | |" << endl
<< "t" << "| |_| || |_| || |_| || ___|| || |_| || |_| |" << endl
<< "t" << "| || || || | __ | || || |" << endl
<< "t" << "| || || _ || || || || || _ |" << endl
<< "t" << "| _ || _ || | | || |_| || ||_|| || _ || | | |" << endl
<< "t" << "|__| |__||__| |__||_| |__||_______||_| |_||__| |__||_| |__|" << endl << endl
<< "tttt" << "---------------" << endl
<< "tttt" << "| 1. New Game |" << endl
<< "tttt" << "| 2. Exit |" << endl
<< "tttt" << "---------------" << endl
<< "tttt" << "Selected : ";
// Prevents from entering an invalid value
unsigned short int usiMenu_Select = 0;
do{
cin >> usiMenu_Select;
}while(usiMenu_Select < 1 || usiMenu_Select > 2);
// Quit Game
if(usiMenu_Select == 2){
return 0;
}
Clear_Screen();
// Grab all the words from the dictionary and store them into a vector
vector<string> vecsWords;
unsigned int uiLength = 0;
ifstream Dictionary;
Dictionary.open("dictionary.txt");
if(Dictionary.is_open()){
while(Dictionary.good()){
string sWord;
getline(Dictionary, sWord);
vecsWords.push_back(sWord);
uiLength++;
}
}
Dictionary.close();
// Pick a random word from the dictionary vector
srand (time(NULL));
const unsigned int kuiRandom_Number = rand() % uiLength;
const string ksWord_Selected = vecsWords[kuiRandom_Number];
// Creates guessing lines
const unsigned short int kusiWord_Length = ksWord_Selected.length();
const unsigned short int kusiTries = 6;
vector<string> vecsGuesses = Add_Lines(kusiWord_Length);
vector<string> vecsWrongs = Add_Lines(kusiTries);
// Guessing game loop
unsigned short int usiIncorrect = 0;
unsigned short int usiCorrect = 0;
while(usiIncorrect < kusiTries){
cout << "ttt" << "Correct : " << Output_Guesses(vecsGuesses, kusiWord_Length) << endl << endl <<
"ttt" << " Wrong : " << Output_Guesses(vecsWrongs, kusiTries) << endl << endl <<
"ttt" << " Guess : ";
// Prevents from entering more than 1 character
string cGuess;
do{
cin >> cGuess;
}while(cGuess.length() > 1);
// Checks if letter guessed is part of the word
bool bValid = false;
for(unsigned short int i = 0; i <= kusiWord_Length; i++){
const string ksValid_Character = ksWord_Selected.substr(i,1);
if(cGuess == ksValid_Character){
vecsGuesses[i] = cGuess;
usiCorrect++;
bValid = true;
}
}
// Checks if answer is valid
if(!bValid){
vecsWrongs[usiIncorrect] = cGuess;
usiIncorrect++;
}
// Output end game message
if(usiCorrect == kusiWord_Length){
cout << "ttt" << " _ _ _ _ " << endl
<< "ttt" << "| | | |_|___ ___ ___ ___ " << endl
<< "ttt" << "| | | | | | | -_| _|" << endl
<< "ttt" << "|_____|_|_|_|_|_|___|_| " << endl
<< "ttt" << "Enter any keys to continue..";
cin >> cGuess;
usiIncorrect = kusiTries;
}else if(usiIncorrect == kusiTries){
cout << "ttt" << " __ " << endl
<< "ttt" << "| | ___ ___ ___ ___ " << endl
<< "ttt" << "| |__| . |_ -| -_| _|" << endl
<< "ttt" << "|_____|___|___|___|_| " << endl
<< "ttt" << "Enter any keys to continue..";
cin >> cGuess;
usiIncorrect = kusiTries;
}
Clear_Screen();
}
}
}
最佳解決思路
-
您可以按字母順序或按組分組您的 STL
#include(在不同的答案中為 @Loki Astari 提供信用):// This is Class.cpp
#include "Class.h"
#include "OtherMyClassIdependon1.h"
#include "OtherMyClassIdependon1.h"// Now C++ header files // Lots of people order these alphabetically
#include <string> // Personally I group them
// All the containers together.
// All the streams together.
// etc. Each group alphabetical.// Now C header files // Lots of people order these alphabetically
#include <unistd.h>// Now System header files
#include <ICantThinkOfAnything> -
使用
<ctime>代替<time.h>。後者是 C 庫,位於namespace std內。 -
那些
using在頂部看起來很粘。我只是把std::放在需要的地方。為了可維護性和 name-clashing 的避免,這也將有助於將 STL 實體與其他實體分開。 -
如果大寫字母用於型別,函式應以小寫字母開頭。
使用 camelCase:
void oneFunction() {}使用 snake_case:
void another_function() {} -
Output_Guesses()不改變容器,所以透過vecsVectorconst&:std::string Output_Guesses(std::vector<std::string> const& vecsVector, /* ... */) {} // ^^^^^^ -
將
std::srand()移動到main()的頂部,以實現可維護性,並將其改寫為:// use nullptr instead if you're using C++11 std::srand(static_cast<unsigned int>(std::time(NULL)));沒有這個,
std::srand()每次返回相同的隨機數。如果您的編譯器發出警告,則只需要轉換,因此請確保它們已啟用。另外,如果你有 C++ 11,用
nullptr替換NULL。 -
當處理 STL 容器 (如
std::vector和std::string),use their iterators instead of indices whenever possible 。一次發生在Add_Lines()。 -
對於您的”winner” 和”loser” 輸出,您正在重新整理每行的緩衝區,這是
std::endl正在做的。要做一個換行符,不要這樣做,新增n在引號內的任何地方。您仍然可以將std::endl放在程式的最後一行或需要重新整理的地方。 -
while (true)沒問題另一個選項是for (;;),它也直到停止 (通常使用break) 進行無限迴圈。 -
我會考慮使用
typedef為您的 frequently-used 型別,如const unsigned short int。例如:如果所有字長都使用相同的型別,則將其命名為WordLength。這是大寫的,因為它是一個 user-defined 型別。關於字長,喜歡std::string::size_type。如果您使用的超級 freakishly-large 字串超出了unsigned short int的大小,該怎麼辦?使用這種型別將保證您可以使用這麼長的字,而無需更改所有這些型別。 -
常數可以放在全球範圍內:
const unsigned short int kusiTries = 6這是可以的,因為它不是
const的全域性變數,不能在程式的其他地方修改。此外,請勿使用 strongly-typed 語言 (如 C++) 中的匈牙利符號。只需一個簡單的
tries即可。 -
使用所有的”magic numbers”,您都可以在
main()中使用EXIT_SUCCESS和EXIT_FAILURE。對於”magic numbers” 本身,更喜歡常數 (如上所述) 。 -
為了正確輸入
std::string,最好選擇std::getline():getline(std::cin, cGuess); -
對於輸入驗證,如選單,我建議 exception-handling(
try/catch) 。這將阻止程式從 bugging-up 輸入不良,並允許恢復。 -
最後 (也許最重要的是):使用更多的功能。您可能仍然保持程式簡單,而不使用類,沒關係。但是,當您將所有內容都填入
main()(或任何一種功能) 時,可以顯著降低程式的整體可維護性。只要在main()中保持”welcome” 的內容,選單和遊戲狀態 (繼續播放) 。其他一切都應該根據目的分為功能。建立一個只顯示簡單的訊息的函式也不實用,除非它發生需要引數。此外,如果您重複使用相同的程式碼塊 (例如顯示陣列),請將其放入單獨的函式中。
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。