/
avplat
/
Tetris-MFC
Обзор
Документация
Войти
/
avplat
/
Tetris-MFC
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
RatingDb.cpp
184 строки
6 KB
Andrey Platonov
добавил возможность приостановки игры
22 окт 2025, 22:36
22 окт 2025, 22:36
a545dd2
Код
Авторство
О чём код?
/// @file /// @brief Create datasets to train neural network to detect QRS complexes at ECGs /// @copyright Andrey Platonov #include "pch.h" #include <chrono> #include <filesystem> #include <format> #include <memory> #include <stdexcept> #include <string> #include <vector> #include <stringapiset.h> #include "RatingDb.h" #ifdef _DEBUG #define new DEBUG_NEW #endif /// @brief Структура для передачи параметров в ratingCallback struct Params { std::vector< RatingData >& data; ///< Вектор для сохранения данных std::string& errorMsg; ///< Сообщение об ошибке }; static int ratingCallback( void* param, int argc, char** argv, char** colNames ); RatingDb::RatingDb() : db( nullptr, &sqlite3_close ) { } bool RatingDb::Open( const std::filesystem::path& fileName ) { errorMsg.clear(); if ( IsOpen() ) { Close(); } sqlite3* _db = nullptr; int ret = sqlite3_open( fileName.string().c_str(), &_db ); db.reset( _db ); if ( ret != SQLITE_OK ) { errorMsg = std::string( "Невозможно открыть базу: " ) + sqlite3_errmsg( db.get() ); return false; } return true; } const CString RatingDb::GetErrorMsg() const { int sizeNeeded = MultiByteToWideChar( 1251, 0, errorMsg.c_str(), (int)errorMsg.size(), nullptr, 0 ); ASSERT( sizeNeeded > 0 ); std::wstring result( sizeNeeded, 0 ); MultiByteToWideChar( 1251, 0, errorMsg.c_str(), (int)errorMsg.size(), result.data(), sizeNeeded ); return CString( result.data() ); } bool RatingDb::AddRating( const RatingData& data ) { int sizeNeeded = WideCharToMultiByte( CP_UTF8, 0, data.Name.GetString(), (int)data.Name.GetLength(), nullptr, 0, nullptr, nullptr ); ASSERT( sizeNeeded > 0 ); std::string nameUtf8( sizeNeeded, 0 ); WideCharToMultiByte( CP_UTF8, 0, data.Name.GetString(), (int)data.Name.GetLength(), nameUtf8.data(), sizeNeeded, nullptr, nullptr ); std::string sql = std::format( "insert into ratings ( name, tm, score, ts ) values ( '{}', {}, {}, {} );", nameUtf8, data.Dur.count(), data.Score, std::chrono::system_clock::to_time_t( data.Time ) ); char* _msg = nullptr; int ret = sqlite3_exec( db.get(), "begin transaction", nullptr, nullptr, &_msg ); std::unique_ptr< char, decltype(&sqlite3_free) > msg( _msg, &sqlite3_free ); if ( ret != SQLITE_OK ) { errorMsg = std::string( "Невозможно начать транзакцию: " ) + msg.get(); return false; } try { _msg = nullptr; ret = sqlite3_exec( db.get(), sql.c_str(), nullptr, nullptr, &_msg ); msg.reset( _msg ); if ( ret != SQLITE_OK ) { errorMsg = std::string( "Невозможно выполнить запрос: " ) + msg.get(); throw std::runtime_error( "sqlite3_exec" ); } _msg = nullptr; ret = sqlite3_exec( db.get(), "commit", nullptr, nullptr, &_msg ); msg.reset( _msg ); if ( ret != SQLITE_OK ) { errorMsg = std::string( "Невозможно завершить транзакцию: " ) + msg.get(); throw std::runtime_error( "sqlite3_exec" ); } } catch ( ... ) { _msg = nullptr; ret = sqlite3_exec( db.get(), "rollback", nullptr, nullptr, &_msg ); msg.reset( _msg ); if ( ret != SQLITE_OK ) { errorMsg = std::string( "Невозможно откатить транзакцию: " ) + msg.get(); } return false; } return true; } bool RatingDb::GetRatings( unsigned count, std::vector< RatingData >& data ) { ASSERT( count > 0 ); errorMsg.clear(); data.clear(); Params p = { data, errorMsg }; char* _msg = nullptr; std::string sql = "select * from ratings order by score desc, tm desc limit " + std::to_string( count ); int ret = sqlite3_exec( db.get(), sql.c_str(), &ratingCallback, &p, &_msg ); std::unique_ptr< char, decltype(&sqlite3_free) > msg( _msg, &sqlite3_free ); if ( ret != SQLITE_OK ) { errorMsg = std::string ( "Невозможно выполнить запрос: " ) + msg.get(); return false; } return true; } /// @brief Функция вызывается для обработки каждой строки при запросе к таблице ratings /// @param[out] param Указатель на vector< RatingData >, в котором будут сохраняться данные, считанные из базы /// @param[in] argc Количество полей в строке таблицы /// @param[in] argv Содержимое полей в строке таблицы /// @param[in] colNames Имена полей таблицы static int ratingCallback( void* param, int argc, char** argv, char** colNames ) { ASSERT( param != nullptr ); Params* p = reinterpret_cast< decltype( p ) >( param ); ASSERT( p != nullptr ); try { RatingData rd; for ( int i = 0; i < argc; ++i ) { std::string col( colNames[ i ] ); if ( col == "name" ) { std::string nameUtf8 = std::string( argv[ i ] ); int sizeNeeded = MultiByteToWideChar( CP_UTF8, 0, nameUtf8.c_str(), (int)nameUtf8.size(), nullptr, 0 ); ASSERT( sizeNeeded > 0 ); std::wstring nameUtf16( sizeNeeded, 0 ); MultiByteToWideChar( CP_UTF8, 0, nameUtf8.c_str(), (int)nameUtf8.size(), nameUtf16.data(), sizeNeeded ); rd.Name = CString( nameUtf16.data() ); } else if ( col == "tm" ) { rd.Dur = std::chrono::seconds( std::atoi( argv[ i ] ) ); } else if ( col == "score" ) { rd.Score = std::atoi( argv[ i ] ); } else if ( col == "ts" ) { rd.Time = std::chrono::system_clock::from_time_t( std::atoi( argv[ i ] ) ); } } p->data.push_back( rd ); } catch ( const std::exception& e ) { p->errorMsg = std::string( "Исключение: " ) + e.what(); return 1; } catch ( ... ) { p->errorMsg = std::string( "Неизвестное исключение" ); return 1; } return 0; }