Skip to content

Instantly share code, notes, and snippets.

@albinopapa
Created August 24, 2020 16:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save albinopapa/30880ea17b924b9382ce1d2613834343 to your computer and use it in GitHub Desktop.
Save albinopapa/30880ea17b924b9382ce1d2613834343 to your computer and use it in GitHub Desktop.
Hangman-ish no classes nor "functions"
#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