-
-
Save albinopapa/30880ea17b924b9382ce1d2613834343 to your computer and use it in GitHub Desktop.
Hangman-ish no classes nor "functions"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <iostream> | |
#include <functional> | |
#include <random> | |
#include <string> | |
#include <string_view> | |
#include <tuple> | |
constexpr auto dictionary = std::array{ | |
std::string_view{"fun"}, | |
std::string_view{"fork"}, | |
std::string_view{"forge"}, | |
std::string_view{"forgot"}, | |
std::string_view{"feather"}, | |
std::string_view{"fearsome"}, | |
std::string_view{"forgotten"} | |
}; | |
auto is_valid_guess = std::function{ []( char guess ) { | |
return std::tolower( guess ) >= 'a' && std::tolower( guess ) <= 'z'; | |
} }; | |
auto get_user_guess = std::function{ []() { | |
char letter = {}; | |
do { | |
std::cout << "Guess a letter: "; | |
std::cin >> letter; | |
} while( !is_valid_guess( letter ) ); | |
return letter; | |
} }; | |
auto pick_word = std::function{ []( std::mt19937& rng ) { | |
auto dist = std::uniform_int<std::size_t>{0, dictionary.size() - 1}; | |
return dictionary[ dist( rng ) ]; | |
} }; | |
auto unhide_guess = std::function{ [](std::string hidden, std::string_view word, std::string_view::const_iterator guess_it ) { | |
auto dist = std::distance( word.begin(), guess_it ); | |
hidden[ dist ] = *guess_it; | |
return hidden; | |
} }; | |
auto penalize = std::function{ [](std::string score, std::string::const_iterator score_it ) { | |
switch( std::distance( score.cbegin(), score_it ) ) { | |
case 0: score[ 0 ] = 'H'; break; | |
case 1: score[ 1 ] = 'O'; break; | |
case 2: score[ 2 ] = 'R'; break; | |
case 3: score[ 3 ] = 'S'; break; | |
case 4: score[ 4 ] = 'E'; break; | |
} | |
return score; | |
} }; | |
using GameData = std::tuple< | |
// rng | |
std::mt19937, | |
// word to guess | |
std::string_view, | |
// hidden word | |
std::string, | |
// score | |
std::string, | |
// game_over | |
bool, | |
// winner | |
bool | |
>; | |
using GameMethods = std::tuple< | |
// update function | |
std::function<void( GameData& )>, | |
// display function | |
std::function<void( GameData const& )>, | |
// is_finished function | |
std::function<bool( GameData const& )> | |
>; | |
using Game = std::tuple<std::function<void( GameMethods&, GameData& )>, GameMethods, GameData>; | |
// Indices to make things easier | |
// method indices | |
constexpr auto update_index = std::size_t{ 0 }; | |
constexpr auto display_index = std::size_t{ 1 }; | |
constexpr auto finished_index = std::size_t{ 2 }; | |
// data indices | |
constexpr auto rng_index = std::size_t{ 0 }; | |
constexpr auto word_index = std::size_t{ 1 }; | |
constexpr auto hidden_index = std::size_t{ 2 }; | |
constexpr auto score_index = std::size_t{ 3 }; | |
constexpr auto gover_index = std::size_t{ 4 }; | |
constexpr auto winner_index = std::size_t{ 5 }; | |
// game indices | |
constexpr auto construct_index = std::size_t{ 0 }; | |
constexpr auto methods_index = std::size_t{ 1 }; | |
constexpr auto data_index = std::size_t{ 2 }; | |
int main( int argc, char* argv[] ) { | |
auto game = Game{ std::function{ | |
[]( GameMethods& methods, GameData& data ) { | |
// init update method | |
std::get<update_index>( methods ) = []( GameData& data ) { | |
auto letter = get_user_guess(); | |
const auto word = std::get<word_index>( data ); | |
if( auto guess_it = std::find( word.begin(), word.end(), letter ); guess_it != word.end() ) { | |
auto& hidden = std::get<hidden_index>( data ); | |
hidden = unhide_guess( std::move( hidden ), word, guess_it ); | |
if( auto it = std::find( hidden.begin(), hidden.end(), '_' ); it == hidden.end() ) { | |
std::get<winner_index>( data ) = true; | |
std::get<gover_index>( data ) = true; | |
} | |
} | |
else { | |
auto& score = std::get<score_index>( data ); | |
if( auto score_it = std::find( score.begin(), score.end(), '_' ); score_it != score.end() ) { | |
score = penalize( std::move( score ), score_it ); | |
} | |
else { | |
std::get<winner_index>( data ) = false; | |
std::get<gover_index>( data ) = true; | |
} | |
} | |
}; | |
// init display method | |
std::get<display_index>( methods ) = []( GameData const& data ) { | |
if( std::get<gover_index>( data ) ) { | |
if( std::get<winner_index>( data ) ) { | |
std::cout << "Congratulations!\n"; | |
} | |
else { | |
std::cout << "Sorry, the word was: " << std::get<word_index>( data ) << '\n'; | |
std::cout << "Better luck next time.\n"; | |
} | |
} | |
else { | |
std::cout << std::get<hidden_index>( data ) << '\n'; | |
} | |
}; | |
// init is_finished method | |
std::get<finished_index>( methods ) = []( GameData const& data ) { | |
return std::get<gover_index>( data ); | |
}; | |
// get word | |
std::get<word_index>( data ) = pick_word( std::get<rng_index>( data ) ); | |
// init hidden string | |
std::get<hidden_index>( data ) = std::string( std::get<word_index>( data ).size(), '_' ); | |
// init score string | |
std::get<score_index>( data ) = std::string( 5, '_' ); | |
// init game_over | |
std::get<gover_index>( data ) = false; | |
// init winner | |
std::get<winner_index>( data ) = false; | |
} | |
}, GameMethods{}, GameData{} }; | |
std::get<construct_index>( game )( std::get<methods_index>( game ), std::get<data_index>( game ) ); | |
auto& game_methods = std::get<methods_index>( game ); | |
auto& game_data = std::get<data_index>( game ); | |
while( !std::get<finished_index>( game_methods )( game_data ) ) { | |
std::get<update_index>( game_methods )( game_data ); | |
std::get<display_index>( game_methods )( game_data ); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment