ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Number Bomb Game V2.7.4

Number Bomb Game V2.7.4

自从我踏入 CSDN 论坛并开始写博文,已经过去一年多了。我的第一篇博文,就是关于《数字炸弹》这款名副其实的“小游戏”的。事实上,我一直在持续迭代这个小代码,它已从最初的仅有 28 行,发展到现在功能较为齐全的游戏版本。这是最新的 V2.7.4 版本,写在下面。

/** * ========= Number Bomb Game V2.7.4 ========= * This is a digital bomb code written by a single person for playing. * There're some comments inside that may help you understand the code. * Enjoy the game! * ============ Author: WP18Noru ============ **/ #include<cstdlib> #include<iostream> #ifdef _WIN32 #include<windows.h> #else #include<time.h> #endif #ifdef _WIN32 #include<conio.h> #else #include<termios.h> #include<unistd.h> #include<cstdio> #endif #if __cplusplus>=201103L #include<random> #endif #include<limits> #include<cctype> #if __cplusplus<201103L #include<ctime> #endif enum Language{ // enum for languages CHINESE,ENGLISH,JAPANESE }; Language language=CHINESE; inline void clear_screen(){ #ifdef _WIN32 std::system("CLS"); #else std::system("clear"); #endif } void input_error_prompt(){ switch(language){ case CHINESE: std::cout<<"输入错误,请重新输入!"<<std::endl; break; case ENGLISH: std::cout<<"Input error, please re-enter! "<<std::endl; break; case JAPANESE: std::cout<<"入力エラーです。再入力してください。"<<std::endl; break; } } int get_char(){ // a compatible function that mimics _getch() from <conio.h> #ifdef _WIN32 return _getch(); #else int received_character; struct termios old_termios,new_termios; tcgetattr(STDIN_FILENO,&old_termios); new_termios=old_termios; new_termios.c_lflag&=~(ICANON|ECHO); tcsetattr(STDIN_FILENO,TCSANOW,&new_termios); received_character=getchar(); tcsetattr(STDIN_FILENO,TCSANOW,&old_termios); if(received_character==EOF){ std::clearerr(stdin); } return received_character; #endif } void unified_sleep(long long time_millisecond){ #ifdef _WIN32 Sleep(static_cast<DWORD>(time_millisecond)); #else struct timespec request; request.tv_sec=time_millisecond/1000; request.tv_nsec=(time_millisecond%1000)*1000000L; nanosleep(&request,NULL); #endif } class number_bomb_game{ // main class of the program private: enum Difficulty{ // enum for difficulty EASY=1,NORMAL,HARD,CUSTOM }; short game_mode,player_count; Difficulty difficulty; long long seed; short bomb,lower_limit,upper_limit,player_input,guess_count; #if __cplusplus>=201103L std::mt19937 random_engine; #endif protected: void select_language(){ short input; do{ std::cout<<"请选择语言。\tPlease select a language. \t言語を選択してください。 \n0. 简体中文\t1. English\t2. 日本語"<<std::endl; if(!(std::cin>>input)){ std::cin.clear(); std::cout<<"输入错误,请重新输入!Input error, please re-enter! 入力エラーです。再入力してください。"<<std::endl; input=-1; }else if(input<0||input>2){ std::cout<<"输入错误,请重新输入!Input error, please re-enter! 入力エラーです。再入力してください。"<<std::endl; } std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }while(input<0||input>2); language=static_cast<Language>(input); clear_screen(); } void output_game_rules()const{ switch(language){ case CHINESE: std::cout<<"是否查看游戏规则?(Y/其他任意键)"<<std::endl; break; case ENGLISH: std::cout<<"Do you want to check the game rules?(Y/Any other key) "<<std::endl; break; case JAPANESE: std::cout<<"ゲームのルールを表示しますか?(Y/他の任意のキー)"<<std::endl; break; } { int received_character=0; received_character=get_char(); if(received_character!=EOF&&std::tolower(static_cast<unsigned char>(received_character))=='y'){ switch(language){ case CHINESE: std::cout<<"数字炸弹是一款基于逻辑推理的猜数字游戏。游戏开始时,系统会在预设范围内生成一个秘密数字(称为“炸弹”)。玩家根据当前数字范围的提示,依次输入一个猜测数字。若玩家猜中炸弹数字,则该玩家游戏失败,并接受惩罚;若未猜中,系统将根据猜测值缩小范围:若猜测值小于炸弹,则下限调整为猜测值+1;若猜测值大于炸弹,则上限调整为猜测值。\n\n游戏可通过种子值控制随机生成结果(种子为-1时完全随机)。每局结束后可选择继续游戏或退出。\n请按任意键继续......"<<std::endl; break; case ENGLISH: std::cout<<"Number Bomb is a logic-based number guessing game.\nAt the start of the game, the system generates a secret number (called the \"bomb\") within a preset range.\nBased on the current range prompt, players take turns entering a guessed number.\nIf the player guesses the bomb number, they lose the game and must accept a penalty.\nIf the guess is incorrect, the system narrows the range based on the guess:\nif the guess is less than the bomb, the lower bound is adjusted to the guess + 1;\nif the guess is greater than the bomb, the upper bound is adjusted to the guess.\n\nThe game can use a seed value to control random outcomes (a seed of -1 means completely random).\nAfter each round, players can choose to continue or quit.\nPress any key to continue...\n"; break; case JAPANESE: std::cout<<"デジタルボムは論理的推論に基づく数字当てゲームです。\nゲーム開始時、システムは事前に設定された範囲内で秘密の数字(「ボム」と呼びます)を生成します。\nプレイヤーは現在の範囲のヒントをもとに、数字を順に予想して入力します。\nもしボムの数字を当ててしまった場合、そのプレイヤーはゲームに敗北し、ペナルティを受けます。\n予想が外れた場合、システムはその予想値に基づいて範囲を狭めます。\n予想値がボムより小さい場合は下限を「予想値+1」に調整し、予想値がボムより大きい場合は上限を予想値に調整します。\n\nシード値によってランダムな結果を制御できます(シードが-1の場合は完全ランダム)。\n各ゲーム終了後、続行するか終了するかを選択できます。\n任意のキーを押して続行してください......\n"; break; } get_char(); // press any key to continue } } clear_screen(); } void choose_game_mode(){ do{ switch(language){ case CHINESE: std::cout<<"请选择游戏模式。(0. 人机对战 1. 多人游戏):"<<std::flush; break; case ENGLISH: std::cout<<"Please choose a game mode( 0. Player vs Computer 1. Player vs Player): "<<std::flush; break; case JAPANESE: std::cout<<"ゲームモードを選択してください(0. プレイヤー対コンピュータ 1. プレイヤー対プレイヤー):"<<std::flush; break; } if(!(std::cin>>game_mode)){ std::cin.clear(); input_error_prompt(); game_mode=-1; }else if(game_mode<0||game_mode>1){ input_error_prompt(); } std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }while(game_mode<0||game_mode>1); clear_screen(); } void input_player_number(){ if(game_mode==1){ do{ switch(language){ case CHINESE: std::cout<<"请输入游玩的人数(2~20):"<<std::flush; break; case ENGLISH: std::cout<<"Please enter the number of players (2~20): "<<std::flush; break; case JAPANESE: std::cout<<"プレイヤー人数を入力してください(2~20):"<<std::flush; break; } if(!(std::cin>>player_count)){ std::cin.clear(); input_error_prompt(); player_count=1; }else if(player_count<2||player_count>20){ input_error_prompt(); } std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }while(player_count<2||player_count>20); } clear_screen(); } void select_difficulty(){ short input; do{ switch(language){ case CHINESE: std::cout<<"请选择难度:\n1. 简单\n2. 普通\n3. 困难\n4. 自定义上下限"<<std::endl; break; case ENGLISH: std::cout<<"Please select the difficulty level: \n1. Easy\n2. Normal\n3. Hard\n4. Custom upper and lower limits"<<std::endl; break; case JAPANESE: std::cout<<"難易度を選択してください:\n1. 簡単\n2. 普通\n3. 難しい\n4. カスタム上下限"<<std::endl; break; } if(!(std::cin>>input)){ std::cin.clear(); input_error_prompt(); input=0; }else if(input<1||input>4){ input_error_prompt(); } std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }while(input<1||input>4); difficulty=static_cast<Difficulty>(input); clear_screen(); } void input_seed(){ do{ switch(language){ case CHINESE: std::cout<<"请输入种子(-1~4294967295,-1表示随机):"<<std::flush; break; case ENGLISH: std::cout<<"Please input the seed (-1~4294967295, -1 represents random): "<<std::flush; break; case JAPANESE: std::cout<<"シード値を入力してください(-1~4294967295、-1はランダムを表します):"<<std::flush; break; } if(!(std::cin>>seed)){ std::cin.clear(); input_error_prompt(); seed=-2; }else if(seed<-1||seed>4294967295LL){ input_error_prompt(); } std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }while(seed<-1||seed>4294967295LL); // "4294967295LL" is 2^32 - 1. It's also the upper limit of unsigned int, the upper limit of the argument to the srand() function, and the upper limit of the seed() method } void custom_upper_and_lower_limits(){ if(difficulty==CUSTOM){ // yes, we need to determine while(true){ // -32768 ~ 32767 is the range of short. here we don't need to validate, input error handling will take care of everything. switch(language){ case CHINESE: std::cout<<"请输入下限(-32768~32767):"; break; case ENGLISH: std::cout<<"Enter the lower limit (-32768 to 32767): "; break; case JAPANESE: std::cout<<"下限を入力してください(-32768~32767):"; break; } if(!(std::cin>>lower_limit)){ std::cin.clear(); input_error_prompt(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }else{ std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); break; } } while(true){ switch(language){ case CHINESE: std::cout<<"请输入上限(-32768~32767),且大于下限:"; break; case ENGLISH: std::cout<<"Enter the upper limit (-32768 to 32767), and it must be greater than the lower limit: "; break; case JAPANESE: std::cout<<"上限を入力してください(-32768~32767)。下限より大きい値を設定してください:"; break; } if(!(std::cin>>upper_limit)||upper_limit<=lower_limit){ std::cin.clear(); input_error_prompt(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }else{ std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); break; } } } } void generate_bomb(long long random_seed){ // it should be noted here that the bomb's generation range is [lower_limit, upper_limit). #if __cplusplus>=201103L if(random_seed!=-1){ random_engine.seed(random_seed); }else{ std::random_device random; random_engine.seed(random()); } std::uniform_int_distribution<> distribution(1,99); switch(difficulty){ case EASY: distribution=std::uniform_int_distribution<>(1,199); bomb=distribution(random_engine); break; case NORMAL: bomb=distribution(random_engine); break; case HARD: distribution=std::uniform_int_distribution<>(1,49); bomb=distribution(random_engine); break; case CUSTOM: if(upper_limit-lower_limit==0){ bomb=lower_limit; }else{ distribution=std::uniform_int_distribution<>(lower_limit,upper_limit-1); bomb=distribution(random_engine); } break; } #else if(random_seed!=-1){ std::srand(random_seed); }else{ std::srand(static_cast<unsigned int>(std::time(0))); } switch(difficulty){ case EASY: bomb=std::rand()%199+1; break; case NORMAL: bomb=std::rand()%99+1; break; case HARD: bomb=std::rand()%49+1; break; case CUSTOM: if(upper_limit-lower_limit==0){ bomb=lower_limit; }else{ bomb=std::rand()%(upper_limit-lower_limit)+lower_limit; } break; } #endif switch(language){ case CHINESE: std::cout<<"炸弹已就绪!"<<std::endl; break; case ENGLISH: std::cout<<"The bomb is ready! "<<std::endl; break; case JAPANESE: std::cout<<"爆弾の準備ができました!"<<std::endl; break; } } bool player_turn(short current_player=0){ do{ switch(language){ case CHINESE: if(current_player==0){ std::cout<<"玩家("<<lower_limit<<'~'<<upper_limit<<"):"<<std::flush; }else{ std::cout<<"玩家"<<current_player<<"("<<lower_limit<<'~'<<upper_limit<<"):"<<std::flush; } break; case ENGLISH: if(current_player==0){ std::cout<<"Player("<<lower_limit<<'~'<<upper_limit<<"):"<<std::flush; }else{ std::cout<<"Player "<<current_player<<"("<<lower_limit<<'~'<<upper_limit<<"):"<<std::flush; } break; case JAPANESE: if(current_player==0){ std::cout<<"プレイヤー("<<lower_limit<<'~'<<upper_limit<<"):"<<std::flush; }else{ std::cout<<"プレイヤー"<<current_player<<"("<<lower_limit<<'~'<<upper_limit<<"):"<<std::flush; } break; } if(!(std::cin>>player_input)){ std::cin.clear(); input_error_prompt(); player_input=-1; }else if(player_input<lower_limit||player_input>=upper_limit){ input_error_prompt(); } std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); }while(player_input<lower_limit||player_input>=upper_limit); guess_count++; if(player_input==bomb){ #ifdef _WIN32 std::system("COLOR cf"); #else std::cout<<"\033[97;101m"<<std::flush; #endif switch(language){ case CHINESE: std::cout<<"炸弹爆炸,你输了!接受惩罚吧,玩家!!!"<<std::endl; break; case ENGLISH: std::cout<<"The bomb exploded, you lost! Accept the punishment, Player!!! "<<std::endl; break; case JAPANESE: std::cout<<"爆弾が爆発しました、あなたの負けです!罰を受けてください、プレイヤー!!!"<<std::endl; break; } return true; }else if(player_input<bomb){ lower_limit=player_input+1; }else{ upper_limit=player_input; } return false; } bool computer_turn(){ short deviation_range=4,deviation=0,computer_guess=0; switch(difficulty){ case EASY: deviation_range=7; break; case NORMAL: break; case HARD: deviation_range=2; break; case CUSTOM: break; } short current_deviation=deviation_range,range_size=upper_limit-lower_limit; if(range_size>50){ current_deviation=deviation_range+2; }else if(range_size<20){ current_deviation=deviation_range/2; if(current_deviation<1){ current_deviation=1; } } #if __cplusplus>=201103L std::uniform_int_distribution<> distribution(-current_deviation,current_deviation); deviation=distribution(random_engine); #else deviation=std::rand()%(current_deviation*2+1)-current_deviation; #endif computer_guess=static_cast<short>((lower_limit+(upper_limit-1))/2)+1+deviation; if(computer_guess<lower_limit){ computer_guess=lower_limit; } if(computer_guess>=upper_limit){ computer_guess=upper_limit-1; } switch(language){ case CHINESE: std::cout<<"计算机("<<lower_limit<<'~'<<upper_limit<<"):"; break; case ENGLISH: std::cout<<"Computer("<<lower_limit<<'~'<<upper_limit<<"):"; break; case JAPANESE: std::cout<<"コンピュータ("<<lower_limit<<'~'<<upper_limit<<"):"; break; } unified_sleep(1000); std::cout<<computer_guess<<std::endl; guess_count++; if(computer_guess==bomb){ #ifdef _WIN32 std::system("COLOR 8f"); #else std::cout<<"\033[37;100m"<<std::flush; #endif switch(language){ case CHINESE: std::cout<<"哎呀!一不小心触发了炸弹!"<<std::endl; break; case ENGLISH: std::cout<<"Oops! I accidentally triggered the bomb! "<<std::endl; break; case JAPANESE: std::cout<<"おっと!うっかり爆弾を触发してしまいました!"<<std::endl; break; } return true; }else if(computer_guess<bomb){ lower_limit=computer_guess+1; }else{ upper_limit=computer_guess; } return false; } void reset_game(){ #ifdef _WIN32 std::system("COLOR 07"); #else std::cout<<"\033[0m"<<std::flush; #endif lower_limit=1; upper_limit=100; guess_count=0; } public: number_bomb_game():game_mode(1),player_count(2),difficulty(NORMAL),seed(-1),bomb(50),lower_limit(1),upper_limit(100),player_input(0),guess_count(0){ #if __cplusplus>=201103L std::random_device game_random_device; random_engine.seed(game_random_device()); #endif } void player_versus_computer(){ while(true){ if(player_turn()||computer_turn()){ break; } } } void player_versus_player(){ short current_player=1; while(true){ if(player_turn(current_player)){ break; } current_player=(current_player!=player_count)?current_player+1:1; } } void play(){ select_language(); output_game_rules(); while(true){ choose_game_mode(); input_player_number(); select_difficulty(); input_seed(); switch(difficulty){ case EASY: lower_limit=1; upper_limit=200; break; case NORMAL: lower_limit=1; upper_limit=100; break; case HARD: lower_limit=1; upper_limit=50; break; case CUSTOM: break; } custom_upper_and_lower_limits(); generate_bomb(seed); unified_sleep(1000); clear_screen(); if(game_mode==0){ player_versus_computer(); }else{ player_versus_player(); } unified_sleep(3000); switch(language){ case CHINESE: std::cout<<"猜测次数:"<<guess_count<<"\n再玩一局请按 <c> 键,否则请按任意键以继续!"<<std::endl; break; case ENGLISH: std::cout<<"Guess counts: "<<guess_count<<"\nPlease press the <c> key to play another round, otherwise please press any key to continue! "<<std::endl; break; case JAPANESE: std::cout<<"試行回数:"<<guess_count<<"\nもう一度プレイするには <c> キーを押してください。そうでない場合は任意のキーを押して続行します!"<<std::endl; break; } { int received_character=0; received_character=get_char(); if(received_character==EOF||std::tolower(static_cast<unsigned char>(received_character))!='c'){ break; } } reset_game(); clear_screen(); } } }; void start(){ std::cout<<"正在启动游戏中"<<std::flush; for(short i=1;i<=6;i++){ unified_sleep(667); std::cout<<'.'; } std::cout<<"\n启动完成!"<<std::flush; unified_sleep(500); clear_screen(); } int main(){ #ifdef _WIN32 SetConsoleTitleA("Number Bomb Game V2.7.4"); #else std::cout<<"\033]0;Number Bomb Game V2.7.4\007"<<std::flush; #endif start(); number_bomb_game game; game.play(); #ifdef _WIN32 std::system("COLOR 07"); #else std::cout<<"\033[0m"<<std::flush; #endif std::cout<<"\nGame Over! "<<std::endl; get_char(); return 0; } /** * Here are some thoughts on the future of the project: * Maybe: a major refactoring of the code structure; * Maybe: minor changes to the code logic; * Maybe (in the more distant future): update to a graphical interface; * Maybe (in the even more distant future): add online multiplayer! **/ // The code is provided for learning, but that does not mean you can infringe. // Thanks.

这就是《数字炸弹》 V2.7.4 的完整实现。代码已在 Windows 和 Linux 下测试通过,支持中英日三语言。如果你有改进建议,欢迎在评论区指出。感谢大家的阅读!

返回列表